MQ(消息队列)简述
如今市面上常见的MQ有:
在使用这些MQ之前,首先思考几个问题
1.为什么要使用MQ?
2.不同的MQ有什么优缺点?
针对为什么使用MQ,主要有三个应用场景:削峰、解耦、异步
但是!MQ除了有可观的优点以外,还是有不可忽视的缺点的,一个系统如果引入了MQ,那么会存在以下问题:
1.系统的复杂度提高(需要考虑数据的一致性、准确性、不重复消费、不丢失数据等)
2.系统的可用性降低(硬生生拉个MQ过来,需要考虑MQ挂了应该怎么办,系统崩溃可不好受)
针对这些方面,列出如下表1-1
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比Kafka、RocketMQ低一个级别 | 同ActiveMQ | 10万级,高吞吐 | 同RocketMQ,主要用在数据采集,实时数据计算 |
topic数量对吞吐量的影响 | - | - | 支持几百到几千的topic数量,吞吐量会有小幅度的下降 | 几十到几百,尽量topic数量不要太多,是在需要支撑大规模的场景,可以增加节点 |
时效性 | ms级 | 微s级,延迟最低 | ms级别 | ms级别 |
可用性 | 高,基于从架构实现高可用 | 同ActiveMQ | 非常高,分布式架构 | 非常高,分布式,数据高可靠,少数节点宕机不会导致数据丢失 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢失 | 通过参数调优,可以做到0丢失 | 通过参数调优,可以做到0丢失 |
功能支持 | MQ领域功能极其完备 | 基于Erlang开发,性能好,培训成本高 | MQ功能比较完善,分布式、扩展性好 | 功能比较简单,主要用于实时计算、数据采集领域 |
互联网早期都是用ActiveMQ,可以由于不支持大规模数据吞吐场景,而且社区也不活跃,所以现在使用的很少,后来开始使用RabbitMQ,但是由于Erlang语言给Java工程师去了解其底层造成了困扰,培训成本太高,如今越来越多的公司开始使用RocketMQ,毕竟是alibaba出品,而且交给apache社区进行管理与维护,kafka在大数据领域也是使用非常广泛,用于数据采集、实时计算领域,常与Flink、SparkStreaming配合使用。
中小公司用RabbitMQ、大公司用RocketMQ和Kafka
如何保证MQ 的高可用
RabbitMQ的高可用
rabbitMQ的高可用是基于master - slaves
的架构,虽然rabbitMQ属于非分布式高可用,但是很多分布式集群的高可用都使用的类似架构,那么rabbitMQ的高可用是怎么实现的呢?
RabbitMQ有三种模式:
单机模式、普通集群模式、镜像集群模式
单机模式
一般就是Demo级别的,一般就是本地启动玩玩,真正生产没人使用
普通集群模式(无高可用性)
普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的 queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例),你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。
镜像集群模式
有高可用,每个节点都保存数据及原数据的全量、一个节点挂掉并不会影响数据的完整性,但是对带宽磁盘消耗非常大,也没有扩展性可言,以为就算添加一个节点,也只会保存全量的数据。
Kafka的高可用
kafka在0.8版本以后引入了HA机制,这里涉及到以下概念
- broker 一个broker就是kafka集群的节点
- topic 消息的主题
- Partition 每个topic都可以按照分区器分为多个分区
- replication 每个partition都可以有多个副本
- leader 真正负责读写的消息副本
- follower 只负责从leader拉去数据
- ISR 副本同步机制,kakfa源码中通过一个ISR来维护leader与候选的follower
- HW 高水位,leader与follower的共同最高水位
- LEO 单个replication的最高offset+1
leader负责读写,leader挂掉了,通过ISR机制从follower中重新选举leader
如何保证消息不重复消费(幂等性)
从zookeeper节点中查看TopicAndPartition的offset
[zk: localhost:2181(CONNECTED) 5] ls /brokers/topics/__consumer_offsets/partitions
[44, 45, 46, 47, 48, 49, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]
#自动提交offset就是将数据提交到zk中
Kafka什么情况下会产生数据重复消费?
在kafka中有offset的概念,代表消息的偏移量,consumer默认每隔一段时间都会将offset提交到kafka的,如果消费者在消费完一段数据但是offset没有来得及提交消费者线程挂掉之后,下次消费,之前消费过的数据就会重复消费一次。
一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性。
幂等性,通俗点说,就一个数据,或者一个请求,给你重复来多次,你得确保对应的数据是不会改变的,不能出错。
幂等性具体示例:
-
比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
-
比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
-
比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?
如果没有消费过,你就处理,然后这个 id 写 Redis。
如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
-
比如基于数据库的唯一键来保证重复数据不会重复插入多条。
因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。
Kafka什么情况下会丢失数据
要弄清楚这个问题,我们得先明白几个概念:
producer、kafka-cluster 、consumer
producer --[ack]–> kafka-cluster属于一种rpc远程处理连接机制
1.在ProducerConfig中可以设置ack
= 0 、-1(all) 、1,
2.通过replication.factor
设置每隔分区的副本数量至少为2
3.min.insync.replicas
大于1,要求leader感应到至少1个follower没掉队
4.retries=MAX
消息写入失败的重试次数
kafka-direct消费参考链接
https://github.com/shufang000/SparkStreaming-DirectKafka010/blob/master/pom.xml