Session保持
一.Session本质
http协议是无状态的,服务端对于客户端来说是透明的,连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。
但是,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。
二.关于Session共享
首先,单机环境不存在session共享的问题,但是无法保证高可用,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。
三.Session共享解决方案
1.采用Nginx负载均衡器,采用的ip_hash来代替默认的轮询方式,即可以将某客户端IP的请求通过哈希算法定位到同一台后端web服务器上,这样避免了session丢失,解决了session问题。
但ip_hash指令无法保证后端服务器的负载均衡,可能有些后端服务器接收的请求多,有些后端服务器接收的请求少;这样失去了负载均衡的意义。
2.将用户的登录session信息写进后端的Mysql数据库,这个在后面的CMS系统中也实现了,效果也不错;但是,用数据库来同步session,会加大数据库的IO,增加数据库的负担。而且数据库读写速度较慢,不利于session的适时同步,不推荐。
后来我提出了折衷方案,如果Nginx并发连接数(即Nginx负载均衡器的NginxStatus的 active connections)>2000,即采用将session写进MySQL数据库的方法;如果并发数小的话,ip_hash效果也是相当好的。
可参考:http://blog.csdn.net/donggang1992/article/details/51095551
3.Session复制,适用于接入层集群较少时,因为session复制占用服务器资源,存储占内存
例如:可以将session缓存到redis中,达到session复制的目的。目前此种方案是 nginx + redis + tomcat 实现的
4.Session绑定,主从复制 ************【ip_hsah 未尝试主从复制】**************
5.客户端cookie保存Session
6.Session集群
一.使用 filter 方法存储(未实现)
这种方法比较推荐,因为它的服务器使用范围比较多,不仅限于 tomcat ,而且实现的原理比较简单容易控制。
可以使用 memcached-session-filter
官方网址:http://code.google.com/p/memcached-session-filter/
官方介绍:解决集群环境下java web容器session共享,使用filter拦截器和memcached实现。在tomcat 6和websphere 8测试通过,现网并发2000,日PV量1100万。
暂不支持session event包括create destory 和 attribute change
东西很不错,体积很小,不过这个东东要和 spring 一起使用,而且要求存储到 memcached 的对象要实现 java 的序列化接口
大家也知道,java 本身的序列化性能也很一般。
我将其简单扩展了一下,不再依赖 spring ,并且利用 javolution 实现序列化,缓存的对象不再有限制。
暂时没有发现 redis 的实现,后面将自己实现使用 redis 存储并且序列化使用 kyro ,详细情况有时间再单独写出来。
二.基于Tomcat本身的session集群共享(未实现)
问题:配置完成,但是无效;
参考的是:tomcat session共享;
三.使用 tomcat session manager 方法存储
这种方法服务器只能使用 tomcat ,但网上有针对 memcached 和 redis 实现,直接配置就行了。 针对Redis,已实践
1.环境准备
Tomcat集群
IP | 主机名 | 端口号 |
192.168.1.111 | edu-web-01 | 8081 |
192.168.1.112 | edu-web-02 | 8081 |
Redis集群
通过TWEMPROXY构建的Redis集群
192.168.1.122 | edu-redis-01 | 6660/6661 |
192.168.1.123 | edu-redis-02 | 6661 |
192.168.1.124 | edu-redis-03 | 6661 |
相关命令:(含配置文件地址)
需要在192.168.1.122,123,124 上分别启动:
SSDB 7770 7771 8880 8881
nohup /usr/local/ssdb/ssdb-server /usr/local/ssdb-master/ssdb_basic_7770.conf &
nohup /usr/local/ssdb/ssdb-server /usr/local/ssdb-master/ssdb_basic_7771.conf &
nohup /usr/local/ssdb/ssdb-server /usr/local/ssdb-master/ssdb_desc_8880.conf &
nohup /usr/local/ssdb/ssdb-server /usr/local/ssdb-master/ssdb_desc_8880.conf &
REDIS
192.168.1.122:6660 6661
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6660.conf &
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6661.conf &
192.168.1.123 6661
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6661.conf &
192.168.1.124 6661
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6661.conf &
启动Twemproxy
nutcracker.init {start|stop|status|restart|reload|condrestart}
nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/run/redisproxy.pid -o /usr/local/twemproxy/run/redisproxy.log
测试:
redis-cli -h 192.168.1.122 -p 1115
2.配置Tomcat
2.1 新增jar包,将这3个jar包放到Tomcat的lib目录下
tomcat-redis-session-manager-1.2-tomcat-7.jar
jedis-2.1.0.jar
commons-pool-1.6.jar
2.2设置Tomcat配置文件
修改 context.xml 文件,在<context></context>内新增
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve"/>
<Manager className="com.radiadesign.catalina.session.RedisSessionManager" database="0" host="192.168.1.122" maxInactiveInterval="60" port="1115"/>
</Context>
注:我在server.xml配置时出现问题,同时在<context>内配置一开始也没成功,原因未查
2.3 运行测试环境
将WEB项目分别添加到2个Tomcat中并启动。
在test1应用的index.jsp中增加如下代码
<%
session.setAttribute("shareSession", "redis share Session")
%>
<a href="/test2">test2 index.jsp</a>
在test2应用的index.jsp中增加如下代码
<%=session.getAttribute("shareSession")%>(输出为NULL)
分别访问Tomcat1和Tomcat2,发现两边浏览器的jsessionid是一样的,在Redis控制台运行key *打印出来的就是共享的jsessionid。
此外,还可以使用memcache,未实践
1、修改 tomcat 的 conf 目录下的 context.xml 文件:
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:localhost:11211 n2:localhost:11212" failoverNodes="n2"
requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$" sessionBackupAsync="false" sessionBackupTimeout="100" transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory" copyCollectionsForSerialization="false" />;
2、以上是以 1.3 版为例子,需要用的 jar 包:
memcached-session-manager-1.3.0.jar
msm-javolution-serializer-1.3.0.jar
javolution-5.4.3.1.jar
memcached-2.4.2.jar
四.基于terracotta 服务器共享
参考:http://www.cnblogs.com/interdrp/p/4056525.html 待实现