保证消息发送顺序难点来自于
-
分布式系统下,时钟不一致,没有全局时钟
多个客户端、服务器之间的时钟可能大相径庭
-
多客户端,导致接收顺序不一定
在绝对时序上,若client1先发出msg1,而后client2发出msg2,那么是无法保证msg1一定先于msg2到达
-
服务集群,难以协调消息顺序
在绝对时序上,若client发出msg1,而后client发出msg2,那么由于服务器集群存在,是无法保证msg1一定先被接收处理
-
网络传输与多线程,不保证传输和处理顺序
在绝对时序上,若client发出msg1,而后client发出msg2,可能网络原因导致msg2反而先到,或者由于多线程处理的存在,导致msg2先被处理
单对单聊天,保证发送与接收顺序一致
发送方标记消息顺序
发送方可以根据发送顺序生成标识来区分顺序,该标识可以是
-
生成的单调递增序列号
可以为每个单对单会话生成递增id,唯一的问题可能就是会溢出,但一般也不会溢出,即使溢出处理之后还是能保证顺序性
-
本地时间戳
保证接收展示顺序
在集群中最关键的是保证尽量按照顺序发送消息给接收方,以及配合接收方保证展示顺序
而接收方要根据传输过来数据去保证展示顺序
-
保证发送方与集群机器匹配,集群机器保证前一条展示正确后发送后一条
消息只能一条发完,再发下一条,性能损耗过大
-
基于每个会话单调递增序列号的情况下,集群不做额外处理直接发给接收方,接收方严格按照顺序展示消息
比如接收方收到了1、3,那么消息1可以展示,而消息3在消息2没有接收到之前都不可以展示
-
接收方纠错。若新接收消息顺序早于展示的消息,那么就刷新展示顺序
给用户展示的消息不具有一致性,这可能会引发误解,但若用户能理解,那么也不失为一个好的解决方法
-
接收方每条消息等待一定时间后展示。也就是说如果一条消息在一定时间内没有其他消息顺序在其前,那么就直接展示
时效性较差,并且也无法充分保证顺序
群聊:以服务器接收时间为准
-
发送者对群聊会话hash到特定服务器x,由x进行统一处理
由x推送到接收者更好还是发送者拉取?
个人认为接收者客户端情况可能已经下线了,会产生很多不必要的推送以及维护很多不必要的连接
如果x出现故障呢?
那么为了防止消息丢失,只有在所有接收者收到消息后才确定该条消息消费完成,否则在等待一定时间后发现仍未完成,则会重试其他服务器或者直接提示发送失败,并且在接收端做好幂等处理
但这样做,在存在客户端长期下线的情况下等待周期过长。如果发送者客户端不等待,又容易丢失消息
-
发送方对群聊会话一致性hash到特定集群group ga中,然后由ga首位服务器s统一处理
ga中机器如何按照接收时间标记顺序?
通过比如向量时钟来同步集群中时间,然后通过该时间来标记接收顺序
s什么时候将消息发送或者被拉取给群聊其他成员?
-
等待一定时间,按照时间戳进行排序,进行发送
-
询问ga其他机器是否有更早于已经收到的最晚消息,若没有就推送消息给群聊其他成员
-
等待客户端拉取消息,将最新消息列表发送过去。若原本最先发送给集群的消息由于网络原因晚同步给s,那么s仍然以s接收到的时间为准
也就是如果没有任何客户端主动拉取消息,那么s将根据收到消息的时间戳进行排序,但一旦拉取过了,就以s收到消息的时间为准
如果s出现故障怎么办?
若服务器x发现s心跳异常,则询问其他集群机器是否认为s异常,如果多数认为异常,标记s下线,交由新首位s1服务器处理(此时还是要求接收客户端进行幂等处理)
-