利用Redis实现session共享

在负载均衡环境中,session不一致是个问题。通过IP_HASH策略可以将同一IP请求分配到同一服务器,但存在session丢失风险。session复制利用组播网络在Tomcat间同步,但性能较低且内存消耗大。采用session共享,结合Redis作为session存储,能适应多种负载策略,即使服务器重启也不会丢失session,但需序列化操作,增加性能开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

负载均衡

首先使用nginx配置一个简单的负载均衡:

upstream myupstream{
    server *.*.*.*:8080 weight=1;
    server *.*.*.*:8081 weight=1;
}
server{
    listen *.*.*.*:80
    local / {
        proxy_pass http://myupstream;
    }
}

session不一致产生的原因

在配置了负载均衡之后,本地发出的请求会被分发到不同的服务器上,第一次请求时,服务器1会产生一个session写到服务器内存中并将sessionid返回到本地浏览器中的cookie中,第二次请求时,本地发起请求同时会携带该sessionid到服务器2,但服务器2内存中并不存在该sessionid,因此会创建一个新的session并返回到本地浏览器中,之后的每一次请求都会循环这个过程,导致用户信息丢失。

解决方案

基于IP_HASH的负载均衡
  • 实现
    设置负载均衡策略为iphash
upstream backserver { 
ip_hash; 
    server *.*.*.*:8080;
    server *.*.*.*:8080;
}
  • 原理:
    同一ip的请求会分发到同一服务器进行处理
  • 优点:
    1、配置简单,无需修改代码,不入侵应用。
    2、便于水平拓展。
  • 缺点:
    1、服务器出现故障或者重启会导致session丢失
    2、可能会导致单点负载过高,
Session复制
  • 实现
    1、修改tomcat配置文件server.xml,添加cluster节点
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">

<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>

<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
bind="127.0.0.1"
address="228.0.0.4"<!--保留ip,用于广播-->
port="45564"
frequency="500"
dropTime="3000"/> 
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4001"<!--如果是在同一台机器上的两个tomcat做负载,则此端口则不能重复-->
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>

<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

2、修改应用内web.xml,增加节点

<distributable/> 
  • 原理
    多个tomcat利用组播网络复制session.(224.0.0.0~224.0.0.255为用户可用的组播地址)
  • 优点:
    1、不入侵应用
    2、可以适应各种负载均衡策略
    3、服务器重启或者宕机不会造成session丢失
  • 缺点
    1、性能低
    2、内存消耗大
session共享
  • 实现
    1、添加相关依赖
<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
  <version>1.2.1.RELEASE</version>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.8.1</version>
</dependency>

2、web.xml添加过滤器

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3、spring配置

	<context:property-placeholder location="classpath:config/redis.properties"
		ignore-unresolvable="true" />
	<!-- 启用redis session maxInactiveIntervalInSeconds为过期时间-->
	<bean id="redisHttpSessionConfiguration"
		class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
		<property name="maxInactiveIntervalInSeconds" value="600" />
	</bean>
	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxWaitMillis" value="${redis.maxWait}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
	</bean>
	<!-- redis连接工厂 -->
	<bean id="connectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="poolConfig" ref="poolConfig" />
		<property name="port" value="${redis.port}" />
		<property name="hostName" value="${redis.host}" />
		<property name="password" value="${redis.password}" />
		<property name="timeout" value="${redis.timeout}"></property>
	</bean>
  • 优点
    1、适应多种负载均衡策略。
    2、服务器重启或者宕机不会造成session丢失。
    3、拓展能力强,适合集群数量大使用。
  • 缺点
    1、入侵应用。
    2、redis读取与存储需要序列化,消耗性能。
  • 原理
    利用过滤器,将HttpSession替换为RedisSession。
    参考:https://blog.youkuaiyun.com/jiaojizu/article/details/80946994
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值