目前項目都會用叢集環境來部署,相比日訪問量低傳統網站,叢集環境在一些技術上多了些注意事項。針對本次促銷中心新後台中就遇到session一致性的問題。
開發一個具有存取控制的服務端,我們需要登陸驗證,而相比那些直接提供登陸介面的應用來說,目前大部分公司往往採用sso登陸方式,即單點登陸。而從單點登陸系統登陸之後用戶端會拿到一個具有登陸資訊的cookie,往往是加密的。
而需要知道登陸資訊,必須調用使用者中心的介面去或者user資訊,拿到user資訊,就可以將user放入session或者本地變數進行鑒權判定了,往往在攔截器中進行。
| public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object o = request.getSession().getAttribute( "user" ); return !o== null ; } |
這在單機環境是沒有問題的,如果遇到叢集環境,叢集又沒有配置session同步,這時候同一用戶端每次請求都可能請求的伺服器不一致,a伺服器產生的session在b伺服器找不到,無法通過驗證。
所以在叢集環境中,不能用session來做鑒權,這時可能想到利用cookie,因為cookie儲存在用戶端,從sso取得cookie資訊,每台伺服器都要去調使用者中心介面去解析cookie擷取使用者資訊,這種方式雖然能完成鑒權,但是弊端顯而易見,Cookie容易將一些使用者資訊暴露,加解密同樣也消耗了效能,每次請求都會請求使用者中心介面,導致
loginService.decodeUserToken(userToken)方法被頻繁調用,這是不可取的,所以還是要用到session,但是叢集環境無法實現session同步,這時會想到採用中間伺服器來搭建session伺服器,可以採用tair,redis等記憶體資料庫,
例如使用阿里的分布式緩衝tair作為session伺服器有很多優點。諸如:
1).存取速度快
2).使用者資料不容易丟失
3).支援叢集
4).支援持久化
我們知道session其實是在cookie中儲存了一個sessionid,使用者每次訪問都將sessionid發給伺服器,伺服器通過ID尋找使用者對應的狀態資料。
同理在cookie中定義一個sessionid,程式需要取得使用者狀態時將sessionid做為key在tair中尋找對於的session值。
類似的情況,在寫防重複提交的代碼時,服務端會隨機產生token作為session到用戶端,然後根據用戶端傳入的token判定是否存在重複提交。