09 | 分布式一致性:让你的消息支持多终端漫游
09 | 分布式一致性:让你的消息支持多终端漫游
讲述:袁武林
时长13:57大小12.77M
如何实现多终端消息漫游
设备维度的在线状态
离线消息存储
离线消息同步的几个关键点
离线消息该怎么存?
多端消息同步机制
离线消息存储超过限额了怎么办?
离线存储写入失败了会怎么样?
消息打包下推和压缩
发送方设备的同步问题
小结
赞 8
提建议
精选留言(37)
- 王棕生2019-09-16老师,对消息的终端漫游,我这边还有一个云消息的实现方案,望点评! 1 所有的消息,全部持久化存储; 2 用户在任意一个终端设备登陆后,通过用户的uid、联系人uid去服务端拉取云消息; 3 拉取云消息的时候,是按每条消息的时间戳倒序拉取,首次拉取可以取当前时间戳。
作者回复: 整体上没啥大问题哈,首次拉取可以不带时间戳,默认服务端就获取最新的N条即可。 另外时间戳是服务端应用服务器生成的么?多服务器间的时钟差异能接受吗?也可以考虑搭建一套全局的“时间相关的序号生成器”来生成消息ID,使用消息ID作为拉取的cursor,这样时间生成上也相对稳定一些。
14 - 王棕生2019-09-16如果用户的离线消息比较多,有没有办法来减少用户上线时离线消息的数据传输量? 答: 用户所有的离线消息对用户来说,并不都是关心和感兴趣的,用户可能只是看了与某个最近联系人的最近的几条消息后,之前的都不想看了,所以这个时候如果将之前的离线消息都拉到本地是非常浪费资源的。通常的做法是: 1 将用户的所有离线消息,按联系人进行分开; 2 用户登录后进入与联系人的聊天窗口时,首先加载与该联系人的最近的10条离线消息; 3 当用户用手滑动手机屏幕的时候,再分页拉取10条。展开
作者回复: 是的,推拉结合是一种不错的折中方式。
共 2 条评论14 - 一步2019-09-17离线消息什么情况下进行存储呢?当用户A给用户B发送一条消息,发现没有用户B的连接信息,这个时候才进行离线消息的存储吗,还是只要有消息发送给B都会进行离线消息的存储,因为这些消息对于用户B的其他设备来说属于离线消息?
作者回复: 出于可靠性考虑,一般来说服务端接收到消息不管接收方是否在线都会先存到离线存储中,同步再进行消息在线推送,如果接收方不在线或者在线推送失败,等下次接收方再次上线时会从这个离线存储中获取消息进行补推。
6 - 分清云淡2019-12-03最后的发送方设备同步的问题,没太明白。怎么确定发送设备呢?服务端还有一份设备消息的关系表么?
作者回复: 是的,对于支持多设备同时登陆的场景,用户上线建立长连时是以uid + 设备id 为维度来记录和连接的映射的,所以发消息时携带设备id,服务端就可以区分出具体是用户的哪个设备发送的,下推时就可以区别处理了。
3 - javaworker2019-09-24有几个问题没想明白,望老师帮解答下,谢谢 1.文中说如果离线消息存储容量超过限制,部分增量消息被淘汰掉了,会导致根据客户端最新版本号获取增量消息失败。 这个问题有些不明白,如果部分增量消息被淘汰,个人觉得也没关系吧,服务端每次把比客户端版本号大的消息都发给客户端就行了啊,怎么会失败呐? 2.文中说的离线消息表中该怎么存?比如A用户和B用户各有两个终端,但都只登陆了一个终端,这时A用户给B发送了一条消息,是按照A的userid存一条消息,按照B的userid也存一条一样的消息,A端上线拉取A的离线,B端上线拉取B的离线,也就是说A的离线消息有自己发出去的,也有别人发给A的消息,统一按照版本号存下来,A上线后都一起会拉走?展开
作者回复: 第一个问题如果容量超限被淘汰掉仍然取大于版本号的消息下推的话可能会导致消息漏推。比如:客户端当前版本号是1,接下来的消息是2,3,4,假如2被淘汰,那么只会下推3和4,导致2漏推。 第二个问题,是的,离线消息按照用户维度来存储,发送方和接收方都会存,因为发送方也可能有多台设备。
共 2 条评论3 - K.Zhou2019-09-16微信不能多端同步消息是因为消息没存在服务端吧?
作者回复: 这个可能是个结果不是个原因,可能微信产品的设计上就是不想支持多终端消息漫游,所以消息不需要长时间存储在服务端。
共 3 条评论3 - Geek_1cc6d12021-04-16离线消息和拉取历史消息有什么区别?2
- 夏目2020-05-30上线时只推送最近的n条消息,等到用户主动刷新是主动拉取2
- YidWang2019-09-16拉去消息量大 主要优化方式:打包压缩或者按需拉取1
- Geek_LeonSZ2021-11-05可以稍微讲一下离线消息是怎么存储的么? 上面讲到"没必要按会话来存,只需要按 UID 来存储即可"。 这个地方可以展开讲讲么? 因为的确是经常会运用到. 可以像第2节课一样, 用一张表来解释下么?
- xinHAOr2021-06-07老师,离线消息是不是可以只保存信令类消息,非信令类消息通过 用时主动拉取 方式获取?
- 冯选刚2021-05-15在最后那里,发送方发消息之后,服务端回复的ack包含版本号和消息id 组成是不是也行。还需要单独发一条版本消息吗,如果单独发版本消息是啥时候发
- 姚佶思2021-04-29在消息列表页面,APP在每次从后台打开到前台,如何保证列表页面中是最新的消息? 1 使用http请求获取所有消息列表数据,在来回切换到消息列表时,会很频繁,客户端会产生卡顿。 2 如果每次进入到消息列表,由服务器push到客户端。客户端长时间不登陆,会接收到大量的消息。 针对这种情况情况改如何设计客户端和服务端的机制?展开
- 璟琛2020-09-22我看评论里面有很多提到推拉结合,按需拉取离线消息的做法,但是当离线设备重新上线的时候一般是在会话列表页,这个时候虽然不用把所有的离线消息都同步下来,但是需要展示每个会话的消息数和最后一条消息吧?这个问题通过按需拉取貌似解决不了?
- 倔强小德普2020-05-21请教两个问题,多设备的情况下,这个版本号是每个账号下面设备的维度记录的吗? 那个离线表模型大致是怎样的?服务端是如何存储每个同一个账号下面多端设备的版本号信息的
- piboye2020-05-07消息还有一个问题比较严重,就是因为并发引起的乱序,导致客户端用大序列号去取消息的时候,低序列号的消息可能还没写入,导致丢消息1
- tm12342020-04-10请问老师 离线存储是不是意味着每条消息会在索引表和离线表中各存一次,也就是说有数据重复呢?可不可以让离线消息直接重用索引表呢?共 1 条评论
- missa2020-03-31离线消息的表怎么设计还是不太明白,它和消息的索引表有什么不同?1
- 小凉子2020-03-31有个疑问想请教老师: 针对离线消息,老师都是提到用户上线是进行服务端下推,然后用户再按需下拉。为什么没有当用户登录上线时,通过http请求携带版本号向服务端获取离线消息,就是说只用拉的方式获取离线消息?
- yangzi2020-03-01老师好,看了您的课程,有个问题:多终端消息同步和离线消息机制该如何搭配使用?这两个的功能类似。感觉离线消息更靠谱一些,因为它有ack,而多终端同步一旦客户端收到的消息不全,比如发送1、2、3,接收端收到1、3,拿3同步消息,同步也就会遗漏消息。
作者回复: 其实这里讲的多终端消息同步就包括离线消息的同步,消1,2,3这种自增序号解决不了丢消息的问题,一种解决方案是在接收端维护起一个链表式结构,每条下推的消息都会携带上一条消息的版本和当前这条消息的版本(版本是用户维度,维护在服务端),接收端需要能够将这些版本都串联起来,否则就需要从断开的位置重新发起同步。