Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >消息顺序性,究竟为什么这么难?

消息顺序性,究竟为什么这么难?

作者头像
架构师之路
发布于 2022-09-20 07:45:37
发布于 2022-09-20 07:45:37
5890
举报
文章被收录于专栏:架构师之路架构师之路

很多业务都需要考虑消息投递的顺序性:

(1)单聊消息投递,保证发送方发送顺序与接收方展现顺序一致;

(2)群聊消息投递,保证所有接收方展现顺序一致;

(3)充值支付消息,保证同一个用户发起的请求在服务端执行序列一致;

消息顺序性是分布式系统架构设计中非常难的问题,有什么常见优化实践呢?

折衷一:以客户端或者服务端的时序为准

不管什么情况,都需要一个标尺来衡量时序的先后顺序,可以根据业务场景,以客户端或者服务端的时间为准,例如:

(1)邮件展示顺序,其实是以客户端发送时间为准的;

画外音:发送方只要将邮件协议里的时间调整为1970年或者2970年,就可以在接收方收到邮件后一直“置顶”或者“置底”。

(2)秒杀活动时间判断,肯定得以服务器的时间为准,不可能让客户端修改本地时间,就能够提前秒杀;

折衷二:服务端生成单调递增id作为时序依据

对于严格时序的业务场景,可以利用单点写db的seq/auto_inc_id生成单调递增的id,来保证顺序性。

画外音:这个生成id的单点容易成为瓶颈。

折衷三:假如业务能接受误差不大的趋势递增id

消息发送、帖子发布时间、甚至秒杀时间都没有这么精准时序的要求:

(1)同1s内发布的聊天消息时序乱了,没事;

(2)同1s内发布的帖子排序不对,没事;

(3)用1s内发起的秒杀,由于服务器多台之间时间有误差,落到A服务器的秒杀;成功了,落到B服务器的秒杀还没开始,业务上也是可以接受的(用户感知不到)

所以,大部分业务,长时间趋势递增的时序就能够满足业务需求,非常短时间的时序误差一定程度上能够接受。

于是,可以使用分布式id生成算法来生成id,作为时序依据。

折衷四:利用单点序列化,可以保证多机相同时序

数据为了保证高可用,需要做到进行数据冗余,同一份数据存储在多个地方,怎么保证这些数据的修改消息是一致的呢?

“单点序列化”是可行的:

(1)先在一台机器上序列化操作;

(2)再将操作序列分发到所有的机器,以保证多机的操作序列是一致的,最终数据是一致的;

典型场景一:数据库主从同步

数据库的主从架构,上游分别发起了op1,op2,op3三个操作,主库master来序列化所有的SQL写操作op3,op1,op2,然后把相同的序列发送给从库slave执行,以保证所有数据库数据的一致性,就是利用“单点序列化”这个思路。

典型场景二:GFS中文件的一致性

GFS(Google File System)为了保证文件的可用性,一份文件要存储多份,在多个上游对同一个文件进行写操作时,也是由一个主chunk-server先序列化写操作,再将序列化后的操作发送给其他chunk-server,来保证冗余文件的数据一致性的。

单对单聊天,怎么保证发送顺序与接收顺序一致呢?

单人聊天的需求,发送方A依次发出了msg1,msg2,msg3三个消息给接收方B,这三条消息能否保证显示时序的一致性(发送与显示的顺序一致)?

方案设计思路如下:

(1)如果利用服务器单点序列化时序,可能出现服务端收到消息的时序为msg3,msg1,msg2,就会与发出序列不一致。

(2)业务上不需要全局消息一致,只需要对于同一个发送方A,ta发给B的消息时序一致,常见优化方案,在A往B发出的消息中,加上发送方A本地的一个绝对时序,来表示接收方B的展现时序。

msg1{sender:A, seq:10, receiver:B, msg:content1}

msg2{sender:A, seq:20, receiver:B, msg:content2}

msg3{sender:A, seq:30, receiver:B, msg:content3}

可能存在问题是:如果接收方B先收到msg3,msg3会先展现,后收到msg1和msg2后,会展现在msg3的前面。

群聊消息,怎么保证各接收方收到顺序一致?

群聊消息的需求,N个群友在一个群里聊,怎么保证所有群友收到的消息显示时序一致?

方案设计思路如下:

(1)假设和单聊消息一样,利用发送方的seq来保证时序,因为发送方不单点,seq无法统一生成,可能存在不一致。

(2)于是,可以利用服务器的单点做序列化。

如上图,此时群聊的发送流程为:

(1)sender1发出msg1,sender2发出msg2;

(2)msg1和msg2经过接入集群,服务集群;

(3)service层到底层拿一个唯一seq,来确定接收方展示时序;

(4)service拿到msg2的seq是20,msg1的seq是30;

(5)通过投递服务将消息给多个群友,群友即使接收到msg1和msg2的时间不同,但可以统一按照seq来展现;

这个方法能实现,所有群友的消息展示时序相同。

缺点是,生成全局递增序列号的服务很容易成为系统瓶颈。

还有没有进一步的优化方法呢?

群消息其实也不用保证全局消息序列有序,而只要保证一个群内的消息有序即可,这样的话,“id串行化”就成了一个很好的思路。

这个方案中,service层不再需要去一个统一的后端拿全局seq,而是在service连接池层面做细小的改造,保证一个群的消息落在同一个service上,这个service就可以用本地seq来序列化同一个群的所有消息,保证所有群友看到消息的时序是相同的。

此时利用本地时钟来生成seq就凑效了,是不是很巧妙?

总结

(1)要“有序”,先得有衡量“有序”的标尺,可以是客户端标尺,可以是服务端标尺;

(2)大部分业务能够接受大范围趋势有序,小范围误差;绝对有序的业务,可以借助服务器绝对时序的能力;

(3)单点序列化,是一种常见的保证多机时序统一的方法,典型场景有db主从一致,gfs多文件一致;

(4)单对单聊天,只需保证发出的时序与接收的时序一致,可以利用客户端seq;

(5)群聊,只需保证所有接收方消息时序一致,需要利用服务端seq,方法有两种,一种单点绝对时序,另一种id串行化;

思路比结论更重要,希望大家有收获。

架构师之路-分享可落地的技术文章

相关推荐:

1万属性,100亿数据,每秒10万吞吐,架构如何设计?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构师之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
消息“时序”与“一致性”为何这么难?
分布式系统中,很多业务场景都需要考虑消息投递的时序,例如: (1)单聊消息投递,保证发送方发送顺序与接收方展现顺序一致 (2)群聊消息投递,保证所有接收方展现顺序一致 (3)充值支付消息,保证同一个用
架构师之路
2018/03/01
1.9K0
消息“时序”与“一致性”为何这么难?
Linux 下的进程间通信:使用管道和消息队列
本篇是 Linux 下进程间通信(IPC)系列的第二篇文章。第一篇文章 聚焦于通过共享文件和共享内存段这样的共享存储来进行 IPC。这篇文件的重点将转向管道,它是连接需要通信的进程之间的通道。管道拥有一个写端用于写入字节数据,还有一个读端用于按照先入先出的顺序读入这些字节数据。而这些字节数据可能代表任何东西:数字、员工记录、数字电影等等。
用户8639654
2021/09/23
1.3K0
零基础IM开发入门(四):什么是IM系统的消息时序一致性?
本文引用了沈剑《如何保证IM实时消息的“时序性”与“一致性”?》一文的图片和内容(由于太懒,图没重新画),原文链接在文末。
JackJiang
2020/11/04
1.3K0
零基础IM开发入门(四):什么是IM系统的消息时序一致性?
支持百万人超大群聊的Web端IM架构设计与实践
现在IM群聊产品多种多样,有国民级的微信、QQ,企业级的钉钉、飞书,还有许多公司内部的IM工具,这些都是以客户端为主要载体。而且群聊人数通常都是有限制,微信正常群人数上限是500,QQ2000人,收费能达到3000人,这里固然有产品考量,但技术成本、资源成本也是很大的因素。笔者的业务场景上正好需要一个迭代更新快、轻量级(不依赖客户端)、单群百万群成员的纯H5的IM产品。
JackJiang
2025/03/13
1240
支持百万人超大群聊的Web端IM架构设计与实践
低成本确保消息时序的方法
IM类系统中,都需要考虑消息时序问题,如果后发送的消息先显示,可能严重扰乱聊天消息所要表达的意义。
普通程序员
2019/10/23
1.6K0
低成本确保消息时序的方法
TimeLine模型下确保消息有序不丢
通过《基于TimeLine模型的消息同步机制》一文,我们了解到Timeline模型有非常多的优点,也是钉钉采用的消息同步机制。实际工作中,我们也将该模型应用在了C端用户的消息场景中。实施过程中也遇到了一些问题,积累了一些经验。本文将介绍极端情况丢失消息的问题及解决办法。
普通程序员
2019/10/23
1.2K0
TimeLine模型下确保消息有序不丢
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
JackJiang
2023/06/09
1.3K0
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
ActiveMQ从入门到精通(二)消息的顺序消费JMS Selectors消息的同步 AND 异步 接受MessageP2P or Pub/Sub持久化订阅持久化消息到MySQL与Spring整合 J
接上一篇《ActiveMQ从入门到精通(一)》,本篇主要讨论的话题是:消息的顺序消费、JMS Selectors、消息的同步/异步接受方式、Message、P2P/PubSub、持久化订阅、持久化消息到MySQL以及与Spring整合等知识。
用户2890438
2018/08/21
2.4K1
ActiveMQ从入门到精通(二)消息的顺序消费JMS Selectors消息的同步 AND 异步 接受MessageP2P or Pub/Sub持久化订阅持久化消息到MySQL与Spring整合
J
群消息这么复杂,怎么能做到不丢不重?
【需求缘起】 之前的文章更多的聊了单对单的消息投递: 《微信为什么不丢消息?》 《http如何像tcp一样实时的收消息?》 群聊是多人社交的基本诉求,不管是QQ群,还是微信群,一个群友在群内发了一条消息: (1)在线的群友能第一时间收到消息 (2)离线的群友能在登陆后收到消息 由于“消息风暴扩散系数”的存在(概念详见《QQ状态同步究竟是推还是拉?》),群消息的复杂度要远高于单对单消息。群消息的实时性,可达性,离线消息是今天将要讨论的核心话题。 【常见的群消息流程】 开始讲群消息投递流程之前,先介绍两个群业
架构师之路
2018/03/01
1.6K0
群消息这么复杂,怎么能做到不丢不重?
一个海量在线用户即时通讯系统(IM)的完整设计Plus
《一个海量在线用户即时通讯系统(IM)的完整设计》(以下称《完整设计》)这篇文章发出来之后有不少读者咨询问题,提出意见或建议。主要集中在模块拆分、协议、存储等方面。针对这些问题做个简单说明。
普通程序员
2019/10/23
2.9K1
一个海量在线用户即时通讯系统(IM)的完整设计Plus
群消息已读回执(这个diao),究竟是推还是拉?
微信用于个人社交,产品设计上,在线状态,强制已读回执都有可能暴露个人隐私,故微信并无相关功能。
架构师之路
2018/07/27
1.6K0
群消息已读回执(这个diao),究竟是推还是拉?
IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
上一篇文章《IM群聊消息的已读回执功能该怎么实现?》是说,“很容易想到,是存一份”,被网友们骂了,大家争论的很激烈(见下图)。
JackJiang
2018/08/29
1.7K0
顺序消息队列
局部顺序:一个Topic下只需要满足同一消息key是有序的既可。例如,一个Topic下是内容变更流水,消息key值为内容ID,同一个内容ID下所有的消息是有序的;
黄豆酱
2022/10/05
1.1K0
顺序消息队列
消息可靠性设计,看这一篇就够了
随着直播、视频等应用的兴起,消息场景也丰富了起来,最典型的就是聊天。具体到教育行业,场景更多,比如签到、答题等,这些场景对消息可靠性提了更高的要求,毕竟不能老师点“签到”学生收不到。本文就聊一聊消息可靠性的方案设计。文章较长,欢迎收藏。 1. 背景 1.1 业务背景 这是企鹅辅导的老师正在直播上课。 在线直播课堂是在线教育的核心业务。直播和录播、回放的区别在于,在上课的过程中,老师和学生可以进行实时的互动。 老师可以发鱼饼进行活跃气氛。可以发起签到,用来检查学生的到课情况。可以发答题卡,用来提问学生问题
用户1097444
2022/06/29
6890
消息可靠性设计,看这一篇就够了
IM群聊消息的已读回执功能该怎么实现?
我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知道。
JackJiang
2018/08/29
5K0
融云技术分享:全面揭秘亿级IM消息的可靠投递机制
本文由融云技术团队原创分享,原题“IM 消息同步机制全面解析”,为使文章更好理解,对内容进行了重新归纳和细节修订。
JackJiang
2021/07/26
9220
【RabbitMq 篇五】-要点概念(优先级、顺序性、消息分发、持久化)
本文介绍RabbitMq几个重要的概念。分别是优先级队列、消息顺序性、消息分发、持久化。
胖虎
2019/06/26
4.6K0
图解 | 为嘛有 TCP 粘包和拆包
李东,自称亚健康终结者,尝试使用互联网+的模式拓展自己的业务。在某款新开发的聊天软件琛琛上发布广告。
码哥字节
2021/08/23
1.3K1
图解 | 为嘛有 TCP 粘包和拆包
【原创】开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构
网上有很多关于IM的教程和技术博文,有亿级用户的IM架构,有各种浅谈原创自研IM架构,也有微信技术团队分享的技术文章,有些开发者想根据这些资料自研IM。理想很丰满,现实很骨感,最后做出来的产品很难达到商用标准。事实上,很多架构没有经过海量用户的考验,当然我们也不会评判某种架构的好坏,如果开发者企图根据网上教程做出一个商用的IM,可能有点过于乐观了。本文主要从我个人角度深度剖析100%开源的OpenIM架构。当然,世界上没有最完美的架构,只有最合适的架构,也没有所谓的通用方案,不同的解决方案都有其优缺点,只有最满足业务的系统才是一个好的系统。而且,在有限的人力、物力,综合考虑时间成本,通常需要做出很多权衡。我们OpenIM的设计初衷,充分考虑了中小企业的需求,轻量级部署,同时也支持集群扩展,能支持几万用户,也能轻松扩展到上亿用户,是一个可信赖的开源项目。
OpenIM
2021/07/28
2.3K0
【原创】开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构
[网络坦白局] TCP粘包 数据包:我只是犯了每个数据包都会犯的错 |硬核图解
李东,自称亚健康终结者,尝试使用互联网+的模式拓展自己的业务。在某款新开发的聊天软件琛琛上发布广告。
9号同学
2021/03/30
7870
[网络坦白局] TCP粘包  数据包:我只是犯了每个数据包都会犯的错 |硬核图解
推荐阅读
相关推荐
消息“时序”与“一致性”为何这么难?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档