在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外一台服务器的时候,session丢失。
nginx.conf配置示例
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#keepalive_timeout 0;
keepalive_timeout 65;
upstream spring-session {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://spring-session;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
请求本地localhost,可调用8081,8082,8083三个端口的应用
常规的解决方案都是使用:如apache使用mod_jk.conf,使用Memcached进行共享。
在开发spring boot app的时候可以借助 spring session 和redis或者ehcache,用外置的redis或者ehcache来存储session的状态,这里使用redis进行介绍,ehcache实现是一样的。
增加相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
在spring boot的文档中,告诉我们添加@EnableRedisHttpSession来开启spring session支持,而@EnableRedisHttpSession这个注解是由spring-session-data-redis提供的,所以在pom.xml文件中spring-session-data-redis
RedisSessionConfig.java
package com.wisely.base;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@Configuration
@EnableRedisHttpSession
public classRedisSessionConfig {
}
如果需要添加失效时间可以使用以下的写法:
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 60) //1分钟失效
@EnableRedisHttpSession注解的源码如下,可以看到可以配置三个参数:
- maxInactiveIntervalInSeconds :session中的数据的过期时间(不是session在redis中的过期时间)
- redisNamespace :命名空间,可以配置当前应用的名称,我这里配置了 mysession.
- redisFlushMode :redis保存session的方式,默认 ON_SAVE
有两种方式: IMMEDIATE:一旦创建session的时候就立即保存. ON_SAVE:创建session的时候不会保存,但当往session中添加数据的时候就会保存
相关配置修改
在application.properties修改redis配置信息(请自行安装redis),请根据实际修改。如:
###### Redis config start ######
spring.redis.database=0
spring.redis.host=192.168.41.60
spring.redis.port=6379
spring.redis.password=
spring.redis.pool.max-active=20
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.timeout=0
###### Redis config end ######
在application.properties还需指定分布式数据存放的方式为redis。如:(当然spring-session 也支持更多的存储方式,具体参考文档)
spring.session.store-type=redis
所有实体类实现Serializable接口
public class SysResource implements Serializable
查看效果
这时候登录系统在不同的app之间跳转的时候,session都是一致了,redis上可以看到:
总结
使用这些代码之后 ,无论你使用nginx或者apache,都无须在关心多个app之间的session一致的问题了。
注意事项
(1)redis版本号需要是2.8以上否则会抛异常:ERR Unsupported CONFIG parameter: notify-keyspace-events;
(2)RedisSessionConfig需要放在App.java启动类可以扫描的位置;
配置Nginx的时候,注意要注释ip_hash,不然通一个IP的请求,会被转发到通一个服务里面。
upstream spring-session {
# ip_hash
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
补充------------
如果使用Security,下面的几步需要配置。
Spring Security 配置
在项目中添加该类:
[java] view plain copy
1. public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
2.
3. public SecurityInitializer() {
4. super(SecurityConfig.class, Config.class);
5. }
6. }
super()的第二个参数,就是我们上面的那个Config文件。添加这个配置文件后,Spring Security就会把Session放到Redis中,这样基于Spring Security的项目也可以实现Session共享了。
Initializer 配置
这一步写法异常简单,还是创建文件:
[java] view plain copy
1. public class Initializer extends AbstractHttpSessionApplicationInitializer {
2.
3. }
就这样,继承一个类即可。