为了降低单台服务器压力,提高系统的吞吐量,首先想到的是负载,多台服务器共享部署同一个系统,利用F5(硬件)或nginx等(软件)来实现请求分发。
这样可以达到负载提高系统承载能力的目的,但是引发了一个新的问题,服务器之间session无法共享。
比如说:用户发起登录请求,nginx分发到了A服务器,用户登录成功,A服务器用户分配了一个sessionId。然后用户发起了访问个人信息请求,这个时候nginx分发给了B服务器,B服务器没有存储用户的登录信息,这个时候就会给用户踢到登录页面。
问题出来了,有两种解决方式:
1、nginx配置ip_hash;
upstream test {
server localhost:6063;
server localhost:6064;
ip_hash;
}
此方案是通过ip的hash值,将用户每次访问分发到指定的同一台服务器,这样就不需要session共享了。
弊端:当用户访问的服务器宕掉了,无法迅速切换到其他的服务器。等到nginx相应过来,切换到了其他服务器,用户的登录信息也丢失了。
2、tomcat+redis session共享
此方案需要对tomcat配置,比较繁琐,每次部署都需要修改tomcat配置,如有遗漏共享失效,不推荐使用。
3、spring+redis session共享
推荐使用此方案,仅需集成spring的redis架包,部署方便,配置简单。先决条件是你需要安装并启动redis。
a、引入spring的redis架包
<!-- 在<properties>中加入配置 -->
<spring.data.redis.version>1.8.4.RELEASE</spring.data.redis.version>
<jedis.version>2.9.0</jedis.version>
<spring.session.version>1.3.0.RELEASE</spring.session.version>
<!-- 在<dependencies>中加入 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring.data.redis.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>${spring.session.version}</version>
</dependency>
b、在spring配置文件中配置request中的session从redis中获取
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大空闲数 -->
<property name="maxIdle" value="${redis.maxIdle}"/>
<!-- 最大空连接数 -->
<property name="maxTotal" value="${redis.maxTotal}"/>
<!-- 最大等待时间 -->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<!-- 连接超时时是否阻塞,false时报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="${redis.blockWhenExhausted}"/>
<!-- 返回连接时,检测连接是否成功 -->
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>
<!-- Spring-redis连接池管理工厂 -->
<bean id="jedisConnectionFactory" p:password="${redis.pass}" p:hostName="${redis.host}" p:port="${redis.port}" p:timeout="${redis.timeout}"
p:poolConfig-ref="poolConfig" p:usePool="true" p:database="${redis.database}" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"/>
<!-- 1800为session过期时间(单位:秒) -->
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="${redis.session.seconds}"/>
</bean>
redis.properties文件配置如下:
redis.host=localhost
redis.port=16379
redis.database=4
redis.pass=
redis.maxIdle=50
redis.maxTotal=100
redis.maxWait=2000
redis.testOnBorrow=false
redis.blockWhenExhausted=true
redis.timeout=10000
redis.maxWaitMillis=10000
defaultCacheExpireTime=60
redis.session.seconds=1800
c、在web.xml中配置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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
注意:此过滤器一定要在其他过滤器前面。因为系统在处理请求过滤信息是按照过滤器顺序过滤的。曾经在第一次配置的时候就把此过滤器放在判断用户登录过滤器后面,导致一直单台服务器session都有问题的情况,切记!
完毕!
如有错误之处,望指正!感谢!