02 | 消息收发架构:为你的App,加上实时通信功能
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
消息收发架构是实现实时通信功能的关键技术模块,为各种业务系统提供实时交互能力。随着移动网络的快速发展和资费的下降,即时消息技术被广泛应用于各种业务系统中,以提升用户实时互动的能力。在为原有业务系统增加实时消息模块时,需要制定消息内容和未读数的存储方式,并建立高效实时的消息收发通道。消息存储方面,需要设计消息索引和消息内容表,以及联系人列表,用于存储历史消息和最近联系人信息。消息收发通道方面,可以通过IM服务端提供的HTTP协议的API接口或维护TCP长连接来实现消息的发送和接收。整体上,为业务系统增加实时消息功能需要考虑消息存储和消息收发通道两个方面的具体工作。 消息接收通道是实现非P2P模式的IM系统的关键组成部分。通过维护TCP长连接,IM服务端能够实时将消息推送给接收方,同时利用第三方手机操作系统级别的辅助通道,如APNs和GCM通道,来提升消息的实时触达能力。对于消息未读数,它是一个重要的补救措施,可以帮助用户及时感知到新消息的到来。在实现上,需要针对用户维度和会话维度分别进行未读数的计数,并通过IM服务端或本地端进行存储。整体上,消息的发送、存储、接收的生命周期较为完整,但未读数提醒对于用户互动积极性和频率有重要影响。 综上所述,本文从消息系统的实现角度对消息的发送、存储、接收等关键部分进行了讲述。通过发送通道将消息提交到IM服务端,进行消息存储和未读数变更后,通过接收通道将消息实时推送给接收方。最后,留给读者两个思考题,引发进一步讨论。
《即时消息技术剖析与实战》,新⼈⾸单¥59
全部留言(77)
- 最新
- 精选
- 王棕生1. 消息存储中,内容表和索引表如果需要分库处理,应该按什么字段来哈希? 索引表可以和内容表合并成一个表吗? 答: 内容表应该按主键消息ID来哈希做分库分表处理,这样便于定位某一条具体的消息;索引表应该按索引的用户UID来哈希做分库分表处理,这样可以使得当前用户的所有联系人都落在一张表上,减少遍历所有表的麻烦。 索引表可以与内容表合成一张表,好处是显而易见的,能减少拉取历史消息时的数据库IO,不好的地方就是消息内容冗余存储,浪费了空间。 2. 能从索引表里获取到最近联系人所需要的信息,为什么还需要单独的联系人表呢? 答: 如果从索引表中获取一个用户的所有联系人信息(包括最后一条聊天内容和时间)的话,SQL语句中会有分组后取top 1的操作,性能不理想; 另外当前用户与单个联系人之间的未读数需要维护,用联系人表的一个字段来存储,比用索引表方便许多。
作者回复: 👍
2019-08-306112 - hlai最后张图,客户端发消息到服务是通过API, 请问为什么不可以长连接么发过去呢?
作者回复: 这里说一下:消息的收发是可以通过同一个长连通道来实现的,对于普通的聊天场景我甚至更推荐这种架构。对于消息下行扇出压力较大的场景(比如:直播、大型聊天室),考虑到下行通道的压力较大,稳定性方面保障会差一些。这种情况可以将上行独立拆分出来,保证用户发消息不会受到消息下推压力大的影响。
2019-11-2922 - 666想了解一下像微博这类消息系统如果解决大V用户的消息收发的?比如用户给大v点赞、评论或者是私信
作者回复: 点赞、评论这些目前采用的拉取模式,用户打开具体的赞箱和评论箱时才从服务端获取;私信是支持在线推送的,不过为了减少对大V的骚扰,对于未关注人私信没有系统push。
2019-09-136 - 关汉聪老师,您的一个回复中写到:“一般会先写缓存层,缓存层都成功的情况下,如果写有索引失败的情况可以先把失败的索引先写入到一个“失败队列”,由其他线程轮询尝试来写入。一般情况下,缓存层可以抗住db重试期间的数据可用性。” 想问下,缓存一般都是缓解读压力用的,这里是为了缓解写压力,那么: 1. 缓存服务器也是要主从或者集群吗,这样每次写入都保证主从缓存都写入后,在写入DB之前,返回消息发送方,成功的ACK,对吗? 2. 如果缓存成功,索引写入DB失败,在“失败队列”被轮询的过程中,消息发送方接下来的每一条消息,为了保证消息的顺序,是不是都要等待之前失败的消息写入DB后,接下来才能发送给消息接收方? 谢谢老师。
作者回复: 1. 缓存在这里的作用主要是快速响应用户的写入请求,规避同步写db的重操作。缓存服务器是否需要采取主从集群可以根据实际访问量来评估,一般写完主后即可返回,由主负责同步消息到从。 2. 由于消息id和产生时间在写入缓存前就已经生成好,失败队列重试导致的顺序错乱不影响最终消息到达客户端后的重排序。
2019-12-1825 - Dxn索引表为啥要插入两条记录?插入一条也是一样的啊
作者回复: 主要是考虑各自索引维护时的独立性:比如一方删除了消息不影响另一方查看类似的需求。
2019-11-0334 - 小祺消息表和索引表合并后表结构: 发消息用户ID ,收消息用户ID, 消息状态, 消息内容,消息类型,消息产生时间 其中消息状态 0: 正常 1:发消息用户已删除 2: 收消息用户已删除 如果两个用户都删除消息,那这条记录就被delete掉。 既可以满足合并消息,又可以满足单个用户删除消息,请问这样设计是否可行?
作者回复: 处理删除和合并上没问题哈,需要考虑一下分库分表场景下,收发双方查询历史消息应该怎么查呢?
2019-09-0364 - Alber消息存储有什么推荐的数据库吗
作者回复: 这个需要看具体的业务场景吧,比如考虑访问模型,数据量大小,读写的比例等等。在我们自己的场景里mysql和hbase,pika都有在使用。
2019-08-304 - 小袁索引表按照聊天对像的id来哈希,这样和某个对象的聊天记录可以落在一个库中,没问题。 内容表我认为可以按时间分库,实际查询时一般都是从最近的聊天记录开始往前翻,或者看某一天的记录,这样按连续时间段来查询,不会只单独看一条记录吧。 如果按消息id分库那岂不是翻某天的聊天记录可能要查好几个库了吗?
作者回复: 按时间段来查询没问题,但是消息写入的时候就会都落到一个表里,写入压力会有问题,但内容表实现上确实可以在hash完后按时间进行分表。
2019-09-072 - geraltlaush之间面试被问到怎么设计存储群聊的聊天记录,保证聊天记录的有序性,没答出来,老师帮忙解答下
作者回复: 一般来说群聊消息的存储上主要是考虑存储冗余的问题,一个群的消息只需要存一份即可,每条消息id通过自增序号或者“时间维度相关”的发号器来生成,通过这个id排序即可。群聊相关的话题后续课程还会细讲哈
2019-09-022 - 挨踢菜鸟老师,请问websocket如何多实例部署,如何解决实例重启造成连接断开的问题
作者回复: 没太理解到您的意思哈,websocket网关只有是无状态的多实例部署没啥问题的呀;实例重启断开连接是肯定的,需要解决的是断开后客户端需要有重连机制以及如果尽量减少实例重启的概率。
2019-08-3092