走进消息队列| 青训营笔记

141 阅读3分钟

这是我参与「第三届青训营-后端场」笔记创作活动的第5篇笔记

1.消息队列的基本概念

消息队列(Message Queue,MQ),指保存消息的一个队列,本质是个队列,但是支持高吞吐、高并发,并且高可用。消息队列是一个生产者-消费者模型,可以有效解决应用解耦、异步消息、流量削峰等问题。

2.主流消息队列

  • Kafka Kafka是一个分布式的、分区的、多副本的消息队列,在高吞吐场景下发挥出色。

首先需要创建一个Kafka集群,然后在该集群中创建一个Topic,并且设置好分片数量。接着编写生产者逻辑,初始化一个生产者,再编写消费者逻辑,初始化一个消费者。

  • Cluster:物理集群,每个集群中可以建立多个不同的Topic
  • ZooKeeper:负责存储集群元信息,包括分区分配信息等
  • Producer:生产者,负责将业务消息发送到Topic
  • Consumer:消费者,负责消费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会将指定位置的消息发送给ConsumerKafka在记录消息文件时,同时还创建了偏移量索引文件和时间戳索引文件。有了这两个索引文件,Kafka就可以使用二分法的方式快速定位要请求的消息位置。

尽管上述内容例举了Kafka的诸多优点和性能优化方式,但是由于其本身的结构性质和相关策略,还是存在不少的问题。例如:由于数据复制的问题,运维成本高;对于负载不均衡的场景,解决方案会很复杂;没有自己的缓存,完全依赖Page Cache,灵活性不高;ControllerCoordinator以及Broker在同一进程中,大量的IO会导致性能下降,甚至影响到整个集群。

为了解决这些问题,字节跳动自研的ByteMQ (BMQ)采取了一定的策略进行优化。

  • BMQ 字节
  • RocketMQ 阿里巴巴