最近在研究Nginx+Tomcat实现负载均衡,实验成功后发现了一个问题:用户登录成功后,总是会自动退出系统。经过判断,发现在负载均衡的情况下,每次操作访问后台都有可能访问不同的Tomcat服务器,因此就会判断当前登录用户的session无效而导致退出系统。
解决这种问题的一个比较简单的方法就是在nginx的配置文件与负载均衡相关的配置处加入ip hash,这样每次就会只访问一台Tomcat服务器而不会退出系统。但是这样也有一个问题,就是如果访问的服务器挂了,就无法继续访问系统了。
咨询了一下同事,才知道可以用Tomcat+Nginx+Redis实现共享session,这样做既能达到负载均衡的目的,也能保持用户登录后session持久性,可谓一石二鸟。
采用Tomcat+Nginx+Redis实现分布式session共享大致分为3步:
1、 修改web系统配置;
2、 修改web系统中所有读取或操作session的地方;
3、 配置Nginx服务器。
下面分别来讲解一下这三步的操作:
1、 修改web系统配置
修改web系统配置也分3步:
1) 引入Redis的Maven依赖
<!-- Jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.2</version>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<!-- Spring Session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<!-- Apache Commons Pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2) 配置Redis
A) redis.properties
#redis主机地址
redis_hostName=127.0.0.1
#端口号
redis_port=6379
#密码
redis_password=123456
#连接超时时间
redis_timeout=20000
B) spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- session设置 -->
<!--
maxInactiveIntervalInSeconds是设置session有效时间,以秒为单位,
但实际上无论怎么设,session真实有效时间还是会比我们设置的稍微长一些
-->
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="3600" />
</bean>
<!-- redis连接池 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" />
<!-- redis连接工厂 -->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis_hostName}" />
<property name="port" value="${redis_port}" />
<property name="password" value="${redis_password}" />
<property name="timeout" value="${redis_timeout}" />
<property name="poolConfig" ref="poolConfig" />
</bean>
</beans>
3) 配置web.xml
A) 在web.xml文件中要引入spring-redis.xml配置文件:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-redis.xml</param-value>
</context-param>
B) 同时,还要配置Filter
<!-- session过滤器 -->
<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>
通常情况下,如果有其他的过滤器,一般将Spring Session过滤器放到第一位。
2、 修改web系统中所有读取或操作session的地方;
1) 如登录过程中,需要将session放到内存中:
HttpSession session = request.getSession();
User user = userService.findByLogin(username, password);
if(null != user){
//需要注意的是如果要往redis中存入对象,则需要将该对象序列化才能存入
session.setAttribute("loginUser", JSON.toJSONString(user));
}
2) 在拦截器中获取session信息的代码:
String userString = request.getSession().getAttribute(“loginUser”).toString();
User user = JSON.parseObject(userString, User.class);
3、 配置Nginx服务器:
至此,全部配置完成。对系统进行访问测试,用户登录后不会再发生因为session无效而退出系统的情况,系统已经能正常访问。