分布式Session
我用「餐厅点餐+代码实战」帮你彻底搞懂分布式Session,看完不仅能应对面试,还能直接应用到实际开发。先记住这个核心矛盾:多服务员如何记住同一顾客的喜好?
一、从生活场景理解Session的本质
传统单机场景(小餐馆)
- 服务员:Tom(唯一服务员)
- 工作流程:
- 顾客首次点餐 → Tom给纸质会员卡(SessionID)
- Tom把顾客口味记录在自己的笔记本(服务器内存)
- 顾客下次出示会员卡 → Tom查笔记本提供服务
分布式场景(连锁餐厅)
- 服务员:Tom、Jerry、Lucy(多个服务器节点)
- 致命问题:
- 顾客第一次找Tom存了爱吃辣 → 第二次请求被分配到Jerry → Jerry一脸懵逼
二、分布式Session五大解决方案
方案1:黏性会话(Sticky Session)
- 原理:让同一用户的请求始终路由到同一服务器
- 实现:Nginx配置ip_hash
upstream backend {ip_hash; # 像给顾客发固定服务员工牌server 192.168.1.101:8080;server 192.168.1.102:8080;
}
- 优点:零改造成本
- 缺点:
- 服务器宕机 → Session丢失(相当于服务员请假,笔记本被带走)
- 扩容缩容困难(新服务员没有历史记录)
方案2:Session复制(同步广播)
- 原理:所有服务器实时同步Session数据
- 实现:Tomcat配置集群
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
- 优点:任意服务器都可响应
- 缺点:
- 网络带宽消耗大(相当于每天让所有服务员互相抄笔记)
- 不适合大规模集群(超过10个节点性能暴跌)
方案3:集中存储(重点掌握)
- 原理:把Session存到独立存储服务
- 架构:
用户 → 负载均衡 → 任意服务器 → Redis/Memcached - 代码示例(Spring Session + Redis):
- 添加依赖:
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId> </dependency>- 配置Redis连接:
@EnableRedisHttpSession public class Config {@Beanpublic LettuceConnectionFactory connectionFactory() {return new LettuceConnectionFactory("redis-host", 6379);} }- 使用Session与单机完全一致:
@GetMapping("/login") public String login(HttpSession session) {session.setAttribute("user", "码农阿杜"); // 自动存到Redisreturn "登录成功"; } - 优点:
- 服务器无状态,方便扩容
- 数据持久化,服务器重启不丢失
- 缺点:
- 增加网络延迟(多一次存储访问)
- 需要维护中间件
方案4:客户端存储(JWT方案)
- 原理:把Session数据加密后直接存Cookie
- 代码示例:
// 生成Token String token = Jwts.builder().setSubject("user123").claim("role", "admin").signWith(SignatureAlgorithm.HS256, "secretKey").compact();// 验证Token Claims claims = Jwts.parser().setSigningKey("secretKey").parseClaimsJws(token).getBody(); - 优点:彻底解决服务端存储问题
- 缺点:
- Token无法主动失效(相当于会员卡永久有效)
- 数据大小受Cookie限制
方案5:Session共享协议(Token+数据库)
- 实现流程:
- 登录成功生成token(UUID)
- 把token和用户数据存入数据库
- 每次请求携带token查询数据库
- 代码示例:
// 生成Token String token = UUID.randomUUID().toString(); redisTemplate.opsForValue().set(token, userInfo, 30, TimeUnit.MINUTES);// 拦截器验证 String token = request.getHeader("X-Token"); User user = redisTemplate.opsForValue().get(token); if(user == null) throw new AuthException(); - 优点:灵活控制存储方式
- 缺点:需要手动管理生命周期
三、方案选型决策树
是否需要服务器完全无状态?
├─ 是 → 客户端存储(JWT)
└─ 否 → 是否需要高并发?├─ 是 → 集中存储(Redis)└─ 否 → Session复制(小集群)/黏性会话(稳定集群)
四、面试高频问题
Q1:如何防止Session劫持?
- 防御措施:
- 使用HTTPS防止网络嗅探
- Cookie设置HttpOnly和Secure
- 定期更换SessionID(如每10分钟)
Q2:分布式Session过期时间如何设置?
- 黄金法则:
- 基础过期时间:30分钟
- 滑动过期:每次访问刷新有效期
// Redis示例 redisTemplate.expire(sessionId, 30, TimeUnit.MINUTES);
Q3:Spring Session的实现原理?
- 核心机制:
- 通过Filter替换原生HttpSession
- SessionRepositoryFilter包装请求/响应
- 实际存储委托给Redis等实现
五、生产环境最佳实践
- Session数据最小化:只存必要信息(如userId)
- 读写分离:Redis主从架构提升读取性能
- 降级方案:在Redis故障时自动切换本地缓存
- 监控预警:监控Session存储容量和延迟
一句话总结
分布式Session的本质是:把服务员们的笔记本换成中央档案室! 掌握这个本质,所有解决方案都是围绕存储位置和同步方式的设计权衡。
补充
方案3和方案5确实都涉及外部存储,但它们的核心差异在于数据管理层次和实现方式。我用餐厅工作流程对比帮你彻底分清这对「双胞胎」:
本质区别对比表
| 方案3:集中存储(Spring Session) | 方案5:Session共享协议(Token+DB) | |
|---|---|---|
| 管理层次 | Web容器层自动管理(对开发者透明) | 应用层手动管理(需要显式编码) |
| 存储内容 | 完整Session对象(序列化存储) | 自定义业务数据(如用户ID、权限等) |
| 标识传递 | 自动通过Cookie传递JSESSIONID | 手动通过Header/Param传递自定义Token |
| 数据读写 | 框架自动完成(如Spring Session Filter拦截读写) | 需要手动编写存取代码 |
| 典型应用 | 传统Web应用迁移到分布式环境 | 前后端分离架构/APP接口 |
餐厅版对比解释
假设餐厅要记录顾客的「忌口清单」:
方案3:中央档案室(Spring Session)
- 服务员直接说:“忌口清单存总部”
- 每次顾客出示会员卡 → 服务员自动联系总部查清单
- 优势:服务员工作方式不变,只是数据位置换了
方案5:自定义登记表(Token+DB)
- 服务员需要:
- 设计新的登记表格(定义Token格式)
- 手动打电话给总部:“把顾客A的清单给我”
- 更新后主动回传总部:“这是顾客A的新清单”
- 优势:完全掌控数据格式和流程
代码级区别演示
方案3典型代码(无感知):
// 和单机Session用法完全一致
HttpSession session = request.getSession();
session.setAttribute("user", user); // 自动存入Redis
方案5典型代码(全手动):
// 登录时生成并存储
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(token, user.getId(), 30, TimeUnit.MINUTES);// 拦截器中验证
String token = request.getHeader("X-Token");
if(!redisTemplate.hasKey(token)) {throw new UnauthorizedException();
}
Long userId = redisTemplate.opsForValue().get(token);
如何选择?
-
选方案3如果:
- 已有传统Web应用需要改造
- 想保持原有Session API写法
- 不介意依赖Spring生态
-
选方案5如果:
- 全新设计的前后端分离系统
- 需要精细控制Session数据结构
- 追求轻量化/去框架依赖
一句话总结区别
方案3是让框架帮你搬行李的旅行社,方案5是自己打包的自助游
两者最终都到达目的地(完成分布式Session),但过程体验和自由度截然不同。
相关文章:
分布式Session
我用「餐厅点餐代码实战」帮你彻底搞懂分布式Session,看完不仅能应对面试,还能直接应用到实际开发。先记住这个核心矛盾:多服务员如何记住同一顾客的喜好? 一、从生活场景理解Session的本质 传统单机场景(小餐馆&…...
Kotlin 运算符重载
在Kotlin中,常用的运算符重载函数名如下: 1.算术操作符: 加法:plus 减法:minus 乘法:times 除法:div 取模:rem 或 mod 整数除法:floorDiv 求幂:pow 自增&…...
OpenHarmony4.1-轻量与小型系统ubuntu开发环境
因OpenHarmony官网提供包含轻量、小型与标准系统的全量代码非常宠大,解包后大概需要70G以上硬盘空间,如要编译标准系统则需要140G以上空间。 如硬盘空间有限与只使用轻量/小型OpenHarmony系统,则可以下载并直接使用本人裁剪源码过的ubuntu硬盘…...
AVR 单片机硬件供电处理
摘自AVR 单片机应用笔记:AN2519 - AVR Microcontroller Hardware Design Considerations。 2. 供电 供电设计是任何硬件设计的关键一环,直接影响到系统的性能。在设计供电时,有两个重要的方面需要考虑:ESD 防护和噪声干扰。这些内…...
LeetCode 27 移除元素
LeetCode 27 - 移除元素(Remove Element)是一个简单但经典的双指针问题,主要考察数组操作的基本功。虽然问题容易,但掌握多种解法以及衍生的变体问题对解决更复杂的操作数组问题有帮助。 题目描述 输入:整数数组 nums…...
对“预训练”的理解
预训练有什么用 传统的机器学习是偏数学的,对数据的量不做过多要求,而深度学习的项目通常是有大量的数据可供使用。 在平常的任务或者项目中,我们可能并没有大量数据,只有少量数据,在这时我们就可以通过“借用”有大…...
论文阅读:CAN GENERATIVE LARGE LANGUAGE MODELS PERFORM ASR ERROR CORRECTION?
CAN GENERATIVE LARGE LANGUAGE MODELS PERFORM ASR ERROR CORRECTION? 生成式大语言模型能否进行自动语音识别(ASR)纠错? https://arxiv.org/pdf/2307.04172 文章目录 速览常规总结通俗版 摘要(Abstract)2. 引言&a…...
Stable Diffusion(SD)系列模型及关联算法深度解析
一、基础模型架构演进 SD v1.5 核心架构:基于Latent Diffusion Model(LDM),通过VAE将图像压缩至潜空间进行扩散训练,支持512x512分辨率生成,兼容二次元与写实风格混合创作12。 训练数据&…...
FPGA开发,使用Deepseek V3还是R1(3):系统级与RTL级
以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&#x…...
logback日志输出配置范例
logback日志输出配置范例 在wutool中,提供了logback日志输出配置范例,实现日志文件大小限制、滚动覆盖策略、定时清理等功能。 关于wutool wutool是一个java代码片段收集库,针对特定场景提供轻量解决方案,只要按需选择代码片段…...
【开源免费】基于SpringBoot+Vue.JS酒店管理系统(JAVA毕业设计)
本文项目编号 T 224 ,文末自助获取源码 \color{red}{T224,文末自助获取源码} T224,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
Unity中动态切换光照贴图LightProbe的方法
关键代码:LightmapSettings.lightmaps lightmapDatas; LightmapData中操作三张图:lightmapColor,lightmapDir,以及一张ShadowMap 这里只操作前两张: using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;public cl…...
linux(2)用户管理
文章目录 1. 切换用户2. 添加删除用户3.写改密码 1. 切换用户 # 切换用户名,不切换工作目录 su 用户名 # 一起切换工作目录 su - 用户名 # 退出用户 exit2. 添加删除用户 # 添加用户 sudo adduser username # 推荐sudo useradd -m -s /bin/bash 用户名-m 如果创建…...
在鸿蒙HarmonyOS手机上安装hap应用
一、下载工具 安装hap包需要用到小工具 。 二、解压到目录后,进入该文件夹,打开命令行,如下图 三、将下载好的hap包放入刚才解压的文件夹内(假设hap包文件名为app.hap) 四、连接好手机和电脑,手机需要打…...
MacBook Pro使用FFmpeg捕获摄像头与麦克风推流音视频
FFmpeg查看macos系统音视频设备列表 ffmpeg -f avfoundation -list_devices true -i "" 使用摄像头及麦克风同时推送音频及视频流: ffmpeg -f avfoundation -pixel_format yuyv422 -framerate 30 -i "0:1" -c:v libx264 -preset ultrafast -b:v 1000k -…...
工程化与框架系列(8)--持续集成实践
持续集成实践 🔄 持续集成(Continuous Integration,简称CI)是现代前端开发流程中的重要环节,它通过自动化构建、测试和部署,帮助团队更快速、更可靠地交付高质量代码。本文将详细介绍前端持续集成的实践方…...
Python核心技术,Django学习基础入门教程(附环境安装包)
文章目录 前言1. 环境准备1.1Python安装1.2选择Python开发环境1.3 创建虚拟环境1.4 安装 Django 2. 创建 Django 项目3. Django项目结构介绍4. 启动开发服务器5. 创建 Django 应用6. 应用结构介绍7. 编写视图函数8. 配置 URL 映射9. 运行项目并访问视图10. 数据库配置与模型创建…...
【Qt-信号与槽】connect函数的用法
🏠个人主页:Yui_ 🍑操作环境:Qt Creator 🚀所属专栏:Qt 文章目录 1.信号和槽的概念1.1 信号的本质1.2 槽的本质1.3 补充说明2. 信号和槽的使用2.1 connect函数介绍2.2 connect函数的简单使用2.2.1 图形化方…...
计算机毕业设计SpringBoot+Vue.js景区民宿预约系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
服务流程设计和服务或端口重定向及其websocket等应用示例
服务流程设计和服务或端口重定向及其websocket等应用示例 目录 服务或端口重定向的服务设计和websocket等应用示例 一、通用请求控制流程 1.1、入口 1.2、所有GET请求首先预检控制单元 1.3、http请求会分别自动307重定向 1.4、所有请求首先执行跨源控制单元 1.5、然后…...
Unity中如何通过Shader与Bounds控制实现视锥体外物体渲染
1. 为什么需要控制视锥体外物体渲染 在Unity的默认渲染流程中,摄像机只会渲染位于视锥体(Frustum)范围内的物体,这个机制被称为视锥体剔除(Frustum Culling)。这个优化手段能显著提升渲染效率,避…...
飞机喷涂废气治理厂家丨一场看不见的“废气治理战”如何打响?
你有没有注意过,当你透过舷窗望向停机坪时,那些静静停靠的飞机,机身光洁如镜,涂装色彩鲜明?一架飞机交付使用,到每隔数年的定期大修,飞机都需要经历复杂的喷涂过程。这层看似简单的“外衣”&…...
用快马AI快速原型:十分钟搭建腾讯云龙虾主题资源监控面板
今天想和大家分享一个有趣的小项目——用InsCode(快马)平台快速搭建腾讯云龙虾主题的资源监控面板原型。这个项目特别适合想要快速验证创意的开发者,整个过程不到十分钟就能完成,而且完全不需要后端支持。 项目构思 这个创意的核心是把云资源管理界面趣味…...
AGV如何实现自主避障
下面按“传感器→建模→算法→安全机制→工程实现”的顺序,把AGV自主避障讲清楚。 一、整体架构概览 AGV要“自己绕开障碍”,至少要做三件事: 1)感知:知道“我在哪”“周围有什么”; 2)规划&…...
DMA固件读卡器源码:pcileech-带读卡器仿真的FPGA
DMA固件读卡器源码,只提供源码 pcileech-带读卡器仿真的fpga最近在折腾硬件安全研究的小伙伴们应该都听说过DMA(直接内存访问)读卡器的骚操作。这玩意儿不经过CPU直接跟内存对话的特性,在取证和漏洞挖掘领域简直是个神器。今天咱们…...
不用Root!教你用ADB命令手动安装Google TTS中文语音包
免Root实现Google TTS中文语音引擎的完整部署指南 你是否遇到过在国产定制Android系统上无法使用Google文字转语音功能的困扰?许多厂商预装的语音引擎发音生硬,而Google TTS的中文语音包又常常因为系统限制无法正常安装。本文将带你绕过这些限制…...
脑网络通信指标——扩散策略的流图指标
和平均首达时间一样,这个指标也是脑网络扩散通信方式的一个指标。这个指标的计算公式也是非常云里雾里,不找原文献推公式看不懂的。 首先给公式: 流图矩阵中的一条边:FG(t)ij = (e^(-tL))ijsj 其中sj = ∑jAij,Aij 就是两个节点之间的结构连接强度,sj就是j节点的强度;…...
【黑金云课堂笔记】第一~二期FPGA知识点总结
知识卡片一:【FPGA 基础篇】开启硬件编程之门FPGA 的本质: FPGA(现场可编程门阵列)并非在运行软件程序,而是在构建电路本身。用户可以通过 Verilog/VHDL 等硬件描述语言,在芯片出厂后随时重新配置其内部逻辑…...
运维系列【仅供参考】:【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧
【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧 【Docker】容器生命周期管理:从优雅停止到高效清理的实战技巧 摘要 1. 为什么需要关注容器生命周期管理? 2. 停止容器的艺术:从温柔到强硬 2.1 优雅停止的正确姿势 2.2 何时该用强制终止 2.3 暂停与恢复的妙用 …...
ai赋能自动化测试:用快马平台让openclaw在win10上实现智能脚本生成与修复
最近在尝试用OpenClaw做自动化测试时,发现传统脚本编写方式效率太低,于是研究了下如何结合AI提升开发体验。在InsCode(快马)平台实践后发现,AI辅助能让测试脚本真正"活"起来。分享几个实用功能点: 智能元素定位的救场能…...
