java session 共享方案_SpringBoot 分布式 Session 共享解决方案

SpringBoot 分布式 Session 共享解决方案

分布式Session一致性?

说白了就是服务器集群Session共享的问题,集群情况下,session保存在各自的服务器的tomcat中,当分发地址至不同服务时,导致sesson取不到,就会产生session共享问题。

Session的作用?

Session 是客户端与服务器通讯会话跟踪技术,服务器与客户端保持整个通讯的会话基本信息。

客户端在第一次访问服务端的时候,服务端会响应一个sessionId并且将它存入到本地cookie中,在之后的访问会将cookie中的sessionId放入到请求头中去访问服务器,如果通过这个sessionid没有找到对应的数据那么服务器会创建一个新的sessionid并且响应给客户端。

分布式 Session 存在的问题?

假设第一次访问服务A生成一个sessionid并且存入cookie中,第二次却访问服务B客户端会在cookie中读取sessionid加入到请求头中,如果在服务B通过sessionid没有找到对应的数据那么它创建一个新的并且将sessionid返回给客户端,这样并不能共享我们的Session无法达到我们想要的目的。

解决方案:使用cookie来完成(很明显这种不安全的操作并不可靠)

使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(不支持负载均衡)

利用数据库同步session(效率不高,访问压力大)

使用tomcat内置的session同步(同步可能会产生延迟,集群过多tomcat,session全局复制导致性能下架)

使用token代替session

使用spring-session以及集成好的解决方案,存放在redis中(读写效率高,并可在集群环境下做高可用)

spring-session 实战

启动两个SpringBoot项目端口号分别为 8080、8090 进行测试。

1、项目依赖// spring boot 与 redis应用基本环境配置

compile 'org.springframework.boot:spring-boot-starter-data-redis:2.1.4.RELEASE'

// spring session 与 redis应用基本环境配置

compile 'org.springframework.session:spring-session-data-redis:2.1.5.RELEASE'

2、测试类@RestController

@RequestMapping("/test")

public class TestController {

@Value("${server.port}")

private Integer projectPort;

@GetMapping("/createSession")

public String createSession(HttpSession session, String name) {

session.setAttribute("name", name);

return "当前项目端口:" + projectPort + " 当前sessionId:" + session.getId() + " 在Session中存入成功!";

}

@GetMapping("/getSession")

public String getSession(HttpSession session) {

return "当前项目端口:" + projectPort + " 当前sessionId:" + session.getId() + "  获取的姓名:" + session.getAttribute("name");

}

}

3、yml 文件配置

为了演示方便,我配置了两个 yml 文件,只是端口不同。

application.ymlserver:

port: 8080

spring:

redis:

host: 127.0.0.1

port: 6379

application-8090.ymlserver:

port: 8090

spring:

redis:

host: 127.0.0.1

port: 6379

4、启动类

在 Spring boot 的文档中,添加 @EnableRedisHttpSession 来开启 `spring session`支持,配置如下:@SpringBootApplication

@EnableRedisHttpSession

public class AppRun {

public static void main(String[] args) {

SpringApplication.run(AppRun.class, args);

}

}

这样以来,最简单的 Spring boot + redis 实现 session 共享就完成了,下面进行下测试。

5、测试

首先我们开启两个 tomcat 服务,端口分别为 8080 和 8090。

bc7fdfc03a181785f939cc7c3cabcadc.gif

启动之后进行访问测试,首先访问 8080 端口的 tomcathttp://localhost:8080/test/createSession

bc7fdfc03a181785f939cc7c3cabcadc.gif

然后访问 8080 端口的 getSessionhttp://localhost:8080/test/getSession

bc7fdfc03a181785f939cc7c3cabcadc.gif

然后再访问 8090 端口的 getSessionhttp://localhost:8090/test/getSession

bc7fdfc03a181785f939cc7c3cabcadc.gif

可见,8080与9090两个服务器返回结果一样,实现了session的共享。

6、redis 查看

查看 redis 时,注意到生成了 3 个key。包含了过期时间,sessionId等。127.0.0.1:6379> keys *

1) "spring:session:expirations:1557234900000"

2) "spring:session:sessions:expires:70c59a29-e6ef-4d4f-825d-03dae4502686"

3) "spring:session:sessions:70c59a29-e6ef-4d4f-825d-03dae4502686"

127.0.0.1:6379> hkeys spring:session:sessions:70c59a29-e6ef-4d4f-825d-03dae4502686

1) "creationTime"

2) "maxInactiveInterval"

3) "lastAccessedTime"

4) "sessionAttr:name"

bc7fdfc03a181785f939cc7c3cabcadc.gif

因为 session 是存储在 redis 中,所以,当我把 8080 和 8090 服务器同时停掉之后,再重新启动,然后刷新浏览器中的响应,session 依然可以获取得到。这就保证了用户在登录后,重新启动服务器 session 不会失效的问题。

@EnableRedisHttpSession 注解

在上面的启动类中,用到了 @EnableRedisHttpSession 的注解,查看源码注意到它有 4 个参数让我们使用。public @interface EnableRedisHttpSession {

/**

* 会话超时(以秒为单位)。 默认情况下,它设置为1800秒(30分钟)

*/

int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;

/**

* 为 redis key 定义唯一的命名空间,默认前缀是 spring:session:

*/

String redisNamespace() default RedisOperationsSessionRepository.DEFAULT_NAMESPACE;

/**

* Redis会话的刷新模式。 默认为 ON_SAVE,另一个是 IMMEDIATE

*/

RedisFlushMode redisFlushMode() default RedisFlushMode.ON_SAVE;

/**

* 过期会话清理的cron表达式。 默认情况下每分钟运行一次

*/

String cleanupCron() default RedisHttpSessionConfiguration.DEFAULT_CLEANUP_CRON;

}

比如设置@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 7200)

Spring Session 的两种刷新模式 RedisFlushMode,参考文章:http://www.ibloger.net/article/3360.html

nginx 集群配置

通过spring boot + redis来实现session的共享非常简单,而且用处也极大,配合nginx进行负载均衡,便能实现分布式的应用了。

例如开启 nginx 集群配置如下:# 默认使用轮询,

upstream backserver{

server 127.0.0.1:8080;

server 127.0.0.1:8090;

}

# 修改server中的local

location / {

proxy_pass  http://backserver;

...

}

Gitee源码

https://gitee.com/liurenkui/springboot-session-demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值