如何设计一个IM单聊架构

官方网站 www.itilzj.com 文档资料: wenku.itilzj.com
单聊
在众多的软件中,聊天功能是不可或缺的一个功能模块,或是用户和用户,或是用户和客服,都需要一个能够即时沟通的功能 。
那么一个IM(InstantMessaging)的1对1聊天系统架构和存储应该如何设计呢 。
下面来一步步的分析规划 。
一. 功能点拆分
首先来看一个IM软件模块包括哪些基本功能
 

  •  
    会话列表(需要按照最后一条消息时间的倒序,将会话进行排列)
     
  •  
    聊天内容页(单聊双方的消息按时间顺序依次排列)
     
  •  
    未读消息计数(发送了但是没有读取的对话,需要在头像旁显示未读数字)
     
  •  
    用户头像,昵称(对话的用户资料)
     
 
根据上述功能点拆分后,可以确定下来需要哪些数据存储
 
  •  
    会话列表
     
  •  
    聊天的消息记录
     
  •  
    离线消息列表
     
  •  
    未读消息数据数量
     
  •  
    用户资料
     
二. 数据结构 
实际进行下面几种数据结构存储时,可使用适合自己的场景的组件,例如公司自研的,或熟悉并满足场景要求的 。
以下我拿redis或MySQL来举例子,提供一个思路,实际生产环境还需要具体设计和选型
1. 会话列表
首先,需要为每一个会话创建一个会话Id进行标识 。
再来看,会话列表的特性是新来消息的会话需要排在列表的上面,那么就可以使用一个有序集合SortedSet来存储 。
结构如下:
 
key: prefix_xxx:{uid} value: {会话Id} score: {msgId}
 
key使用当前用户的uid来标识,集合中的每个item则是会话的Id,item的score为会话的最后一条消息的Id,这样根据score自动形成一个有序集合后,就能够满足我们的应用场景了 。
2. 单聊消息列表
场景:聊天的消息列表,是一个按照时间顺序来排列的消息记录,并且需要可以根据offset来进行数据拉取 。
同样可以使用redis的有序集合SortedSet来存储会话的消息列表,通过scan拉取消息
 
key: prefix_session_list:{sessionId} value: {msgId} score: {msgId}
 
也可以创建一个Mysql数据表来持久化存储消息记录
create table t_msg_record_list (`id` bigint not null primary key,`sessionId` bigint not null comment '会话Id',`msgId` bigint not null comment '消息Id',`isRead` tinyint not null default 0 commment '已读状态',`recordStatus` smallint not null default 0 commment '消息状态',`createTime` datetime not null,key `sessionId` (`sessionId`))engine=innodb;
 
根据会话Id分页查询时,就可以这样查询出所有msgId,再根据msgId去拉取msg的详情,组合成列表返回给客户端
SELECT msgId FROM t_msg_record_list WHERE sessionId = 1 AND recordStatus = 0 AND msgId > 1 ORDER BY id desc LIMIT 10;
3. 离线消息
离线消息可以分为「索引」和「消息id列表」两部分
离线消息索引需要记录的是,哪些用户给当前用户发送了离线消息,所以我们可以使用redis的集合Set来记录这些信息
 
key: prefix_xxx:{uid} value: {senderUid}
 
通过scan离线消息索引拿到了sendUid,再去拿这个会话的具体的离线消息id列表
然后,消息id列表使用redis的一个list链表来存储
 
key:prefix_offline_msg:{uid}:{senderUid} value:{msgId}
 
拿到所有msgId以后,去获取msg的实体详情填充即可
4. 未读计数
未读计数= 收到消息总数 - 已读数量
 
所以我们要存储两个已知数据便于计算出未读数量,即消息总数量和已读数量
由于对话存在双方发消息,所以分别维护对话双方的两个数据项,方便计算各自的未读数
接受消息总数量
 
key: prefix_session_count:{会话Id}:{uid} value: 总数量
 
已读数量
 


推荐阅读