服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - 快醒醒,Cookie + Session 的时代已经过去了

快醒醒,Cookie + Session 的时代已经过去了

2021-09-28 09:18飞天小牛肉小牛肉 编程技术

由于 HTTP 协议是无状态的,完成操作关闭浏览器后,客户端和服务端的连接就断开了,所以我们必须要有一种机制来保证客户端和服务端之间会话的连续性,常见的,就是使用 Cookie + Session(会话) 的方式。

快醒醒,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

快醒醒,Cookie + Session 的时代已经过去了

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

快醒醒,Cookie + Session 的时代已经过去了

明明用户在上一个界面还是登录的,跳到下一个界面就退出登录了,这显然不合理。

分布式集群 Session 共享

当然了,对此的解决方法其实也有很多种,其实就是如何解决 Session 在多个服务器之间的共享问题:

Session Replication

这个是最容易想到的,既然服务器 B 没有服务器 A 存储的 Session,那各个服务器之间同步一下 Session 数据不就完了。

快醒醒,Cookie + Session 的时代已经过去了

这种方案存在的问题也是显而易见的:

  • 同步 Session 数据带来了额外的网络带宽开销。只要 Session 数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
  • 每台Web服务器都要保存所有 Session 数据,如果整个集群的 Session 数据很多(比如很多人同时访问网站的情况),每台服务器用于保存 Session 数据的内存占用会非常严重。

Session Sticky

从名称也能看出来,Sticky,即让负载均衡器能够根据每次的请求的会话标识来进行请求的转发,保证一个会话中的每次请求都能落到同一台服务器上面。

快醒醒,Cookie + Session 的时代已经过去了

存在问题的:

  • 如果某台服务器宕机或者重启了,那么它上面存储的 Session 数据就丢失了,用户就需要重新进行登陆。
  • 负载均衡器变为一个有状态的节点,因为他需要保存 Session 到具体服务器的映射,和之前无状态的节点相比,内存消耗会更大,容灾方面会更麻烦。

Session 数据集中存储

借助外部存储(Redis、MySQL 等),将 Session 数据进行集中存储,然后所有的服务器都从这个外部存储中拿 Session

快醒醒,Cookie + Session 的时代已经过去了

存在的问题也很显然:

  • 过度依赖外部存储,如果集中存储 Session 的外部存储机器出问题了,就会直接影响到我们的应用

ThreadLocal

事实上,无论采用何种方案,使用 Session 机制,会使得服务器集群很难扩展,因此,Session 适用于中小型 Web 应用程序。对于大型 Web 应用程序来说,通常需要避免使用 Session 机制。

So,在 Echo 项目中,我们决定摒弃 Session,一个 ThreadLocal 解决所有问题(狗头)!

ThreadLocal 线程本地内存,很好理解,就是每个访问 ThreadLocal 变量的线程都有自己的一个 “本地” 实例副本,每个线程之间互相隔离,互不干涉。

这里我就不详细解释底层原理了,ThreadLocal 适用于如下两种场景:

  • 每个线程需要有自己单独的实例(数据)
  • 实例(数据)需要在多个方法中共享,但不希望被多线程共享

来看如何用 ThreadLocal 实现我们的需求:显示登录信息,在本次请求中持有当前用户数据。

首先我们需要明白的是,ThreadLocal 只跟其归属的线程有关,线程死亡了,那么它对应的 ThreadLocal 中存储的信息也就被清除了(线程死亡前一定要释放掉绑定的用户数据,不然会出现 OOM 问题),也就是说,ThreadLocal 只用于在本次请求中持有数据。

简单来说,我们把用户数据存入 ThreadLocal 里,这样,只要本次请求未处理完,这个线程就一直还在,当前用户数据就一直被持有,当服务器对本次请求做出响应后,这个线程就会被销毁。

那同一个用户发出的两次请求可能被不同的两个线程进行处理,如何使得这个两个线程的 ThreadLocal 持有相同的用户信息呢?

过滤器。

具体来说,我们定义一个过滤器,在每次请求前都对用户进行判断(为了避免每次请求都经过过滤器,可以将登录成功的用户信息暂时存储到 Redis 中),然后将已经登录成功的用户信息存到 ThreadLocal 里,从而使得该线程在本次请求中持有该用户信息。

延伸 · 阅读

精彩推荐
  • 编程技术真正聪明的程序员,总有办法不加班

    真正聪明的程序员,总有办法不加班

    工作效率提升了,就可以少加班了,聪明的程序员,总会有一堆可以提升编码效率的工具?当一种工具满足不了工作需求,就去探索新的,今天纬小创就给...

    今日头条12482021-03-04
  • 编程技术从Context源码实现谈React性能优化

    从Context源码实现谈React性能优化

    这篇文章主要介绍Context的实现原理,源码层面掌握React组件的render时机,从而写出高性能的React组件,源码层面了解shouldComponentUpdate、React.memo、PureComponen...

    魔术师卡颂5312020-12-20
  • 编程技术Delphi - Indy idMessage和idSMTP实现邮件的发送

    Delphi - Indy idMessage和idSMTP实现邮件的发送

    这篇文章主要介绍了Delphi - Indy idMessage和idSMTP实现邮件的发送,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...

    JJ_JeremyWu6592020-09-22
  • 编程技术简单、好懂的Svelte实现原理

    简单、好懂的Svelte实现原理

    本文会围绕一张流程图和两个Demo讲解,正确的食用方式是用电脑打开本文,跟着流程图、Demo一边看、一边敲、一边学...

    魔术师卡颂4822021-11-10
  • 编程技术2021年值得关注的React PDF 库

    2021年值得关注的React PDF 库

    今天,许多网络应用程序为其用户提供内置的PDF浏览选项。然而,选择一个并不容易,因为它们的功能远远超过显示PDF。在这篇文章中,我将评估5个React的...

    TianTianUp5232021-06-21
  • 编程技术用户态 Tcpdump 如何实现抓到内核网络包的?

    用户态 Tcpdump 如何实现抓到内核网络包的?

    在网络包的发送和接收过程中,绝大部分的工作都是在内核态完成的。那么问题来了,我们常用的运行在用户态的程序 tcpdump 是那如何实现抓到内核态的包...

    开发内功修炼11612021-09-08
  • 编程技术让开发效率倍增的 VS Code 插件

    让开发效率倍增的 VS Code 插件

    今天来分享一些提升开发效率的实用 VS Code 插件!Better Comments 扩展可以帮助我们在代码中创建更人性化的注释,有不同形式和颜色的注释供我们选择。 ...

    前端充电宝7132022-04-21
  • 编程技术AIOps,SRE工程师手中的利器

    AIOps,SRE工程师手中的利器

    AIOps开始成为一种极为重要的站点可靠性工程工具。它能够高效吸纳观察数据、参与数据以及来自第三方工具的数据,判断系统运行状态并保证其处于最佳...

    至顶网5972021-03-08