服務(wù)重啟后 session 數(shù)據(jù)丟失
應(yīng)用做集群部署的時候,不同的節(jié)點無法共享 session 數(shù)據(jù)
我們以使用比例的 Tomcat 為例,針對第二個問題 Tomcat 提供了集群 session 復(fù)制的解決方案,詳情請看官方文檔??赐晡臋n你會發(fā)現(xiàn) Tomcat 自帶的方法配置非常復(fù)雜,而且它沒有解決個問題 —— 服務(wù)重啟導(dǎo)致 session 數(shù)據(jù)丟失的問題。
現(xiàn)在還有另外一種方案就是使用 memcached 或者是 redis 來存儲 session 數(shù)據(jù),于是就有了這么一些開源項目。這些開源項目使用和配置都比較簡單,而且對應(yīng)用完全透明,只需要在 server.xml 中配置好 Manager 即可。例如:
<Context> ... <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:host1.yourdomain.com:11211,n2:host2.yourdomain.com:11211" sticky="false" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" requestUriIgnorePattern=".*.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" /> </Context>
但是這幾個開源項目都有一個根本的問題沒法解決,當存放在 session 中的數(shù)據(jù)量比較大,而且讀取 session 數(shù)據(jù)非常頻繁時會導(dǎo)致 memcached 或者是 redis 吞吐量受帶寬限制使得性能變得非常差。逼迫你必須通過 memcached 或者 redis 的擴容和集群來解決問題,大大的增加了硬件投入的成本和運維的成本。
--------
那么用 J2Cache 的 session-manager 模塊就可以有效解決前面提到的所有問題。J2Cache 在 redis 的基礎(chǔ)上引入了內(nèi)存緩存的概念,可以確保服務(wù)重啟后 session 數(shù)據(jù)不會丟失,其次極大的降低了 redis 的數(shù)據(jù)吞吐量,保證在高并發(fā)情況下依然有很好的性能表現(xiàn)。
與前面提到的幾個開源項目不同,J2Cache 的 session manager 采用 Filter 方式實現(xiàn),支持各種 Java 的 Web 容器服務(wù)。
使用方法:
1. Web 項目添加 J2Cache 的 session-manager 模塊依賴:
<dependency> <groupId>net.oschina.j2cache</groupId> <artifactId>j2cache-session-manager</artifactId> <version>1.0.0-beta4</version> </dependency>
2. 在 web.xml 中配置 Filter:
<filter> <filter-name>j2cache-session-filter</filter-name> <filter-class>net.oschina.j2cache.session.J2CacheSessionFilter</filter-class> <init-param><!-- 內(nèi)存中存放會話數(shù) --> <param-name>session.maxSizeInMemory</param-name> <param-value>2000</param-value> </init-param> <init-param><!-- 會話有效期,單位:秒鐘 --> <param-name>session.maxAge</param-name> <param-value>1800</param-value> </init-param> <!-- cookie configuration --> <init-param> <param-name>cookie.name</param-name> <param-value>J2CACHE_SESSION_ID</param-value> </init-param> <init-param> <param-name>cookie.path</param-name> <param-value>/</param-value> </init-param> <init-param> <param-name>cookie.domain</param-name> <param-value></param-value> </init-param> <!-- redis configuration --> <init-param> <param-name>redis.mode</param-name> <param-value>single</param-value> </init-param> <init-param> <param-name>redis.hosts</param-name> <param-value>127.0.0.1:6379</param-value> </init-param> <init-param> <param-name>redis.channel</param-name> <param-value>j2cache</param-value> </init-param> <init-param> <param-name>redis.cluster_name</param-name> <param-value>j2cache</param-value> </init-param> <init-param> <param-name>redis.timeout</param-name> <param-value>2000</param-value> </init-param> <init-param> <param-name>redis.password</param-name> <param-value></param-value> </init-param> <init-param> <param-name>redis.database</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>redis.maxTotal</param-name> <param-value>100</param-value> </init-param> <init-param> <param-name>redis.maxIdle</param-name> <param-value>10</param-value> </init-param> <init-param> <param-name>redis.minIdle</param-name> <param-value>1</param-value> </init-param> </filter> <filter-mapping> <filter-name>j2cache-session-filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3. 啟動應(yīng)用,即可開啟分布式 session 存儲。
當重啟 Web 應(yīng)用時,內(nèi)存中的 session 數(shù)據(jù)為空,會自動從 redis 中讀取重啟前保存的 session 數(shù)據(jù)。所有節(jié)點又通過 redis 進行 session 數(shù)據(jù)的共享,當有 session 數(shù)據(jù)更新時會通過 Redis Pub/Sub 來通知其他節(jié)點重新從 Redis 中讀取數(shù)據(jù),確保不同節(jié)點的 session 數(shù)據(jù)是一致的。