當瀏覽器發起一個新的HTTP請求時,WEB服務端會主動建立一個session.並分配一個sessionID做爲服務端識別客戶端的一個標識,session對象會保存在服務端.此時session對象處於NEW STATE狀態,若是調用mysql
session.isNew()則返回true.當服務器處理完相應的請求時候,會將sessionID同reponse響應消息 一塊兒傳回客戶端瀏覽器,並將其存到該客戶端瀏覽器的cookie中。當客戶端再發送其它http請求的時候.會將sessionID連同request消息一塊兒發送給服務端。服務端再根據傳過來的sessionID將此次request與保存在服務端的session對象聯繫起來.此時的session對象已不是NEWSTATE狀態.這樣循環屢次.直到session對象超時或銷燬.web
注:當客戶端瀏覽器禁用cookie時,sessionID將不能保存在cookie中,通常此種狀況,會使用url重寫,將sessionID做爲請求參數來進行客戶端和瀏覽器的信息傳輸交互redis
- cookie cookie是在客戶端保存一些少許數據的解決方案.而session是在服務端保存少許數據的方案. 若是cookie不設定時間的話就表視它的生命週期爲瀏覽器會話的期間,只要關閉瀏覽器,cookie就消失了,這種cookie被稱爲會話cookie.其通常不保存在硬盤上.而是保存在內存中。若是設置了過時時間.那麼瀏覽器會把cookie保存到硬盤中,再次打瀏覽器時會依然有效.直到它的有效期超時;
注:會話cookie能夠在一個瀏覽器間的不一樣的tab頁中共享。隨瀏覽器主進程的關閉而失效 存儲在硬盤中的cookie能夠在不一樣瀏覽器進程間共享。
分佈式系統session共享問題的由來
目前大多數大型web應用都採用了分佈式服務集羣的部署方式,所謂集羣,就是讓一組計算機服務器協同工做,解決大併發,高可用,水平擴展的問題。可是在服務集羣中,session共享每每是一個比較頭疼的問題。由於session是在服務器端保存的,若是用戶跳轉到其餘物理服務器的話,session就會丟失,通常狀況下,session對象在後端是不可跨物理服務器而存在。因而就有了分佈式系統的session共享問題。 目前公司有不少的應用都是集羣佈置環境,可是,有不少項目運維在配置f5做負載均衡時,做了訪問地址ip hash算法來分擔流量,該算法根據訪問客戶端的IP地址進行歸類並和集羣中的真實的服務器數取模,獲得一個固定值,來分配真實的服務器,這樣的確能夠分擔部分的流量,但並無起到failover的功能,即這臺服務器掛機後,該客戶端的請求信息仍然會發送到該服務器上,而且,若是服務器集羣中,真實的服務器有硬件性能上的差別,在這種分配策略上也作不到所謂的「能者多勞」。因此,要作到真正的HA,這種算法是不合適的。算法
因此,爲了提升程序的HA及提供failover,在應用端若是是集羣佈置,而且在應用的開發過程當中,若是在session中保存了相關的內容,則最好要提供分佈式的session解決方案。
經常使用的集羣Session共享的方式
- 客戶端Cookie保存方案,將原來保存在session中的內容以加密的方式保存在客戶端cookie中。
- 優勢:減輕服務器端的壓力,每次session信息被寫回客服端,而後經瀏覽器再次提交到服務器。即便兩次請求即便在集羣中的不一樣服務器上完成,因爲session信息都是隨請求信息一塊兒提交,也能夠到達session共享。
- 缺點:
- 傳遞cookie時,http信息頭的長度限制使咱們只可以在cookie中存入少許的用戶信息;
- 須要額外地作session信息加密的工做;
- 若是採用這種方式,每次訪問網站二級域名時都會在http信息頭中帶有這些以cookie形式存儲的值信息,會佔用必定的帶寬;
- 信息存儲是在客戶端進行,用戶徹底能夠禁用cookie或刪除cookie,不是很可靠
- 服務器間Session同步方案,將session對象在集羣中的全部物理機上做同步 服務器間session同步策略,不一樣的容器有不一樣的解決方案。通常經常使用如下2種
- 使用主-從服務器的架構,當用戶在主服務器上登陸後,經過腳本或者守護進程的方式,將session信息傳遞到各個從服務器中,這樣,用戶訪問其它的從服務器時,就能夠讀到session信息。 缺點:好比速度慢、不穩定等,另外,若是session信息傳遞是主->從單向的,會有一些風險,好比主服務器down了,其它服務器沒法得到session信息
- Session 對象的集羣中的廣播機制。 一臺主機中產生session中,將此session對象在集羣網絡中進行廣播同步,各集羣中的主機收到廣播後,再同步到本地的session內存域中。 缺點:若是session內容中有大型對象時,不適合傳輸。集羣範圍中網絡中對存在大量的廣播消息,佔用帶寬,會有延時.
- 使用集中統一管理Session方案 即將集羣中各主機產生的session對象都存儲到一箇中心存儲結構中,目前比較流行的存儲結構是:redis集羣,Memcache,mysql數據庫等。這種集中存儲的結構,能斛決上面方案中的一些弊斷。但也有一些應用上問題。好比選擇mysql做存儲結構中,mysql數據庫能夠用做存儲的session對象,但在併發量高時,對數據庫的讀寫要求較高,還須要另外提升session失效的相關算法。Redis集羣,memcache主要是之內存爲存儲介質,有先天的讀寫優點,而且都能提供失效機制,特別適合用來做session的存儲結構。因此,這一種比較好的解決方案。 目前這兩種方案都有容器插件的方式部署在容器中有解決方案,但有其相應的缺點:
- 插件的版本更新不及時。
- 對容器不透明,不一樣容器要適配不一樣的插件。
- 插件自己的穩定性沒法控制。
- 運維在配置集羣時,還要特別注意相關插件的配置。增長了維護的難度。
相應的優勢就是:對程序透明,開發程序時候,不用考慮集羣,仍是單機環境。佈置簡單,沒有額外的工做量。
Spring Session的使用方式
第一步:引入依賴,根據須要配置相應的存儲 <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>1.3.1.RELEASE</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> </exclusion> <exclusion> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </exclusion> </exclusions> </dependency> 第二步:web應該配置filter過濾器。 <filter> <filter-name>springSession</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSession</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 第三步:配置相應的SPRING BEAN <bean id="springSession" class="org.springframework.session.web.http.SessionRepositoryFilter" c:sessionRepository-ref="redisOperationsSessionRepository" p:httpSessionStrategy-ref="cookieHttpSessionStrategy" /> <bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer" p:cookiePath="/" /> <bean id="cookieHttpSessionStrategy" class="org.springframework.session.web.http.CookieHttpSessionStrategy" p:cookieSerializer-ref="defaultCookieSerializer" /> <bean name="redisOperationsSessionRepository" class="org.springframework.session.data.redis.RedisOperationsSessionRepository" c:redisConnectionFactory-ref="connectionFactory" p:defaultMaxInactiveInterval="${session.timeout}" />