什么是消息队列?
消息队列MQ是保存消息的一个容器,本质是一个队列,这个队列需要支持高吞吐、高并发和高可用
消息队列诞生于1985,服务于金融机构和新闻机构,简称为TIB。后来IBM和微软逐渐开始加入研发属于自己的消息队列。后来AMQP将消息队列技术推广了开来。
常用消息队列:
Kafka:分布式、分区的、多副本的日志提交服务,在高吞吐场景下发挥出色
RocketMQ:出自阿里之手,低延迟、强一致、高性能,在实时场景中运用较广
Pulsar:开源的下一代云原生分布式消息流平台,采用存算分离架构设计,腾讯出资并在使用,
BMQ:和Pulsar蕾西,存算分离,初期定位是承接高吞吐离线业务场景,逐渐替换掉Kafka集群
Kafka
使用场景
一般用于离线业务场景,比如日志信息、Metrics数据和用户行为分析。
基本概念和结构
创建集群->新建Topic->编写生产者逻辑->编写消费者逻辑
一些基本概念
Topic:逻辑队列,不同的业务场景可以创建不同的Topic
Cluster:物理集群,每个集群可以创建不同的Topic
Producer:生产者,负责将业务消息发送到Topic中
Consumer:消费者,负责消费Topic中的消息
ConsumerGroup:消费者组,不同的消费者组进度互不干涉
在一个topic内部,有多个partition,用于存储消息,每一个partition可以存储多个消息,每一个消息有一个 OFFSET,OFFSET是消息在partition内的相对位置信息,可以理解为唯一的ID
每一个partition中有多个replica(副本),这些副本有着不同的角色,分别是leader和Follower,Leader负责对外进行写入和读出,Follower会尽量保持自身存储内容和Leader一致。如果Leader发现有Follow和自身存储的信息差别太大(比如下图中的replica3),则会将replica踢出ISR。那么ISR有什么用呢,当Leader发生了宕机,则会从ISR中选择Follower成为新的Leader,这就是Kafka高可用的地方
Kafka架构
Kafka中Zookeeper用于存储集群单元信息,包括分区信息
而broker是消息的中介,生产者producer往broker里面指定的topic中写消息,消费者consumer从broker里面拉取指定topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站。
从一条消息分析Kafka流程
producer在向broker发送消息的时候,会进行批量发送,而不是逐条发送,而且会通过Snappy,Gzip等压缩算法对消息进行压缩,从而减少带宽的压力。
在讨论Broker如何将消息回存到本地磁盘之前(也就是Consumer消费的过程),我们先看看Broker消息文件结构。
副本replica最终会以log的形式写入到磁盘中
Broker如何找到已经存入的文件
可以通过时间戳索引,也可以通过OFFSET寻找
待补充
数据拷贝
传统的数据拷贝
这期间使用了十分多的Buffer之间的拷贝,使得开销十分大
使用了零拷贝之后,内核态直接从磁盘读出数据后,直接送到网卡缓冲区NIC Buffer,这大大降低了开销
Consumer-消息接收端
每个消费者组都需要拉取全部partition数据,那么哪个Consumer负责拉取哪个partition数据呢?最简单的是手动拉取的,在启动的时候分配任务,哪个Consumer负责拉取哪几个partition。但是万一其中一个Consumer宕机,就会导致无法拉取到完全的partition。
另外还可以使用自动分配方式,也就是对于每一个消费者组,都会选择一个Broker作为一个协调者Coordinator,这个协调者负责分配各个消费者获取partition的任务,这使得可以动态调整各个Consumer的任务。这又称为Consumer Rebalance。
Kafka的缺点
- 运维成本高
- 对于负载不均衡场景,解决方案负责
- 没有自己的缓存,完全依赖Page Cache
- Controller和Coordinator以及Broker在同一进程内,大量IO会导致其性能下降