分布式系统,用户连接到不同的物理设备,在不同的进程里工作。
独立进程在处理一些用户关系性比较强的业务时(例如用户在线状态),涉及多个进程交互,逻辑要比单服复杂很多。对于较小体量的系统,我们仍然希望寻求一种简单的交互方式。
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的系统,也无法保证服务端与客户端的用户在线状态 强一致
。
因为网络是有延迟的,例如用户在坐地铁,地铁过隧道,没有任何网络信号了,这种场景,其实用户已经断网了,服务端无法马上感知到用户掉线。所以一般的应用都是 推拉
结合,即便服务推送数据失败,当客户端重新连接上来后能主动拉取到延时的数据。