这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
本文是对于掘金课程的课程笔记,针对课程内容的一些重难点、本人在学习消息队列知识时候进行的简单记录。
一、本堂课的重点内容
- 前世今生
- Kafka
- BMQ
- RocketMQ
二、详细知识点介绍
消息队列重要作用:解耦、削峰、异步、日志处理
前世今生
- TIB
- IBM MQ/WebSphre
- SMQ
- JMS
- AMQP/RabbitMQ
- Kafka(高吞吐)
- RocketMQ(实时场景运用广)
- Pulsar(下一代云原生分布式消息流平台)
Kafka
如何使用Kafka
- 创建集群
- 新增topic
- 编写生产者逻辑
- 编写消费者逻辑
基本概念
- topic:逻辑队列
- cluster:物理集群
- producer:生产者,将业务消息发送到topic
- consumer:消费者,消费topic中的消息
- consumergroup:消费者组
一个集群有多个broker,其中会有一个broker作为controller,作为集群大脑;一个broker中有多个topic,每个topic有多个partition,同样的,每个broker中会有一个topic作为leader,其他则是follower;每个partition有多个replica,leader replica会在isr中选出。
问题:从一条消息的视角,为什么kafka能支撑那么高的吞吐?
producer->broker->consumer
producer
- 采用批量发送,批量发送可以减少IO次数,从而加强发送能力
- 采用数据压缩,减少消息大小,目前支持Snappy,ZSTD等
broker如何存储数据?
broker的消息文件结构
topic->partition->replica->log->logsegment(.log+.index+.timeindex+others)
broker通过顺序写来提高写入效率(末尾添加,减少寻道时间)
如何找到消息?
目标:寻找offset
- 二分找到小于目标offset的最大文件(通过索引找到batch,该batch中可能含有)
- 时间戳索引文件
数据拷贝
传统数据拷贝:
磁盘->read buffer->application buffer->socket buffer->nic buffer->消费者进程(从磁盘空间到内核空间,再带应用空间,再回到内核空间)
broker-零拷贝:使用系统调用,不需要再经过应用空间,降低3次内存拷贝次数
consumer
如何解决partition在consumer group的分配问题?
- 手动分配,哪一个consumer消费哪一个partition完全由业务决定(不能自动容灾,新增机器会有数据中断问题,但是比较快)
- 自动分配,选取一个broker当做coordinator,进行rebalance
kafka的缺点
- 数据复制问题
- 重启
- 替换、扩容、缩容
- 负载不均衡(partition迁走,又有数据复制问题)
问题总结:
- 运维成本高
- 对于复杂不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖page cache
- controller和coordinator和broker在同一进程中,大量IO导致性能下降
BMQ
为了解决kafka的问题产生
简介:兼容kafka协议,存算分离,云原生消息队列
引入分布式存储系统和meta storage system,有点类似读写分离的思想
对于BMQ来说,重启、替换、扩容、缩容都可以在秒级完成
broker
写文件流程:messages->数据校验->buffer->writer thread->storage
如果datanode节点挂了或者其他原因导致我们写文件失败,如何处理?重新找一个可用的节点写入,创建segment,从而保证高可用
读取文件:fetch request->wait->cache->如果hit则return data,否则到storage(open file->seek->read)
- 泳道消息:解决主干泳道流量隔离问题以及泳道资源重复创建问题
- databus:原生SDK配合复杂,使用databus比较便利,支持动态配置
- mirror:无法使用多机房部署来解决跨region读写问题,因此引入mirro,通过最终一致方式,解决跨region读写问题
RocketMQ
一般用在电商业务线,业务峰值时刻
相比kafka,多标签、生产者集群(为了支持事务消息)
存储模型
所有消息存储到commitlog,随后dispatch到consumerQueue,存的是索引
高级特性
- 事务保证,(库存-1与消息队列),最终一致性
- 事务消息(两阶段提交)
- 延迟发送(scheduleMessage延迟服务)
- 消息重试和死信队列(发送到scheduleTopic,如果超过重试错误发送到死信队列)
三、课后个人总结
通过本次课程,我重点掌握了kafka的基本构成,各个组件的结构特点,以及一个完整的消息消费流程,以及内部的一些高级特性,为什么kafka能够完成那么高的吞吐量,也了解了他的一些不足,随后引入的BMQ与RocketMQ各自解决了什么问题,与kafka的不同点、优势在哪里。在学习过程中,也发现各个知识点之间是会相互交汇的,学习消息队列也会有定时任务的课题,在学习定时任务以及分布式架构的时候也会有消息队列的身影,还有都学会了,再系统性地进行理解、实践、分类,才算做好了大项目开发的准备工作。