[即时通讯] 分布式系统-用户在线状态管理

2020-05-20

分布式系统,用户连接到不同的物理设备,在不同的进程里工作。

独立进程在处理一些用户关系性比较强的业务时(例如用户在线状态),涉及多个进程交互,逻辑要比单服复杂很多。对于较小体量的系统,我们仍然希望寻求一种简单的交互方式。


1. 解耦

分布式系统,每个服务节点可以相互通信,我们希望,节点间尽量解耦,显然 B 图的逻辑更加清晰。

通信解耦


2. 架构

添加 redis 进行数据共享,减少业务节点间的通信。

分布式架构

节点类型 描述
gate 接入服务集群,负责客户端接入和客户端业务协议的路由。
logic 逻辑服务集群,负责客户端业务功能实现。
redis cluster 负责数据(限时)缓存,方便不同类型节点服务共享数据。

gate 写数据,logic 读数据。

用户的实时在线状态被分散保存在多个 gate 服务上。gate 服务将用户在线状态实时同步到 redis 集群。

logic 服务处理群聊时,我们需要获得当前群组所有成员的在线状态,这时候我们不需要遍历 gate 服务进行获取,我们只需要通过 redis 获取即可。


3. Session

逻辑服务节点直接从 redis 上获取数据,可谓简单粗暴,这样 redis 负载可能会成为一个新的问题。特别是活跃的大群,每次发送消息,都要从 redis 取出大量的用户在线状态数据,这不是一个明智做法。

我们可以把进程内存利用起来 —— Session。这样虽然不能保证 Session 里的数据与 redis 同步,也一定程度上减轻了 redis 的负载。

可以根据实际系统负载,设置 Session 的有效时间。

为了增强 Session 数据一致性,这样要求上游服务路由过来的同一个用户请求,应该尽可能落在同一个节点进程上处理。


那些原来离线,后面上线的用户,没有实时发送的消息,将被保存为离线消息,并通过其它策略定时对离线消息进行推送。

缓存


4. 小结

在现实生活里,无论多牛X的系统,也无法保证服务端与客户端的用户在线状态强一致。因为网络是有延迟的,例如用户在坐地铁,地铁过隧道,没有任何网络信号了,这种场景,其实用户已经断网了,服务端无法马上感知到用户掉线。所以一般的应用都是推拉结合,即便服务推送数据失败,当客户端重新连接上来后能主动拉取到延时的数据。