ThreadLocal与Cookie + Session?
这篇文章主要在做 Echo 社区项目的时候写的,在保持用户登录态的这个需求下,为啥要用 ThreadLocal 存储用户信息,而不是采用常见的 Cookie + Session。
Cookie + Session
由于 HTTP 协议是无状态的,完成操作关闭浏览器后,客户端和服务端的连接就断开了,所以我们必须要有一种机制来保证客户端和服务端之间会话的连续性,常见的,就是使用Cookie + Session(会话) 的方式。
具体来说,当客户端请求服务端的时候,服务端会为此次请求开辟一块内存空间(Session 对象),服务端可以在此存储客户端在该会话期间的一些操作记录(比如用户信息就可以存在 Session 中),同时会生成一个 sessionID ,并通过响应头的Set-Cookie:JSESSIONID=XXXXXXX命令,将 seesionID 存储进客户端的 Cookie 中。
可能会有同学问为啥不直接把数据全部存在 Cookie 中,还整个 Session 出来然后把 sessionID 存在 Cookie 中的?
-
Cookie 长度的限制:首先,最基本的,Cookie 是有长度限制的,这限制了它能存储的数据的长度
-
性能影响:Cookie 确实和 Session 一样可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些 Cookie,那如果 Cookie 中存储的数据比较多的话,这无疑增加了客户端与服务端之间的数据传输量,增加了服务器的压力。
-
安全性:Session 数据其实是属于服务端的数据,而 Cookie 属于客户端,把本应在 Session 中存储的数据放到客户端 Cookie,使得服务端数据延伸到了外部网络及客户端,显然是存在安全性上的问题的。当然我们可以对这些数据做加密,不过从技术来讲物理上不接触才是最安全的。
这样,按照 Cookie + Seesion 的机制,服务端在接到客户端请求的时候,只要去 Cookie 中获取到 sessionID 就能据此拿到 Session 了。Session 存活期间,我们认为客户端一直处于活跃状态(用户处于登录态),一旦 Session 超期过时,那么就可以认为客户端已经停止和服务器进行交互了(用户退出登录)。
如果遇到禁用 Cookie 的情况,一般的做法就是把这个 sessionID 放到 URL 参数中。这也是经常在面试中会被问到的问题。
这种机制在单体应用时代应用非常广泛,但是,随着分布式时代的到来,Session 的缺点也逐渐暴露出来。
举个例子,比如我们有多个服务器,客户端 1 向服务器发送了一个请求,由于负载均衡的存在,该请求被转发给了服务器 A,于是服务器 A 创建并存储了这个 Session

紧接着,客户端 1 又向服务器发送了一个请求,但是这一次请求被负载均衡给了服务器 B,而服务器 B 这时候是没有存储服务器 A 的 Session 的,这就导致 Session 的失效。

明明用户在上一个界面还是登录的,跳到下一个界面就退出登录了,这显然不合理。
分布式集群 Session 共享
当然了,对此的解决方法其实也有很多种,其实就是如何解决 Session 在多个服务器之间的共享问题:
Session Replication
这个是最容易想到的,既然服务器 B 没有服务器 A 存储的 Session,那各个服务器之间同步一下 Session 数据不就完了。

这种方案存在的问题也是显而易见的:
-
同步 Session 数据带来了额外的网络带宽开销。只要 Session 数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
-
每台Web服务器都要保存所有 Session 数据,如果整个集群的 Session 数据很多(比如很多人同时访问网站的情况),每台服务器用于保存 Session 数据的内存占用会非常严重。
Session Sticky
从名称也能看出来,Sticky,即让负载均衡器能够根据每次的请求的会话标识来进行请求的转发,保证一个会话中的每次请求都能落到同一台服务器上面。

存在问题的:
-
如果某台服务器宕机或者重启了,那么它上面存储的 Session 数据就丢失了,用户就需要重新进行登陆。
-
负载均衡器变为一个有状态的节点,因为他需要保存 Session 到具体服务器的映射,和之前无状态的节点相比,内存消耗会更大,容灾方面会更麻烦。
Session 数据集中存储
借助外部存储(Redis、MySQL 等),将 Session 数据进行集中存储,然后所有的服务器都从这个外部存储中拿 Session

存在的问题也很显然:
-
过度依赖外部存储,如果集中存储 Session 的外部存储机器出问题了,就会直接影响到我们的应用
ThreadLocal
事实上,无论采用何种方案,使用 Session 机制,会使得服务器集群很难扩展,因此,Session 适用于中小型 Web 应用程序。对于大型 Web 应用程序来说,通常需要避免使用 Session 机制。
So,在 Echo 项目中,我们决定摒弃 Session,一个 ThreadLocal 解决所有问题(狗头)!
ThreadLocal 线程本地内存,很好理解,就是每个访问 ThreadLocal 变量的线程都有自己的一个 “本地” 实例副本,每个线程之间互相隔离,互不干涉。
这里我就不详细解释底层原理了,ThreadLocal 适用于如下两种场景:
-
每个线程需要有自己单独的实例(数据)
-
实例(数据)需要在多个方法中共享,但不希望被多线程共享
来看如何用 ThreadLocal 实现我们的需求:显示登录信息,在本次请求中持有当前用户数据。
首先我们需要明白的是,ThreadLocal 只跟其归属的线程有关,线程死亡了,那么它对应的 ThreadLocal 中存储的信息也就被清除了(线程死亡前一定要释放掉绑定的用户数据,不然会出现 OOM 问题),也就是说,ThreadLocal 只用于在本次请求中持有数据。
简单来说,我们把用户数据存入 ThreadLocal 里,这样,只要本次请求未处理完,这个线程就一直还在,当前用户数据就一直被持有,当服务器对本次请求做出响应后,这个线程就会被销毁。
那同一个用户发出的两次请求可能被不同的两个线程进行处理,如何使得这个两个线程的 ThreadLocal 持有相同的用户信息呢?
过滤器。
具体来说,我们定义一个过滤器,在每次请求前都对用户进行判断(为了避免每次请求都经过过滤器,可以将登录成功的用户信息暂时存储到 Redis 中),然后将已经登录成功的用户信息存到 ThreadLocal 里,从而使得该线程在本次请求中持有该用户信息。
相关文章:
ThreadLocal与Cookie + Session?
这篇文章主要在做 Echo 社区项目的时候写的,在保持用户登录态的这个需求下,为啥要用 ThreadLocal 存储用户信息,而不是采用常见的 Cookie Session。 Cookie Session 由于 HTTP 协议是无状态的,完成操作关闭浏览器后,…...
freecad手动装插件 add on
python工作台输入 FreeCAD.ConfigGet("UserAppData") 在返回的地址上新建文件夹:Mod #like /home/chen/snap/freecad/common 进入Mod #like /home/chen/snap/freecad/common/Mod git clone 你要的项目 #like git clone https://github.com/looooo/f…...
【算法】二分查找(下)
一、山峰数组的峰顶索引 题目链接:852. 山脉数组的峰顶索引 - 力扣(LeetCode) 题目描述: 给定一个长度为 n 的整数 山脉 数组 arr ,其中的值递增到一个 峰值元素 然后递减。 返回峰值元素的下标。 你必须设计并实现时…...
【动手学深度学习】#6 卷积神经网络
主要参考学习资料: 《动手学深度学习》阿斯顿张 等 著 【动手学深度学习 PyTorch版】哔哩哔哩跟李牧学AI 由于本系列一开始跳过了第一章引言部分,因此系列编号比书本章节编号提前。现改为和书本统一(因为之前自己的原始笔记也是按照书本章节编…...
认识一家公司:瑞芯微(Rockchip Electronics Co., Ltd.)以及旗下的两款芯片RK3288\RK3588
瑞芯微(Rockchip Electronics Co., Ltd.)简介 一、公司概况 瑞芯微电子股份有限公司(简称“瑞芯微”)成立于2001年,总部位于中国福建省福州市,是一家专注于集成电路设计与研发的高新技术企业。公司采用Fa…...
爬虫面试题
总结一下最近面试遇到的笔试题 1、解释Python中的init方法的作用。 在Python中,__init__方法是一种特殊的构造方法,主要用于在创建类的实例时初始化对象。至少接受至少一个参数:self,它是对当前实例的引用,可以通过添加其他参数…...
Netty——零拷贝
文章目录 1. 什么是零拷贝?2. 为什么需要零拷贝?2.1 传统 I/O 的拷贝流程2.2 零拷贝的优化2.2.1 通过 sendfile 系统调用2.2.2 通过 mmap (内存映射) 系统调用 3. Netty 实现零拷贝的方式3.1 文件传输优化:FileRegion 封装3.2 直接内存 (Dire…...
Java制作简单的聊天室(复习)
设计的知识点:几乎包含java基础的全部知识点(java基础语法,java基础进阶:双列集合,io流,多线程,网络编程等) 代码如下 客户端: 服务器采用的时多线程的循环多线程的方式…...
ES 字段的映射定义了字段的类型及其行为
在 Elasticsearch 中,字段的映射定义了字段的类型及其行为。你提供的 content_answer 字段映射如下: Json 深色版本 "content_answer": { "type": "text", "fields": { "keyword": { …...
Android开发点击字符串web链接跳到系统浏览器上
Android开发点击字符串web链接跳到系统浏览器上 直接上代码:用到你就拿去用 public static void performItemUrlClick(View view, String contentUrl) {if (!TextUtils.isEmpty(contentUrl)) {Intent intent new Intent();if (!contentUrl.startsWith("http…...
运维规则之总结(Summary of Operation and Maintenance Rules)
运维规则之总结 在运维领域,经验和流程往往决定了系统的稳定性与可靠性。一个运维人,总结出了以下10条运维规则,涵盖了从基础管理到高级策略的全面内容,旨在帮助运维人员更好地应对各种挑战,确保系统的平稳运行。 1.…...
智能家居赋能宠物经济:未来宠物行业的另一片蓝海
一、引言:宠物经济的范式转移 随着城市化进程的加速,宠物在现代家庭中的地位日益重要,宠物经济蓬勃发展。近年来,智能家居技术的兴起为宠物行业带来了新的变革,从传统的情感消费模式向技术赋能的精细化养宠模式转变。…...
C++Primer学习(13.6 对象移动)
13.6 对象移动 新标准的一个最主要的特性是可以移动而非拷贝对象的能力。如我们在13.1.1节(第440页)中所见,很多情况下都会发生对象拷贝。在其中某些情况下,对象拷贝后就立即被销毁了。在这些情况下,移动而非拷贝对象会大幅度提升性能。 如我…...
RHCE工程师特训指南
RHCE(红帽认证工程师)是Linux领域极具含金量的认证之一,其考试以实操为主,注重系统管理、网络服务配置及自动化运维能力。以下内容可帮助对RHCE考生高效规划学习路径。 一、RHCE认证概述 认证结构 RHCE认证分为两部分ÿ…...
内核、进程和线程---操作系统
操作系统 操作系统位于用户程序和硬件之间,通过系统调用提供接口可以让应用程序去使用硬件,但是硬件资源的管理和安全控制由操作系统负责。 用户空间和内存空间 在计算机系统中,内存可以分为两大区域:内核空间(Ker…...
如何在 Postman 中上传图片并在请求中正确引用?
Postman 是一款常用的 API 测试工具,它不仅可以测试 API 的请求和响应,还支持多种数据格式包括图片。如何在 Postman 中传输图片? Postman 如何上传图片并在请求中使用教程...
平板实现 adb connect 连接的步骤
1. 检查设备的开发者选项 确保平板设备已开启开发者模式,并启用了USB调试。 2. 检查设备和电脑的网络连接 确保平板和电脑连接到同一个Wi-Fi网络,确认设备的 IP 地址是否正确。 通过 ping 命令测试: ping 192.168.3.243. 通过USB线进行初…...
安全+低碳+高效:Acrel-3000助力企业打造未来型电能管理体系-安科瑞黄安南
一 背景 电能因为方便传输、易于转换、便于控制等特性,成为广大企事业单位生产、办公最主要的能量来源。双碳背景下,由于电能清洁、高效、零排放的特点,能源消费侧将逐步以电代煤、以电代油、以电代气,形成以电为中心的能源消费体…...
专注自习室:番茄工作法实践
专注自习室:番茄工作法实践 我需要一个任务管理工具,但在网上找了很多都找不到合适的工具。市面上的大多数产品过于强调任务完成性,给我带来了很强的心理压力,这种压力最终反而降低了我的工作效率。于是我决定自己动手࿰…...
docker save如何迁移镜像更节省空间?
文章目录 方法一:使用docker save命令方法二:直接保存多个镜像到一个tar文件哪个方法更节省磁盘空间?空间效率对比实际测试示例其他优势结论 如何用脚本迁移加载镜像 迁移镜像时候,往往会碰到基础镜像相同的很多镜像需要迁移&…...
LeetCode算法题(Go语言实现)_16
题目 给定一个二进制数组 nums 和一个整数 k,假设最多可以翻转 k 个 0 ,则返回执行操作后 数组中连续 1 的最大个数 。 一、代码实现 func longestOnes(nums []int, k int) int {left, zeroCnt, maxLen : 0, 0, 0for right : 0; right < len(nums); …...
CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案
计算机该如何求解三角函数?或许你的第一印象是采用泰勒展开,或者采用多项式进行逼近。对于前者,来回的迭代计算开销成本很大;对于后者,多项式式逼近在较窄的范围內比较接近,超过一定范围后,就变…...
JVM 面经
1、什么是 JVM? JVM 就是 Java 虚拟机,它是 Java 实现跨平台的基石。程序运行之前,需要先通过编译器将 Java 源代码文件编译成 Java 字节码文件;程序运行时,JVM 会对字节码文件进行逐行解释,翻译成机器码指令&#x…...
SEO(搜索引擎优化)详解
SEO(搜索引擎优化)详解 SEO是Search Engine Optimization的缩写,中文称为"搜索引擎优化"。它是指通过一系列技术和方法,提高网站在搜索引擎自然(非付费)搜索结果中的排名,从而获得更…...
Ubuntu平台下安装Node相关环境
说明:在进行VUE、TS等开发需要用到NodeJS相关环境,不同的项目有时候需要不同的Node版本支撑。本文将详细讲解NVM、Node、Yarn、PM2等环境安装的实施步骤。 测试服务器环境:22.04 LTS。 1. NVM 定义:Node Version Manager&#x…...
deepseek大模型一体机与deepseek的关系
deepseek大模型一体机与deepseek的关系 一、deepseek大模型一体机是什么 DeepSeek大模型一体机是由深度求索(DeepSeek)公司推出的软硬件一体化AI解决方案,旨在为企业提供高效、便捷的大模型部署和应用能力。 二、deepseek大模型一体机与de…...
Windows Server 2025 使用 IIS 搭建 ASP.NET 3.5 网站
开启远程桌面 参考文章Windows server开启远程桌面教程打开服务管理器。ECS 配置安全组,开启 3389Telnet 验证网络联通性 telnet x.x.x.x 338安装 Windows App,登录验证 安装 ASP.NET 3.5 1.参考文章Windows Server 2012安装 .NET Framework 3.5和 Wi…...
高等数学-第七版-上册 选做记录 习题7-2
1. 2....
基于Promise链式调用的多层级请求性能优化
代码优化-循环嵌套关联请求 1. 背景 在实际开发中,我们经常会遇到需要嵌套关联请求的场景,比如: 获取项目列表获取项目详情获取项目进度 2. 问题 在这种场景下,我们可能会遇到以下问题: 串行请求瀑布流ÿ…...
【强化学习】基于深度强化学习的微能源网能量管理与优化策略研究【Python】
目录 主要内容 程序要点 2.1 微能源网系统组成 2.2 强化学习及Q学习算法 部分代码 运行结果 下载链接 主要内容 该程序借助深度 Q 网络(DQN),学习预测负荷、风 / 光可再生能源功率输出及分时电价等环境信息,运用…...
