写点什么

应用的无状态设计

  • 2022 年 7 月 16 日
  • 本文字数:1740 字

    阅读完需:约 6 分钟

应用的无状态设计

谈到无状态,我们首先想到的场景是应用实例无本地数据,这是没问题的,但不够准确。想象一下,即使应用无本地数据,实例进程中的内存数据在实例重启后依然会丢失。


因此,实例是否无状态,不应简单以内存或者本地是否有数据为标准来衡量,而是应该以当实例副本增加时实例间能否真正完全对等来衡量,包括应用实例本地数据、内存数据、外部持久化数据。只有完全对等,才能真正利用好 Kubernetes 的弹性伸缩能力。


例如,在微服务中容器化的网关可以无限扩展,但网关进程内的数据怎么办?这时两个微服务网关的实例就不是完全对等的。我用手机 App 访问应用,第一次通过第一个网关进入,第二次通过第二个网关进入,显然之前的会话信息会丢失。


在应用的无状态化设计中,静态数据是可以放在本地的(如业务逻辑层或数据访问层的本地数据)。而变化的数据,需要存储在数据库和缓存中。


接下来分析微服务网关无状态的问题。微服务网关包含的数据主要是客户请求 Session,所以微服务网关的无状态设计最终转变成了 Session 存储的问题。


在 Web 开发中,服务器跟踪用户信息的技术称为会话技术,会话技术有两种实现。Cookie:将会话的过程数据保存到用户浏览器上。Session:将会话数据保存到服务器端。


Cookie 通过将会话过程的数据保存到用户的浏览器上,使浏览器和服务器可以更好地进行数据交互。我们可以形象地将 Cookie 理解成我们在商场办的会员卡。卡上记录了个人信息、消费额度和积分额度等。以后每次去商场,商场根据会员卡就能很快了解到顾客的信息。


在 Cookie 模式下,当用户通过浏览器访问 Web 服务器时,Web 服务器会向客户发送一些信息,这些信息都保存在 Cookie 中。这样,当浏览器再次访问服务器时,会在请求头中将 Cookie 发送给服务器,Web 服务器端可以分辨出当前请求是由哪个用户发出的,以便服务器对浏览器做出正确的响应。


Cookie 技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据的共享。但如果传递的信息比较多,使用 Cookie 技术会增大服务器端的程序处理难度。这时,可以使用 Session。


形象点说,Session 就像医院发给病人的就医卡。就医卡上只有卡号,没有其他信息,病人去看病时,出示就医卡,医院就可以根据卡号查到病历档案。


当浏览器访问 Web 服务器时,Servlet 容器(还以就医卡举例)会创建一个 Session 对象和 ID 属性。Session 对象相当于病例档案,ID 相当于就医卡号。客户端后续访问服务器时,只要将标识号传递给服务器,服务器就能根据请求判断是哪个客户发的,从而选择与之对应的 Session 对象为其服务。需要注意的是,客户端要接受、记录和发送 Session 对象的 ID,而 Session 是借助 Cookie 技术来传递 ID 属性的。


Session 是服务器端用于验证用户权限的一把钥匙,存于服务器端,在进行数据交互时使用。我们经常遇到的登录失效类问题,就是通过 Session 解决的。Session 是一串具有一定时效性的加密字符串(通常有效期为 7 天),由服务端生成和解析。Session 通常包含的字段有 deviceid、clientType、uid、ts、checksum 等,总之要和业务相关。加密方案通常采用 AES,加密和解析都在服务器端。


Cookie 是保存在本地的数据,可以这样理解:在页面中输入账号,自动弹出密码,这个密码之所以会弹出就是因为本地 Cookie 的原因,包括历史记录等,而之所以有记录,就是因为内容存储在本地的 Cookie 文件中。


Session 和登录用户数有关,有一个用户登录就有一个 Session。如果允许一个用户多端登录,那 Session 会更多。因此 Session 不能在网关上单机存储,需要设置 Session 的分布式。那么,我们可以把 Session 存在什么位置呢?如果存在 API 网关本地,但下次请求从另一个 App 网关进入,那显然需要重新认证。


我们有两种方法可以解决这个问题。

1:将 Session 存在手机 App 本地(存在手机 App 的 SQLite 里)。客户端生成 Session,服务器端解析,做校验。这是 JWT 模式。这种方法的缺点是,客户端每次请求 API 网关时都需要校验 Session 字符串,费流量,网络不好的时候访问会慢一点;生成的东西比较多;如果手机重启了,Session 也就没了。


2:给 API 网关接缓存,把 Session 存在缓存里。这样 App 请求来了以后,网关就可以横向扩展了。从 App 访问任何一个网关,都会有相同 Session 的信息。


同样,对于业务逻辑层而言,我们也可以将静态数据放置于应用实例本地,将动态数据存放在外置的 Redis Cluster 中。


发布于: 刚刚阅读数: 5
用户头像

InfoQ签约作者 2018.11.30 加入

热爱生活,收藏美好,专注技术,持续成长

评论

发布
暂无评论
应用的无状态设计_7月月更_穿过生命散发芬芳_InfoQ写作社区