分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”
在说到消息中间件的时候,我们通常都会谈到一个特性:消息的顺序消费问题。这个问题看起来很简单:Producer发送消息1, 2, 3。。。 Consumer按1, 2, 3。。。顺序消费。
但实际情况却是:无论RocketMQ,还是Kafka,缺省都不保证消息的严格有序消费!
这个特性看起来很简单,但为什么缺省他们都不保证呢?
“严格的顺序消费”有多么困难
下面就从3个方面来分析一下,对于一个消息中间件来说,”严格的顺序消费”有多么困难,或者说不可能。
发送端
发送端不能异步发送,异步发送在发送失败的情况下,就没办法保证消息顺序。
比如你连续发了1,2,3。 过了一会,返回结果1失败,2, 3成功。你把1再重新发送1遍,这个时候顺序就乱掉了。
存储端
对于存储端,要保证消息顺序,会有以下几个问题:
(1)消息不能分区。也就是1个topic,只能有1个队列。在Kafka中,它叫做partition;在RocketMQ中,它叫做queue。 如果你有多个队列,那同1个topic的消息,会分散到多个分区里面,自然不能保证顺序。
(2)即使只有1个队列的情况下,会有第2个问题。该机器挂了之后,能否切换到其他机器?也就是高可用问题。
比如你当前的机器挂了,上面还有消息没有消费完。此时切换到其他机器,可用性保证了。但消息顺序就乱掉了。
要想保证,一方面要同步复制,不能异步复制;另1方面得保证,切机器之前,挂掉的机器上面,所有消息必须消费完了,不能有残留。很明显,这个很难!!!
接收端
对于接收端,不能并行消费,也即不能开多线程或者多个客户端消费同1个队列。
总结
从上面的分析可以看出,要保证消息的严格有序,有多么困难!
发送端和接收端的问题,还好解决一点,限制异步发送,限制并行消费。但对于存储端,机器挂了之后,切换的问题,就很难解决了。
你切换了,可能消息就会乱;你不切换,那就暂时不可用。这2者之间,就需要权衡了。
业务需要全局有序吗?
通过上面分析可以看出,要保证一个topic内部,消息严格的有序,是很困难的,或者说条件是很苛刻的。
那怎么办呢?我们一定要使出所有力气、用尽所有办法,来保证消息的严格有序吗?
这里就需要从另外一个角度去考虑这个问题:业务角度。正如在下面这篇博客中所说的:
http://www.jianshu.com/p/453c6e7ff81c
实际情况中:
(1)不关注顺序的业务大量存在;
(2) 队列无序不代表消息无序。
第(2)条的意思是说:我们不保证队列的全局有序,但可以保证消息的局部有序。
举个例子:保证来自同1个order id的消息,是有序的!
下面就看一下在Kafka和RocketMQ中,分别是如何对待这个问题的:
Kafka中:发送1条消息的时候,可以指定(topic, partition, key) 3个参数。partiton和key是可选的。
如果你指定了partition,那就是所有消息发往同1个partition,就是有序的。并且在消费端,Kafka保证,1个partition只能被1个consumer消费。
或者你指定key(比如order id),具有同1个key的所有消息,会发往同1个partition。也是有序的。
RocketMQ: RocketMQ在Kafka的基础上,把这个限制更放宽了一步。只指定(topic, key),不指定具体发往哪个队列。也就是说,它更加不希望业务方,非要去要一个全局的严格有序。
关键点:这个放开,其实牵涉到一个更大的问题。就是RocketMQ和Kafka在底层存储上面的重大差异。这个我在上1篇,”拨乱反正“”续篇中,有过介绍。
后面在源码分析序列中,会进一步分析这个问题。
分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”的更多相关文章
- 消息队列之事务消息,RocketMQ 和 Kafka 是如何做的?
每个时代,都不会亏待会学习的人. 大家好,我是 yes. 今天我们来谈一谈消息队列的事务消息,一说起事务相信大家都不陌生,脑海里蹦出来的就是 ACID. 通常我们理解的事务就是为了一些更新操作要么都成 ...
- 分布式消息队列RocketMQ(一)安装与启动
分布式消息队列RocketMQ 一.RocketMQ简介 RocketMQ(火箭MQ) 出自于阿里,后开源给apache成为apache的顶级开源项目之一,顶住了淘宝10年的 双11压力 是电商产品的 ...
- Spring Cloud(7):事件驱动(Stream)分布式缓存(Redis)及消息队列(Kafka)
分布式缓存(Redis)及消息队列(Kafka) 设想一种情况,服务A频繁的调用服务B的数据,但是服务B的数据更新的并不频繁. 实际上,这种情况并不少见,大多数情况,用户的操作更多的是查询.如果我们缓 ...
- 消息队列与Kafka
2019-04-09 关键词: 消息队列.为什么使用消息队列.消息队列的好处.消息队列的意义.Kafka是什么 本篇文章系本人就当前所掌握的知识关于 消息队列 与 kafka 知识点的一些简要介绍,不 ...
- 消息队列之 Kafka
转 https://www.jianshu.com/p/2c4caed49343 消息队列之 Kafka 预流 2018.01.15 16:27* 字数 3533 阅读 1114评论 0喜欢 12 K ...
- 主流消息队列rocketMq,rabbitMq比对使用
首先整理这个文章是因为我正好有机会实战了一下rocketmq,阿里巴巴的一个开源消息中间件.所以就与以往中rabbitmq进行小小的比较一下.这里主线的根据常见面试问题进行整理. 一.消息队列常用的场 ...
- 消息队列之Kafka——从架构技术重新理解Kafka
Apache Kafka® 是 一个分布式流处理平台. 这到底意味着什么呢? 我们知道流处理平台有以下三种特性: 可以让你发布和订阅流式的记录.这一方面与消息队列或者企业消息系统类似. 可以储存流式的 ...
- 01 . 消息队列之(Kafka+ZooKeeper)
消息队列简介 什么是消息队列? 首先,我们来看看什么是消息队列,维基百科里的解释翻译过来如下: 队列提供了一种异步通信协议,这意味着消息的发送者和接受者不需要同时与消息保持联系,发送者发送的消息会存储 ...
- 消息队列之kafka
消息队列之activeMQ 消息队列之RabbitMQ 1.kafka介绍 kafka是由scala语言开发的一个多分区,多副本的并且居于zookeeper协调的分布式的发布-订阅消息系统.具有高吞吐 ...
随机推荐
- 04IP编址(网络层)
帧中type为0x0800,送给ip ip报文结构 TTL 生存时间最大为255,经过三层设备就减1 protocol:协议号 version:4,6 source ip address:源ip编 ...
- 武汉Uber优步司机奖励政策(1月11日~1月17日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 12 垃圾回收GC
1.垃圾回收 1.) 小整数对象池 #提前建立好的 Python 对小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收.在一个 Python 的程序中,所有位于这个范 ...
- Java:String、StringBuffer、StringBuilder
一.String 1. String类是final类,意味着String类不能被继承,它的成员方法都默认为final方法.在早期的JVM版本中,被final修饰的方法会转为内嵌调用来提升执行效率.从J ...
- Redis系列八 使用Jedis
使用Jedis jar操作Redis 1.配置redis.conf文件,修改 2.建java工程,加入 jedis jar包 3.代码示例: package com.ntjr.redis; impor ...
- 「日常训练」Case of Matryoshkas(Codeforces Round #310 Div. 2 C)
题意与分析(CodeForces 556C) 为了将所有\(n\)个娃娃编号递增地串在一起(原先是若干个串,每个串是递增的), 我们有两种操作: 拆出当前串中最大编号的娃娃(且一定是最右边的娃娃). ...
- Qt-网络与通信-TCP版本聊天程序
代码在公司,考不出来,智能用书里自带的例子来写了. 不过这个TCP版本的程序并没有出来书上的效果,具体问题出在哪里还没有找到,运行书里自带的代码也是这样. 另外发现一个问题 Qt5.8.0VS版本对中 ...
- Linux命令应用大词典-第32章 性能监控
32.1 sar:收集.报告或保存系统活动信息 32.2 iostat:报告CPU统计数据和设备.分区输入.输出消息 32.3 iotop:进行I/O监控 32.4 mpstat:报告CPU相关的统计 ...
- mysql新手入门随笔4
40.子查询:出现在其他SQL语句里的SELECT语句 例如:SELECT sname,mark FROM student WHERE mark = (SELECT max(mark) FROM st ...
- 原生js常用方法
原生JavaScript设置cookie值 function setCookie(name, value, Hours) { var d = new Date(); var offset = 8; v ...