如何设计一个IM单聊架构( 二 )


key: prefix_session_read_count:{会话Id}:{uid} value: 已读数量
5. 用户资料 
使用mysql按需设计即可,变更保存后将数据同步到redis中使用
三. 架构层级拆分
如何设计一个IM单聊架构

文章插图
如图所示,我们可以将架构大致分为五层,具体说明如下
【如何设计一个IM单聊架构】1. 客户端层
我们IM服务的client肯定是有多个,web/App等,需要封装多种SDK隐藏底层细节,便于接入方接入 。
2. 连接层
即时通讯需要客户端和服务端之间建立一个长链接,一方面维护用户的在线状态,另一方面便于复用连接进行消息的收发 。
而维护连接这个动作,它的独立性很强,不需要与业务逻辑耦合,所以我们把链接层单独拆分出来一个 。
这样在业务逻辑迭代上线时,业务层进行滚动上线也不会导致用户的链接断开 。
连接协议
至于连接协议的选择,有如下几种方式
 
  1.  
    基于tcp链接,自定义传输协议(开发成本高,需要有一定条件)
     
  2.  
    websocket
     
  3.  
    http chunk (不建议使用,http工作在7层上,且只能服务端单向的向客户端传输数据,心跳连接不好维护)
     
 
这里推荐优先使用四层的协议来进行长链接的维护 。
 
因为长链接集群的前方要做负载均衡,使用七层的协议,客户端要先和负载均衡机器建立链接,然后负载均衡机器再和业务层集群交互 。
这样在连接数很大的时候,负载均衡的机器容易成为瓶颈 。四层的负载均衡可以直接通过修改目标机器ip prot的方式来进行转发,不需要client和负载均衡机器建链接
3. 业务层 
业务层可以分为「长链接业务层」和「短链接业务层」
 
具体两者的功能拆分,可根据业务实际情况设计
  •  
    长链接业务层: 负责会话相关的业务逻辑,比如收发消息/拉取会话列表/未读计数push等业务
     
  •  
    短链接业务层: 负责一些临时接口请求,比如用户资料拉取/资料变更等类似业务
     
 
两种业务层都通过调用服务层来进行数据读取和写入等擦欧总
4. 服务层
这层属于微服务,来为上层业务层提供基础服务能力,例如敏感消息过滤/会话列表数据读写/消息的落地和发送等功能 。
5. 数据层
为上层的服务层来提供数据的实际落地写入,可以使用mysql,redis或其他sql/nosql数据库 。
四. 推拉模式选择
那么在消息的发送上,我们应该选用推模式,还是拉模式,抑或是推拉结合呢?
1. 纯推模式
首先,我们假设使用纯推模式,来看会存在什么样的问题
场景1: 新设备登陆初始化
用户新登陆一台设备的时候,如果消息记录全都是空的,体验会很不好 。
那么就需要服务端推送全量的消息记录到客户端,历史消息量大的时候,非常浪费服务端资源和带宽 。
场景2: 设备间切换
如何设计一个IM单聊架构

文章插图
 
tips:设备A和B都非第一次登陆
 
如图所示,流程如下
 
  1.  
    用户1在设备A上登陆,收到了用户2的消息1和2,push到了设备A上 。
     
  2.  
    用户1退出了设备A,用户2又给他发送了消息3和4
     
  3.  
    用户1登陆了设备B,服务端push消息3和4到了设备B
     
 
但是此时,设备B缺少了消息1和2,用户再登陆回设备A的话又缺少了消息3和4,这也就产生了「消息空洞」
2. 纯拉模式
然后,我们假设使用纯拉模式,来看会存在哪些问题
场景1: 收新消息
纯拉模式下,客户端需要和服务端进行一个长轮询,来定时检查是否存在新消息,并进行消息拉取 。
这样轮询的时间间隔需要很难确定合适,间隔大了消息不实时,间隔小了无疑对服务器会产生很大的压力,无法支撑大量的在线用户进行聊天 。
总结
由于推拉模式分别适用于业务中的不同场景需要,所以我们要使用推拉结合的方式来做 。


推荐阅读