乐趣区

关于分布式:解决分布式session问题

session

说到 session,我置信每个程序员都不生疏,或多或少在我的项目中应用过。session 这个词,其实是一个形象的概念,它不像 Cookie 那样有着明确的定义。当大多数程序员议论 session 的时候,可能指的是服务端存储数据的 session 对象,例如,用户登录胜利之后把用户信息存储在 session 中,相似于这样的程序

 Session["UserName"] = new User();

 public class User{public int UserId {get ;set ;}
     public string UserName {get ;set;}

 }

而在计算机中,尤其是网络应用中,session 被定义为“会话”,能够把它看做客户端和服务端的一条通道连贯,同一个用户的申请应用同一个 session 会话。在大多数利用中,次要用于用户的辨认,艰深来讲,服务端能够通过 session 来记录每一个用户的状态信息。那咱们就以最罕用的服务端 session 对象来啰嗦几句

单机 session

session 是存储在服务端的,这是一个很重要的概念。这意味着它须要占用服务器的内存,并且它须要一种开释的机制来保障服务器内存不会被撑爆(例如 LRU)。

在我的项目初期,为了疾速上线,服务器的部署很多状况下只有一台服务器,记录用户的登录状态广泛应用 session 机制。请不要说这样做不合理,至多在我的项目初期这种做法是最简略而且最疾速的计划。随着我的项目的一直迭代降级,用户量的一直减少,你会发现单机零碎成为了我的项目的最大性能瓶颈,这个时候少数架构师会抉择程度扩大计划。

其实说到底,零碎性能的晋升都围绕着一个“分”字,无论是数据库的分库分表,还是当初衰亡的微服务,始终在围绕着一个畛域进行切分

当单机的 session 机制进行程度扩大就面临着必须要要解决的问题:session 的亲和性(粘性)要怎么样去解决?

分布式 session

一个单机零碎扩大为一个分布式系统,就会面临着分布式 CAP 实践中 AP 和 CP 的抉择,具体能够查看之前的文章:

艰涩难懂的 CAP,是否完全正确?

谈到分布式 session 的一致性问题,其实次要是要解决用户 session 的亲和性,同一个用户的申请怎么样能力保障达到正确存储 session 信息的服务器呢?

session 复制

最后的计划是采纳 session 复制计划,整体的流程非常简单:假如当初有三台服务器,当一个 session 在其中一台服务器上被创立,则同时把这个 session 复制到其余两台服务器上。这样当用户的申请无论达到哪台服务器,都会有相应的 session 数据。

这种计划的劣势在于服务器能够任意程度扩大,每个服务器都保留着所有的 session 信息,当退出一台服务器只须要把所有的 session 信息复制过来即可。然而劣势更加显著

  • 每个服务器上都保留着全副的 session 信息,服务器占用的资源大大增加。
  • session 同步须要占用网络带宽,最重要的是如果采纳的异步复制形式,数据会有短暂性的不统一,可能会导致用户拜访失败。

session 复制的计划当初曾经很少有人应用了

负载平衡计划

当一台服务器扩大为多台服务器,目前最罕用的计划是在流量的入口增加负载均衡器,大体的部署图是这样的

如果负载均衡器可能利用某种伎俩来实现 session 的粘性就能实现分布式 session。目前支流的 nginx 能够依据“hash_ip”算法将同一个 IP 的申请固定到某台服务器,这样来自于同一个 ip 的 session 申请总是申请到同样的服务器。

这种形式比 session 同步形式要好很多,每台服务器只存储对应的 session 数据,这大大节俭了内存资源,而且服务器之间没有数据同步过程。当有新服务器退出的时候,只须要批改负载均衡器的配置即可,这样很不便就反对了服务器程度扩大。然而,同时也面临着一些有余

  • 服务器重启意味着对应的 session 信息失落,这在一些重要的业务场景中是不容许的
  • 服务器的程度扩大须要批改负载均衡器的配置,批改之后可能会导致之前的 session 从新散布,这样会导致一部分用户路由不到正确的 session
session 剥离

当初利用更宽泛的分布式 session 技术是把 session 数据彻底从业务服务器中剥离,独自存储在其余外部设备中,而这些外部设备能够采纳主备或者主从,甚至集群的模式来达到高可用。比方当初最罕用的计划是把 session 数据存储在 redis 中,尽管从 redis 读写 session 数据须要破费肯定的网络耗时,然而对于个别的利用来说在能够承受范畴之内。

这种计划益处是整体架构更加清晰,也更加灵便,利用的服务器整体扩大能力再也不必思考 session 的影响,而 session 的问题被转移到外部设备,通常能够利用内存性 NOSql 来解决性能问题,而这些外部设备个别都会有对应的分布式集群计划,例如 redis,能够利用主从或者哨兵模式甚至集群来提供更大规模的数据撑持能力。

Actor 模型

很少有人会提及 Actor 模型,我在之前的文章中介绍过 actor 模型,大家能够去看一下

分布式高并发下 Actor 模型如此优良

Actor 模型解决这种用户粘性问题会更加优雅,它天生就自带了对象辨认性能,简略来说,同一个 key 的申请,总能达到正确的 actor 实例,这不是咱们想要的后果吗?而且 actor 模型下不必加锁就能解决并发问题,为什么没人用呢?而且采纳 acotr 模型就能够利用过程内缓存的模式,比申请局域网 redis 的网络提早要低很多。

写在最初

当然如果只是针对用户登录这个利用场景,session 计划并不是惟一的解决方案,能够参考菜菜之前的文章

程序员过关斩将 – 更加优雅的 Token 认证形式 JWT

写在最初

每个问题的解决方案有很多,没有完满的计划,只有最适宜业务场景的计划。认清技术的实质,才是咱们进步本身技能的捷径。能力无限,技术有限,欢送批评指正!

更多精彩文章

  • 分布式大并发系列
  • 架构设计系列
  • 趣学算法和数据结构系列
  • 设计模式系列

退出移动版