登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
轻量养虾,开箱即用!低 Token + 稳定算力,Gitee & 模力方舟联合出品的 PocketClaw 正式开售!点击了解详情
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
47
Fork
22
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
开发画像分析
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
消息队列中,如何保证消息的顺序性?
待办的
#IAJKPH
陌生人
拥有者
创建于
2024-08-13 10:04
<p style="text-align: start;"><span style="color: inherit;"><strong>问:如何保证消息的顺序性?</strong></span></p><h2 style="text-align: start;"><span style="color: inherit;">面试官心理分析</span></h2><p style="text-align: start;">其实这个也是用 MQ 的时候必问的话题,第一看看你了不了解顺序这个事儿?第二看看你有没有办法保证消息是有顺序的?这是生产系统中常见的问题。</p><h2 style="text-align: start;"><span style="color: inherit;">面试题剖析</span></h2><p style="text-align: start;">我举个例子,我们以前做过一个 mysql <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 同步的系统,压力还是非常大的,日同步数据要达到上亿,就是说数据从一个 mysql 库原封不动地同步到另一个 mysql 库里面去(mysql -> mysql)。常见的一点在于说比如大数据 team,就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。</p><p style="text-align: start;">你在 mysql 里增删改一条数据,对应出来了增删改 3 条 <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 日志,接着这三条 <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 发送到 MQ 里面,再消费出来依次执行,起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你楞是换了顺序给执行成删除、修改、增加,不全错了么。</p><p style="text-align: start;">本来这个数据同步过来,应该最后这个数据被删除了;结果你搞错了这个顺序,最后这个数据保留下来了,数据同步就出错了。</p><p style="text-align: start;">先看看顺序会错乱的俩场景:</p><p style="text-align: justify;">RabbitMQ:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者2先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/53e3f13e-639c-40b5-af6e-65f8733e9528.png" alt="" data-href="" style=""></p><p style="text-align: center;"><br>Kafka:比如说我们建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。消费者从 partition 中取出来数据的时候,也一定是有顺序的。到这里,顺序还是 ok 的,没有错乱。接着,我们在消费者里可能会搞多个线程来并发处理消息。因为如果消费者是单线程消费处理,而处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟只能处理几十条消息,这吞吐量太低了。而多个线程并发跑的话,顺序可能就乱掉了。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/0c187b38-0130-4b55-8fd9-936d5fca8e96.png" alt="" data-href="" style=""></p><h3 style="text-align: start;"><span style="color: inherit;">解决方案</span></h3><h4 style="text-align: start;"><span style="color: inherit;">RabbitMQ</span></h4><p style="text-align: start;">拆分多个 queue,每个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062709572066043.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062709572066043.png" data-href="" style=""></p><h4 style="text-align: start;"><span style="color: inherit;">Kafka</span></h4><p style="text-align: justify;">一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。</p><p style="text-align: justify;">写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/0368b7cf-cd35-4b17-8a08-96868be248ee.png" alt="" data-href="" style=""></p>
<p style="text-align: start;"><span style="color: inherit;"><strong>问:如何保证消息的顺序性?</strong></span></p><h2 style="text-align: start;"><span style="color: inherit;">面试官心理分析</span></h2><p style="text-align: start;">其实这个也是用 MQ 的时候必问的话题,第一看看你了不了解顺序这个事儿?第二看看你有没有办法保证消息是有顺序的?这是生产系统中常见的问题。</p><h2 style="text-align: start;"><span style="color: inherit;">面试题剖析</span></h2><p style="text-align: start;">我举个例子,我们以前做过一个 mysql <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 同步的系统,压力还是非常大的,日同步数据要达到上亿,就是说数据从一个 mysql 库原封不动地同步到另一个 mysql 库里面去(mysql -> mysql)。常见的一点在于说比如大数据 team,就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。</p><p style="text-align: start;">你在 mysql 里增删改一条数据,对应出来了增删改 3 条 <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 日志,接着这三条 <span style="color: rgb(233, 105, 0); background-color: rgb(248, 248, 248);"><code>binlog</code></span> 发送到 MQ 里面,再消费出来依次执行,起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你楞是换了顺序给执行成删除、修改、增加,不全错了么。</p><p style="text-align: start;">本来这个数据同步过来,应该最后这个数据被删除了;结果你搞错了这个顺序,最后这个数据保留下来了,数据同步就出错了。</p><p style="text-align: start;">先看看顺序会错乱的俩场景:</p><p style="text-align: justify;">RabbitMQ:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者2先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/53e3f13e-639c-40b5-af6e-65f8733e9528.png" alt="" data-href="" style=""></p><p style="text-align: center;"><br>Kafka:比如说我们建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。消费者从 partition 中取出来数据的时候,也一定是有顺序的。到这里,顺序还是 ok 的,没有错乱。接着,我们在消费者里可能会搞多个线程来并发处理消息。因为如果消费者是单线程消费处理,而处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟只能处理几十条消息,这吞吐量太低了。而多个线程并发跑的话,顺序可能就乱掉了。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/0c187b38-0130-4b55-8fd9-936d5fca8e96.png" alt="" data-href="" style=""></p><h3 style="text-align: start;"><span style="color: inherit;">解决方案</span></h3><h4 style="text-align: start;"><span style="color: inherit;">RabbitMQ</span></h4><p style="text-align: start;">拆分多个 queue,每个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062709572066043.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062709572066043.png" data-href="" style=""></p><h4 style="text-align: start;"><span style="color: inherit;">Kafka</span></h4><p style="text-align: justify;">一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。</p><p style="text-align: justify;">写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。</p><p style="text-align: center;"><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/0368b7cf-cd35-4b17-8a08-96868be248ee.png" alt="" data-href="" style=""></p>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
Java
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (
-
)
标签 (
-
)
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册