这是我参与「第三届青训营-后端场」笔记创作活动的第5篇笔记
1.消息队列的基本概念
消息队列(Message Queue,MQ),指保存消息的一个队列,本质是个队列,但是支持高吞吐、高并发,并且高可用。消息队列是一个生产者-消费者模型,可以有效解决应用解耦、异步消息、流量削峰等问题。
2.主流消息队列
- Kafka
Kafka是一个分布式的、分区的、多副本的消息队列,在高吞吐场景下发挥出色。
首先需要创建一个Kafka集群,然后在该集群中创建一个Topic,并且设置好分片数量。接着编写生产者逻辑,初始化一个生产者,再编写消费者逻辑,初始化一个消费者。
Cluster:物理集群,每个集群中可以建立多个不同的TopicZooKeeper:负责存储集群元信息,包括分区分配信息等Producer:生产者,负责将业务消息发送到TopicConsumer:消费者,负责消费Topic中的消息ConsumerGroup:消费者组,不同组Consumer消费进度互不干涉
kafka的优点
Kafka 实现了零拷贝原理来快速移动数据,避免了内核之间的切换。Kafka 可以将数据记录分批发送,从生产者到文件系统(Kafka 主题日志)到消费者,可以端到端的查看这些批次的数据。
零拷贝的方式在很多优秀的高性能框架中都有应用,其思想就在于有效减少了数据从磁盘到NIC Buffer的拷贝次数。传统数据拷贝方式中要将数据从磁盘读取到NIC Buffer,需要先将磁盘中数据拷贝到内核态的Read Buffer,再拷贝到用户态的Application Buffer,再拷贝到内核态Socket Buffer,最后到NIC Buffer,一共经历了四次拷贝。
批处理能够进行更有效的数据压缩并减少 I/O 延迟,Kafka 采取顺序写入磁盘的方式,避免了随机磁盘寻址的浪费
在该部分,采用了批量发送和数据压缩的方法来提高Kafka的吞吐量。
批量发送就是指生产者将一批消息打包成一个Batch进行发送,这样一次就可以发送多个消息,可以有效减少IO次数,增强发送能力。
但是批量发送会导致一个问题——如果服务器的网络带宽不高,例如带宽只有1MB,如果一个Batch的消息量很大,带宽会不够。由此,提出了数据压缩,通过一些压缩算法,减少要发送的Batch大小。目前Kafka支持的压缩算法有Snappy、Gzip、LZ4、ZSTD。
在该部分,采用了顺序写、消息索引以及零拷贝的方法来提高性能。
考虑到存储磁盘的结构特性和磁头定位方式,Kafka采用了顺序写的方式来记录消息文件,即始终在文件末尾进行添加,不会进行中间插入的操作。
当Consumer发送FetchRequest请求消息数据,Broker会将指定位置的消息发送给Consumer。Kafka在记录消息文件时,同时还创建了偏移量索引文件和时间戳索引文件。有了这两个索引文件,Kafka就可以使用二分法的方式快速定位要请求的消息位置。
尽管上述内容例举了Kafka的诸多优点和性能优化方式,但是由于其本身的结构性质和相关策略,还是存在不少的问题。例如:由于数据复制的问题,运维成本高;对于负载不均衡的场景,解决方案会很复杂;没有自己的缓存,完全依赖Page Cache,灵活性不高;Controller、Coordinator以及Broker在同一进程中,大量的IO会导致性能下降,甚至影响到整个集群。
为了解决这些问题,字节跳动自研的ByteMQ (BMQ)采取了一定的策略进行优化。
- BMQ 字节
- RocketMQ 阿里巴巴