说到 session,我相信每一个程序员都不陌生,或多或少在项目中使用过。session 这个词,实际上是一个抽象的概念,它不像 Cookie 那样有着明确的定义。当大多数程序员谈论 session 的时候,可能指的是服务端存储数据的 session 对象,例如,用户登陆成功以后把用户信息存储在 session 中,相似于这样的程序nginx
Session["UserName"] = new User(); public class User{ public int UserId {get ;set ;} public string UserName {get ;set;} }
而在计算机中,尤为是网络应用中,session 被定义为“会话”,能够把它看作客户端和服务端的一条通道链接,同一个用户的请求使用同一个 session 会话。在大多数应用中,主要用于用户的识别,通俗来说,服务端能够经过 session 来记录每个用户的状态信息。那咱们就以最经常使用的服务端 session 对象来啰嗦几句程序员
session 是存储在服务端的,这是一个很重要的概念。这意味着它须要占用服务器的内存,而且它须要一种释放的机制来保证服务器内存不会被撑爆(例如 LRU)。redis
在项目初期,为了快速上线,服务器的部署不少状况下只有一台服务器,记录用户的登陆状态广泛使用 session 机制。请不要说这样作不合理,至少在项目初期这种作法是最简单并且最快速的方案。随着项目的不断迭代升级,用户量的不断增长,你会发现单机系统成为了项目的最大性能瓶颈,这个时候多数架构师会选择水平扩展方案。算法
其实说到底,系统性能的提高都围绕着一个“分”字,不管是数据库的分库分表,仍是如今兴起的微服务,始终在围绕着一个领域进行切分
当单机的 session 机制进行水平扩展就面临着必需要要解决的问题:session 的亲和性(粘性)要怎么样去解决?数据库
一个单机系统扩展为一个分布式系统,就会面临着分布式 CAP 理论中 AP 和 CP 的选择,具体能够查看以前的文章:设计模式
谈到分布式 session 的一致性问题,其实主要是要解决用户 session 的亲和性,同一个用户的请求怎么样才能保证到达正确存储 session 信息的服务器呢?服务器
最初的方案是采用 session 复制方案,总体的流程很是简单:假设如今有三台服务器,当一个 session 在其中一台服务器上被建立,则同时把这个 session 复制到其余两台服务器上。这样当用户的请求不管到达哪台服务器,都会有相应的 session 数据。网络
这种方案的优点在于服务器能够任意水平扩展,每一个服务器都保留着全部的 session 信息,当加入一台服务器只须要把全部的 session 信息复制过去便可。可是劣势更加明显session
session 复制的方案如今已经不多有人使用了
当一台服务器扩展为多台服务器,目前最经常使用的方案是在流量的入口添加负载均衡器,大致的部署图是这样的
若是负载均衡器可以利用某种手段来实现 session 的粘性就能实现分布式 session。目前主流的 nginx 能够根据“hash_ip”算法将同一个 IP 的请求固定到某台服务器,这样来自于同一个 ip 的 session 请求老是请求到一样的服务器。
这种方式比 session 同步方式要好不少,每台服务器只存储对应的 session 数据,这大大节省了内存资源,并且服务器之间没有数据同步过程。当有新服务器加入的时候,只须要修改负载均衡器的配置便可,这样很方便就支持了服务器水平扩展。可是,同时也面临着一些不足
如今应用更普遍的分布式 session 技术是把 session 数据完全从业务服务器中剥离,单独存储在其余外部设备中,而这些外部设备能够采用主备或者主从,甚至集群的模式来达到高可用。好比如今最经常使用的方案是把 session 数据存储在 redis 中,虽然从 redis 读写 session 数据须要花费必定的网络耗时,可是对于通常的应用来讲在能够接受范围以内。
这种方案好处是总体架构更加清晰,也更加灵活,应用的服务器总体扩展能力不再用考虑 session 的影响,而 session 的问题被转移到外部设备,一般能够利用内存性 NOSql 来解决性能问题,而这些外部设备通常都会有对应的分布式集群方案,例如 redis,能够利用主从或者哨兵模式甚至集群来提供更大规模的数据支撑能力。
不多有人会说起 Actor 模型,我在以前的文章中介绍过 actor 模型,你们能够去看一下
Actor 模型解决这种用户粘性问题会更加优雅,它天生就自带了对象识别功能,简单来讲,同一个 key 的请求,总能到达正确的 actor 实例,这不是咱们想要的结果吗?并且 actor 模型下不用加锁就能处理并发问题,为何没人用呢?并且采用 acotr 模型就能够利用进程内缓存的形式,比请求局域网 redis 的网络延迟要低不少。
固然若是只是针对用户登陆这个应用场景,session 方案并非惟一的解决方案,能够参考菜菜以前的文章
每一个问题的解决方案有不少,没有完美的方案,只有最适合业务场景的方案。认清技术的本质,才是咱们提升自身技能的捷径。能力有限,技术无限,欢迎批评指正!
更多精彩文章