tomcat+nginx 分布式集群 redis实现session共享

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tangshuai33333/article/details/79569462

一、理解session、cookie
首先要明确session和cookie的区别。浏览器端 存的是cookie每次浏览器发请求到服务端是http 报文头是会自动加上你的cookie信息的。服务端拿着用户的cookie作为key去存储里找对应的value(session).

同一域名下的网站的cookie都是一样的。所以无论几台服务器,无路请求分配到哪一台服务器上同一用户的cookie是
不变的。也就是说cookie对应的session也是唯一的。

只要保证多台业务服务器访问同一个redis服务器(或集群)就行了。

二、为什么要共享session?

        我们使用单台Tomcat的时候不会有共享sesssion的疑虑,只要使用Tomcat的默认配置即可,session即可存储在Tomcat上。

         但是随着业务的扩大,增加Tomcat节点构成Tomcat集群大势所趋,分布式带来了增加更大规模并发请求的优势,但是也随之到来了一个问题,每个Tomcat只存储来访问自己的请求产生的session,如果Tomcat-A已经为客户端C创建了会话session,那么Tomcat-B并不知道客户端已与集群中的Tomcat-A产生了会话,在访问时就会为C再创建一份session,如果是基于session的验证会话权限的接口(如用户登录认证后才可访问的数据接口),将会导致在访问集群中不同节点的时候重复认证。session的不共享导致原来的会话管理机制在Tomcat集群中无法工作。

         所以,如果有一个Tomcat集群都能访问的公共session存取区就好了,基于这个概念,我们想到了使用Redis来做这个session公共存取区,这样子的话就有一个统一管理回话的地方了。回看我们上文提到的例子,如果Tomcat-A已经为客户端C创建了会话session,这个session信息会直接存储在公共的Redis里面,那么Tomcat-B就可以到公共session存储区里获得已为C产生的session,这样的结果是集群的公共session存取区在逻辑上就像一个tomcat的内部session存取区一样了。

三、解决
1、如果在Tomcat6或Tomcat7下部署,直接将以下jar文件到Tomcat的 lib下即可:
commons-pool2-2.2.jar
jedis-2.5.2.jar
tomcat-redis-session-manage-tomcat7.jar

2、配置tomcat配置文件 conf/context.xml
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />        
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" 
    
host="localhost"             <!-- Redis地址 -->

    port="6379"                  
<!-- Redis端口 -->
    password="123456"            
<!-- Redis密码 -->
    database="0"                 
<!-- 存储Session的Redis库编号 -->
    maxInactiveInterval="60"     
<!-- Session失效的间隔(秒) -->
    />

这样一来我们的tomcat即可把session的管理交由我们配置的redis来处理。
需要注意的是,如果在Tomcat8下按照上述部署,会在启动时报错,笔者查看过原因,是tomcat-redis-session-manager最后更新的年代相隔较久,代码中使用的Tomcat api出现了过时删去的情况,在Tomcat8下会出现问题,如果想在Tomcat8下使用,需要自行对过时的api进行修改,替换成新的Tomcat api。

(以上即可解决session共享问题,第四点是关于redis集群,使系统更稳定的设置)
四、基于sentinel的redis集群搭建

上文介绍的方法其实已经可以搭建一个完整的Tomcat集群了,如果系统想要一个更安全可靠的环境,那么nginx其实也可以做集群,这里略去不说,我们想要说的是redis集群。

上面我们已经说到redis是session的公共存储区,如果redis不幸挂掉的话将会导致致命的问题,因为无session源可取,Tomcat中有session读取的接口会直接报错。所以搭建一个redis集群还是很有必要的,幸好redis对分布式HA的搭建支持得很好,原生即有一套sentinel哨兵机制即可用。

以sentinel模式启动的redis实例起到了监控者的作用,redis集群以master-slave的模式启动,消息不再直接发给redis实例,而是发给sentinel,由sentinel同步至所有的redis实例,如果出现redismaster实例挂掉的情况,会由sentinel发现,根据配置还可以由sentinel自己组成的集群去选举产生新的master,新的master将会承担起作用,起到了灾难自动回恢复的作用。

这里来说一下sentinel集群的配置:
我们使用两个redis实例来组成master-slave,需要三个sentinel组成哨兵集群来监控两个redis实例,在master出现问题的时候选举产生新的master。
路径假设如下:
redis1
redis2
sentinel1
sentinel2
sentinel3

配置redis1/redis.conf为master:

    bind 127.0.0.1
    port 6379

配置redis2/redis.conf为redis1的slave:

    bind 127.0.0.1
    port 6379
    slaveof <redis1_ip> 6379

配置sentinel1/redis-sentinel.conf

    port 26379    
    sentinel monitor mymaster <redis1_ip> 6379 2

指定redis1为master,slave信息会在启动后被sentinel监听到并自动写入到配置文件中,因此不需要手动写入,最后的quorum表示当有2个sentinel判断master挂掉的时候即可选举slave为新的master。

sentinel2sentinel3配置相同。

这样之后启动redis和sentinel集群,即可构建一个高可用的redis集群。可以尝试一下把redis1这个master挂掉,sentinel就会探查到并且在2个sentinel都探查到的时候即会选举产生新的master:

# +monitor master mymaster <redis1-ip> 6379 quorum 2
# +sdown master mymaster <redis1-ip> 6379

同时我们的Tomcat配置也将改为使用sentinel集群的版本:

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
         sentinelMaster="mymaster"
         sentinels="<sentinel1-ip>:26379,<sentinel2-ip>:26379,<sentinel3-ip>:26379"
         maxInactiveInterval="60"/>

这个集群搭建完成后,我们的系统将会更为稳定:

猜你喜欢

转载自blog.csdn.net/Tangshuai33333/article/details/79569462