Spring Boot + Redis 处理 Session 共享

背景

Web 开发中,通过 Session 在服务端记录用户状态是很常见的操作。对于 Web 开发中 Session、Cookie 等概念请参考《Session 机制详解》。但是 Session 的机制对于单机应用是没问题的,但是对于集群环境,由于在将请求分配到另一台服务器时,新的服务器无法通过浏览器传入的 Cookie 值取到 Session,所以导致所有基于 Session 的操作都会失败,如:登录状态。

本文通过搭建一个非常简易的集群环境,来演示 Session 机制在集群环境中存在的问题,并通过 Redis 进行 Session 共享来解决该问题。

一、问题再现

1、测试环境

(1)App Server

使用 Spring Boot 2 写一个简单的 Web 应用,提供两个链接:


Controller 部分代码如下:

@RestControllerpublic class TestController {    @GetMapping("/set-session")    public Object writeSession(String sessionVal, HttpSession httpSession) {        System.out.println("Param 'sessionVal' = " + sessionVal);        httpSession.setAttribute("sessionVal", sessionVal);        return sessionVal;    }    @GetMapping("/get-session")    public Object readSession(HttpSession httpSession) {        Object obj = httpSession.getAttribute("sessionVal");        System.out.println("'sessionVal' in Session = " + obj);        return obj;    }}

单机测试通过。

(2)通过 Nginx 做负载均衡
分别在 9001 和 9002 两个端口启动 App Server,然后通过 Nginx 配置负载均衡,配置如下:

http {    upstream app_server {        server 127.0.0.1:9001;        server 127.0.0.1:9002;    }    server {        listen 9000;        location / {            proxy_pass http://app_server;        }    }}

测试失败。

二、原因分析

主要是因为原来 A 服务器将其 Session 的标识 Cookie_for_Session_A 放入浏览器 Cookie,当下一次请求被分配到 B 服务器,B 服务器无法通过  Cookie_for_Session_A 获取到对应的 Session,导致失败。

解决的思路,主要是引入三方服务器,将 Session 保存到三方服务器,A、B 服务器共享三方服务器中的 Session 数据。

三、解决方案

引入 Redis 作为三方服务器存储 Session 数据。

1、引入 Redis 相关库

dependencies {    implementation('org.springframework.boot:spring-boot-starter-web')    implementation('org.springframework.boot:spring-boot-starter-data-redis')    // https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis    compile group: 'org.springframework.session', name: 'spring-session-data-redis', version: '2.1.2.RELEASE'}

2、配置 Redis 连接

application.yml,这里为了演示清晰,只做了最简配置,正式使用请调整相关参数

spring:  redis:    host: 127.0.0.1    port: 6379

3、开启配置

创建一个配置类 SessionConfig,类名随意。

关键是两个注解:

@Configuration@EnableRedisHttpSession@Configuration@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)public class SessionConfig {}

4、打包、运行测试

执行 Gradle 的 bootJar 任务,然后按照前面的方式,分别在 9001 和 9002 端口运行 jar 包:

java -jar redis-session.jar java -jar redis-session.jar

测试通过。

来源:https://blog.51cto.com/13981400/2367775


1PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。Java后端编程交流群已成立公众号运营至今,离不开小伙伴们的支持。为了给小伙伴们提供一个互相交流的平台,特地开通了官方交流群。扫描下方二维码备注 进群 或者关注公众号 Java后端编程 后获取进群通道。 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 —————END————— 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 推荐阅读: 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 简单、易用的 MySQL 官方压测工具 80 81 82 8312306”的架构到底有多牛逼? 84 85 86 87 新技能 MyBatis 千万数据表,快速分页! 88 89 90 91 一文搞懂 Redis 缓存穿透、击穿、雪崩! 92 93 94 95 MyBatis-Plus常用 API 全套教程 96 97 98 99 腾讯,干掉 Redis 项目,正式开源、太牛逼啦! 100 101 102 103 IntelliJ IDEA 更新后,电脑卡成球,该如何优化? 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。 127 128 129 130 131 132 133 134 135 136 137 138 明天见(。・ω・。)ノ♡ 139 140 141 142 143 144 145 146

本文分享自微信公众号 - Java后端编程(java_hdbc)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )