一、概念
读扩散顾名思义就是把读放大了,增加了读的复杂度,相对的就减少了写的复杂度;每次会话中产生的消息,只需要写一次库就可以,接收端从这个库里拉取消息。对于群消息的场景,能够大大降低消息写入的次数,一条群消息只需要写一次即可;接收端需要对每个会话都拉取一次才能获取全部消息,读被大大的放大了,并产生很多无效的读,因为不是每个会话都有新消息。
写扩散
顾名思义就是把写放大了,增加了写的复杂度,相对的就减少了读的复杂度;每次会话中的消息,会产生多次写;对于群消息的场景,写入会被更加的放大,如果这个群有N个参与者,那每条消息需要额外的写N次,即把消息拆开到人,并分别存储;写扩散,在接收端消息同步逻辑会非常简单,只需要从库里读取一次即可,大大降低了消息所需要读的压力;缺点就是写被放大了。
群消息模型一般使用写扩散模型,也就是说发到群里的一条消息会给群里的每个人都存一份,通过牺牲空间来换取了每个人拉取群消息的效率。
扩展阅读:http://blog.csdn.net/AAA821/article/details/72550767
二、常用协议
XMPP协议简单的来说就是使用XML格式进行发送接收消息处理的协议。
官网:https://xmpp.org/
GTalk是基于XMPP协议实现的。
MQTT协议
是一种基于发布/订阅模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上;最大的优点是以极少的代码和带宽,为连接远程设备提供可靠的消息服务。
MQTT: http://mqtt.org/
FaceBook 的Messager 是基于MQTT实现的。
私有协议通过自己定义协议格式的方式实现,需要考虑的全面的一些,工作量比较大。
微信是使用的私有协议。
protobuf协议
简单,快,小,比使用 xml, json 进行数据交换快许多,由于其灵活性和方便有很多人使用其封装消息结构,实现消息系统。
三、IM系统需要支持的功能
1)用户一对一单聊2)用户群聊
3)用户多个终端消息同步
4)用户消息通知推送
也可以利用消息系统的通道实现一些控制类消息的推送,提示客户端更新数据等。
四、消息系统模型
五、消息系统架构
Client:
LVS/Haproxy:
作为HA层,实现后端系统的高可用。
接入层:
1)MQTT代理:支持发布订阅模式的MQTT消息服务器;通过这个代理服务,接收客户端发送过来的MQTT协议格式的消息,还可以把MQTT协议格式的消息发布给客户端。
2)Nginx: HTTP协议代理服务器,历史消息的获取通过http请求获取。
如果有新的协议格式的消息类型接入,只需要在接入层扩容新的消息代理服务即可。
MQ:队列服务,比如:RabbitMQ队列服务、Kafka队列服务等。
业务层:
1)p_logic:把MQTT协议的数据转化为业务数据,并投递到MQ队列里,然后给客户端返回 ack。先投递到队列里的目的是先接收数据落地到高可用的高性能的系统里,提高系统的性能,(采用了邮箱系统的开源软件Postfix的一些设计思想)
2)s_logic: 消息业务处理服务,解析消息业务数据,比如:入库,群消息拆分,转投等功能。
3)通知服务、APNS服务等都属于消息系统里的组件,可以根据实际需要添加,比如:APNS服务,是实现苹果手机的消息推送服务。
整个业务层借助MQ队列进行消息周转,实现各个组件的见协同工作。
数据层:
1)Redis: 缓存一些临时性的数据。
2)Mysql: 消息存储系统,存储所有的消息。
3)文件存储:消息聊天里支持发送文件,所有的文件存储到这个系统里。
六、消息发送流程
1)客户A发送消息到客户B
讨论:
1、如何保证消息的有效性?
存储消息的时候,存储一个seqID,客户端根据seqID进行排序。
2、客户端存在的一个场景:
在弱网或者无网的情况,查看已经收到本地的消息,无论状态是否同步到服务端成功,消息计数都要清零,不能说用户看了消息,还显示未读状态。如何保证多端消息计数的一致性?
3、消息如何存储?数据库如何设计?
可以根据写扩散模型设计表结构,设计表结构要注意到如何实现分库分表。
待补充。。。。