kaka的gravatar头像
kaka 2017-09-25 15:36:55
apache tomcat+memcached实现分布式servlet session机制

最近项目做了点小小的改动,web服务器(tomcat)部署在两台机器上(只给提供两台),防止单节点故障,类似于如下架构

apache tomcat+memcached实现分布式servlet session机制

这种情况下,之前单机的session已经不能满足了,只能修改为分布式的session共享,考虑了两种方案:

第一种是用spring session + redis实现session共享,这种方案其实很简单,spring已经提供了,只需要在pom中引用对应的spring-session-data-redis的jar就行,但是没办法,领导要求只能是两台电脑,redis集群需要至少三台以上才可用(这个在网上查的,没有实际测试过),而且现在项目中用到的缓存是memcached,所以只能放弃这种方案。

第二种就是tomcat+memcached实现分布式session共享,使用的是开源的memcached-session-manager,一个开源的高可用session解决方案。分为两种模式:Sticky模式和Non-Sticky模式,简单介绍下这两种模式:

Sticky模式(粘性session):tomcat session为主session,memcached为备session。每次请求都会被映射到同一台web服务器,除非该web服务器宕机。这样session其实是存放在服务器的本地的,直到请求处理完成后,才会同步到memcached服务器;而当Web服务器宕机时,请求被映射到其他Web服务器,这时候,其他Web服务器可以从后端memcache中恢复session

Non-Sticky(非粘性session):请求每次映射的后端Web服务器是不确定的,当请求到来时,从memcached中加载session,当请求处理完成时,将session再写回到memcached。

目前我们项目中已经实现了分布式的memcached,现在只需要将tomcat+memcached配置好即可。我使用的是Non-Sticky模式

首先需要导入如下jar包到tomcat的lib目录下,对应的pom如下,严格按照jar的版本添加,不然会因为jar冲突导致各种奇怪的报错

<!--分布式session-->
		<dependency>
			<groupId>org.ow2.asm</groupId>
			<artifactId>asm</artifactId>
			<version>5.0.3</version>
		</dependency>
		<dependency>
			<groupId>com.esotericsoftware</groupId>
			<artifactId>kryo</artifactId>
			<version>3.0.3</version>
		</dependency>
		<dependency>
			<groupId>de.javakaffee</groupId>
			<artifactId>kryo-serializers</artifactId>
			<version>0.37</version>
		</dependency>
		<dependency>
			<groupId>de.javakaffee.msm</groupId>
			<artifactId>memcached-session-manager</artifactId>
			<version>1.9.5</version>
		</dependency>
		<dependency>
			<groupId>de.javakaffee.msm</groupId>
			<artifactId>memcached-session-manager-tc7</artifactId>
			<version>1.9.5</version>
		</dependency>
		<dependency>
			<groupId>com.googlecode</groupId>
			<artifactId>minlog</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>de.javakaffee.msm</groupId>
			<artifactId>msm-kryo-serializer</artifactId>
			<version>1.9.5</version>
		</dependency>
		<dependency>
			<groupId>com.esotericsoftware.reflectasm</groupId>
			<artifactId>reflectasm</artifactId>
			<version>1.09</version>
		</dependency>
		<dependency>
			<groupId>net.spy</groupId>
			<artifactId>spymemcached</artifactId>
			<version>2.12.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.objenesis/objenesis -->
		<dependency>
			<groupId>org.objenesis</groupId>
			<artifactId>objenesis</artifactId>
			<version>2.1</version>
			<scope>test</scope>
		</dependency>

然后修改tomcat的conf目录下的server.xml和context.xml,我是在本地虚拟机里面装了两个tomcat指定了两个不同的端口去启动的。

server.xml修改如下:多台web服务器jvmRoute做以区分,如果是本地启动多台tomcat,记得把端口修改为不一样的。

 <Engine name="Catalina" defaultHost="192.168.212.37" jvmRoute="tomcat1">

context.xml修改如下:主要是修改Manager节点,如果是分布式的memcached,memcachedNodes可以写成:memcachedNodes="n1:192.168.212.36:11211,n2:192.168.212.37:11211"这种形式,因为我这里引用的是我物理机上的单点memcached,所以只写了如下的配置:

<Context>

    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" 
	 memcachedNodes="n1:192.168.212.36:11211"
 	 sticky="false"
	 sessionBackupAsync="false"
 	 requestUriIgnorePattern=".*\.(ico|png|gif|jpg|jpeg|bmp|css|js|html|htm)$"
 	transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />

    <!-- Uncomment this to enable Comet connection tacking (provides events
         on session expiration as well as webapp lifecycle) -->
    <!--
    <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
    -->

</Context>

以上操作完成后,启动tomcat,访问不同的web服务器,在同一浏览器里打印sessionId,效果如下:可以看出两台web服务器实现了session共享

apache tomcat+memcached实现分布式servlet session机制

apache tomcat+memcached实现分布式servlet session机制

查看另一台机器上的memcached,可以看到已经存入的sessionId

apache tomcat+memcached实现分布式servlet session机制

 

等抽空把spring session + redis这种方案测试一次

更新于2017年09月28日

更正下,之前我做调研是在自己的虚拟机里面启动了两个tomcat,只是端口不同,直接访问这两个tomcat获取到的sessionId是一样的,今天我部署到测试环境上,发现直接访问两个不同机器的tomcat,获取到的sessionId不同,查询memcached里面发现存了两份,一早上都在怀疑是不是自己配置出问题了,最后另一个同事把keepalive配置好后,也就是该博文最上面的架构图,我通过访问192.168.211.216这个虚拟IP地址通过keepalive去切换到实际的两台tomcat服务器192.168.211.218和192.168.211.220,从这两台服务器后台日志可以看出,哪一个挂掉就会切换到另一台上,而且sessionId是一样的。所以上面的测试如果要在不同机器上生效,应该要配置下Nginx去做下转发,后面再仔细研究下吧。


打赏

已有2人打赏

terryang的gravatar头像 最代码官方的gravatar头像
最近浏览
hhx33333 2021年11月12日
暂无贡献等级
sky_hui  LV6 2019年6月26日
zyl  LV34 2018年6月29日
微微上翘  LV23 2018年2月24日
zhoulukang  LV2 2018年1月24日
哈哈啊实打实的 2017年11月22日
暂无贡献等级
weienqing  LV17 2017年11月20日
狼牙月伊人  LV2 2017年11月4日
ftd2010wmq  LV1 2017年11月3日
wwwzzzjjj  LV15 2017年10月13日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友