上篇文章《网络通信之Session的历史血脉》是围绕着理解底层通信来的。因为不管是MQ还是持久层框架中,建立连接后都使用了session来保持或者保存状态数据。
上篇文章和《深入理解MQ生产端的底层通信过程-理解channel》、《接下来一段时间会对大家进行网络通信的魔鬼训练-理解socket》、《网络字节序列-大端序和小端序》、《https引起的跨域问题-COE&casestudy》、《懂得三境界-使用dubbo时请求超过问题》、《一个http请求进来都经过了什么(2021版)》是一个系列。只是用不同的方法在讲底层通信。中间尝试了很多方法和形式,旨在让大家能看下去,深层理解。生怕因为太过枯燥令大家前功尽弃、半途而废。
因为在上一篇里有朋友评论里提到了分布式session。其实分布式session本身是有点脱离我的文章大纲的,但是既然有朋友提出来了,总得把事情讲明白,所以加更了这篇。
分布式session解决了什么问题?
在《稳定性「三十六计」- 无状态化》里我提到:随着容器化、云原生等的流行,DevOps团队也在不断鼓吹「以无状态为荣,以有状态为耻」。因为有状态的服务难以部署、难以扩展。
「状态」其实对用户体验而言是个好东西。保存用户的登录状态;浏览器异常关闭再次打开恢复用户之前的窗口状态;记录用户的偏好状态……于是勤于动脑的软件工程师们就想了:怎么既能拥有无状态化的扩展性,又拥有有状态时的良好用户体验呢?
答案就是分布式session。它更像是一种业务问题的解决方案,而上篇文章所讲的session更合适的描述是一种技术设计抽象。
常用的分布式session解决方案
2007年至今-客户端存储
使用cookie
客户端存储是指直接将信息存储在cookie中。客户端通过http协议和服务器进行cookie交互,通常用来存储一些不敏感信息。它有很明显的缺点:
数据存储在客户端,存在安全隐患
cookie存储大小、类型存在限制
数据存储在cookie中,如果一次请求cookie过大,会给网络增加更大的开销
虽然这种方式有缺点,但是可以通过合理的控制减少副作用。所以我从07年参加工作时就在用这种方法,现在的系统也还在用。JWT就是其中一个典型,它长度小,信息做了加密,一般仍然是存储在cookie中解决单点登录问题。
JWT
JWT:Json Web Token,是基于Json的一个公开规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,他的两大使用场景是:认证和数据交换。
由服务端根据规范生成一个令牌(token),并且发放给客户端。此时客户端请求服务端的时候就可以携带者令牌,以令牌来证明自己的身份信息。
2009年开始我进行互联网领域,有几年和JWT打交道比较多。因为那时候,你想不想做全栈都是全栈,因为前后端不分离,做什么都是一坨。也就是近7年更专注做后端了。那时候记忆比较深的就是cookie里存着一段用很简易的加密做的字符串,用户名信息等关键信息之间用一个下划线隔开,还有一个带有效期的随机数字段,数据库里也存一份。匹配上了就认证成功用户登录状态session有效。
没听说谁家用过-session会话保持(黏滞会话)
会话保持是利用负载均衡的原地址Hash算法实现,负载均衡服务器总是将来源于同一IP的请求分发到同一台服务器上,,也可以根据cookie信息将同一个用户的请求每次都分发到同一台服务器上,不过这时的负载均衡服务器必须工作在HTTP协议层上。这种会话保持也叫黏滞会话(Sticky Sessions)。
这种方案虽然保证了每个用户都能准确的拿到自己的session,而且大量用户访问也不怕,但是这种会话保持不符合系统高可用的需求。这种方案有着致命的缺陷:一旦某台服务器发生宕机,则该服务器上的所有session信息就会不存在,用户请求就会切换到其他服务器,而其他服务器因为没有其对应的session信息导致无法完成相关业务。所以这种方法基本上不会被采纳。
2010年-服务器session复制
原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,以此来保证Session同步。
优点:可容错,各个服务器间session能够实时响应。
缺点:会对网络负荷造成一定压力,如果session量大的话可能会造成网络堵塞,拖慢服务器性能。
我在10年的时候,在公司举行了一个讲座上听人家说过,自己没用过。对这个印象也不深:因为当初那个讲座是leader非要我去的,我坐在第一排,然后……睡着了。因为确实也比较无聊,互联网场景下很少有场景需要这样用。
2011年至今-状态集中存储
2011年,我经过两年的努力,终于在公司里,从一个写业务代码的开发,转成了一个中间件开发者。当时让我一个负责约等于是开发一个zookeeper吧。那时候zookeeper还没有普及,当时很多公司都在开发自己的中间件。
一个下午,我在测试环境发布了一个不成熟的版本,自己的服务挂了。一屋子的人都站了起来。因为我这边挂了,其他人的模块都跑不起来。好像有点跑题了,总之,从那之后,市面上开始出现了各种集中式的状态存储:zookeeper、memcache缓存,其实数据库也是一种。
本质上,对于Java开发者来说,session存储的东西只是从JVM内移到了JVM外。而这种场景下会话保持就相当于是按照hash值进行路由,session复制就相当于集中存储的副本了。也就是说session会话保持和服务器session复制实际上是现代状态集中存储的基础原理,只不过是管理方由业务开发人员转移到中间件管理端,降低了对业务开发人员的开发管理成本。
session使用注意事项
15年时,我们线上发生过一个问题:我正在验证一个线上功能。为了更好的验证,用chrome浏览器登录一个用户,用IE登录另外一个用户。这时候,我刷新了IE页面,结果IE用户突然自己变成了chrome的用户。以多年做技术的敏锐嗅觉,我意识到在组件层面出了问题。于是将这个问题立即上报了技术经理。技术经理听了我的报告,联系了负责CDN的团队。经过他们的排查,CDN的静态缓存策略设置的有问题,他们立即更新了策略解决了问题。(现在想来一身冷汗啊,随随便便就操作生产了?)
上面的教训告诉咱们:使用session要十分注意对请求解析的筛选。