最近工作上看到挺多消息队列的讨论,但之前对这个消息中间件没有太多深入的了解,借着这次机会好好学习一下。
什么是消息队列
消息队列我们一般称它为MQ(Message Queue),含义也非常直观,和我们熟悉的数据结构———FIFO的队列数据结构类似,用于存放我们需要通讯的消息内容。
把消息放到消息队列中的服务,叫做生产者。
把消息从消息队列中取出处理的服务,叫做消费者。
但和队列数据结构不同,消息队列与生产者和消费者服务没有直接联系,它是一个独立的中间件服务,他的特点就是:
- 解耦
- 异步
- 流量削峰
消息队列的解耦主要体现在:
1、不同的服务提供商直和使用者不需要了解对方的具体实现和操作,只需要通过消息队列收发消息即可(如订单和库存系统等)。
2、不同的服务之间不需要同时在线,同时提供服务。
消息队列异步化则体现在:
对于不使用消息队列的系统而言,他需要等待所有需要对应消息的系统返回成功,才能给客户端返回超过,如图所示,最好的情况下需要300ms。
而使用消息队列,则只需要将消息写入消息队列即可返回成功,耗时50ms。消息的可靠性由消息队列来保证,消息的处理有消费者自行决定。
至于流量削峰,则是异步化的延伸。例如各大电商网站,在双十一大促时,订单量激增,如果把这些订单量一次性实时打给下游系统,下游系统可能由于处理不过来而崩溃。
而利用消息队列,可以暂时存储消息,等下游系统处理完后再取消息,不至于将系统弄崩。
同时,结合消息队列,也可以做一些熔断和降级的操作。
消息队列的种类和对比
这里借用了消息队列mq总结的总结图,列举出来常见的消息队列的对比。
Kafka 简单介绍与分析
Kafka是应用最广泛的消息中间件之一
Kafka最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统。它拥有以下几点特性:
- 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒
- 可扩展性:kafka集群支持热扩展
- 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
- 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
- 高并发:支持数千个客户端同时读写
Kafka系统结构
Producer:消息生产者,负责往kafka中放消息
Broker:是Kafka的实例,每个服务器就是一个broker实例(可以有多个),支持水平无限拓展
Topic:消息的主题,一个Broker上可以有多个Topic;数据就按照topic进行分类和存储
Partition:Topic的分区,每个topic可以有多个分区,作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹。
Replica:每个分区都有多个副本Replica,用于做备份;分区的数量不能大于broker的数量,且一个分区的leader和follower一定是在不同机器上
Consumer:消息的消费者
consumer group:消费者组,将多个消费者组成一个消费者组;在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!
Topic 和 Partition
kafka消息订阅的主体是消费者组而不是消费者(一个消费者也是一个消费者组);每条消息只能被消费组里的一个成员消费。
- 顺序性
一个topic可以分为多个partition,每个partition内消息是有序的,但整个topic不一定是有序的。
每个partition类似一个日志文件,每一条消息都会append到partition一个log。
消费到那条信息由offset指示,offset由消费者维护,生产者不感知,但生产者会定期删除日志。
消费者会像kafka提交自己的offset,重启时可以从kafka集群获得offset,继续消费
- 消费者组
消费者组的所有消费实例协调在一起,共同消费订阅主题的所有分区。
kafka会将每个分区均匀分配给组里每个消费者,保证一条消息只被一个消费者组里的一个实例消费
- Rebalance
Rebalance 就是让一个消费者组下所有的消费者实例在协调者组件(zookeeper)的帮助下,完成订阅主题分区的分配,就如何消费订阅主题的所有分区达成共识的过程。
rebalance条件:
1、消费者组成员变化
2、topic分区数发送变化
3、订阅主题数发生变化
- 消息丢失
对于生产者:
Kafka 不丢消息有一定的条件,只对“已提交”的消息(committed message)做有限度的持久化保证。
有限度的保证:假如一条消息保存在 N 个 Kafka Broker 的分片副本上,那么这个前提条件就是这 N 个 Broker 中至少有 1 个存活。
对于消费者:
一般都是获取到消息后,处理失败了,仍提交位移给broker,实际上这条消息丢失了。一般解决办法是处理完成再提交offset