kafka | 青训营笔记

74 阅读6分钟

这是我参加「第五届青训营 」伴学笔记创作活动的第 11 天。今天主要学习消息队列以及一个分布式消息处理系统kafka

重点内容

  1. 了解消息队列的基本定义与消息队列的发展历程
  2. 学习kafka的基本概念,架构设计,底层原理及架构缺陷

主要知识点

一、消息队列的基本概念

消息队列(MQ)实质上是一个队列容器,用于保存消息。而在实际应用中,消息队列需要满足高吞吐高并发高可用三个要求。

二、消息队列的发展历程

随着相关技术的完善以及一些协议的出现,消息队列自1985年出现后得到了快速发展,其大致发展过程如下图所示

b1e1b8dd7355aafe74ecc02ed1449ba.jpg

当下,业界内主要使用的消息队列有如下四种:

  • kafka:提供分布式分区多副本的日志提交服务,在高吞吐场景下发挥较为出色

  • RocketMQ:拥有低延迟、强一致、高性能、大容量和灵活的扩展能力,往往在实时场景应用较为广泛

  • Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体,采用了存算分离的架构设计

  • BMQ:类似Pulsar架构,存算分离,在业内初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的kafka集群

本篇笔记主要对kafka的相关内容进行记录,RocketMQ与BMQ留到下一篇笔记中继续学习。

三、kafka

1、使用场景

kafka往往用于离线消息处理,类似服务器的日志信息反馈,分析,处理。同时也适用于处理程序运行的Metrics数据以及一些用户行为,如用户的搜索,点赞,评论,收藏。

2、如何使用kafka

  1. 安装配置kafka
  2. 创建集群
  3. 新增Topic
  4. 编写生产者逻辑
  5. 编写消费者逻辑

3、基本概念

  • Topic:逻辑队列,一个Topic中拥有多个分区(Partition),分区是可以并发处理的
  • Cluster:物理集群,每个集群中可以建立多个不同的Topic
  • Producer:生产者,负责将业务消息发送到Topic中
  • Consumer:消费者,负责消费Topic中的消息
  • ConsumerGroup:消费者组,包含多个消费者,每个消费者的消费进度互不干涉

此外还涉及到Topic内的offset(相对位置),Replica(副本),以及副本分布相关概念

4、kafka基本架构

146e9dae6619d04cc3ebb1fc569a97d.jpg

5、kafka运行的具体流程

这一部分我们从一条消息进入kafka的处理流程对kafka进行分析。一条消息进入kafka处理的流程可简化为: Producer -> Broker -> Consumer,因此接下来会从这三个部分进行分析。

生产者(Producer)

  • 批量发送:为了应对大消息量的场景,采取批量发送机制,通过一次性发送多个消息从而减少I/O次数,加强发送能力。

  • 消息压缩:在消息容量太大,带宽较小,导致发送速度慢的场景下,kafka提供了消息压缩,通过对消息进行压缩处理减小消息的大小

消息存储(Broker)

Broker写入
  • 消息文件结构:kafka的消息结构可以用一张图概括

6ba8ec4b92907a95f82601e6c2258d3.jpg

结合前面介绍的基本概念,一个Topic会有多个Partition,而每个partition都可以通过数据复制产生对应 的副本。在存储过程中,kafka会通过副本生成日志,将日志写入磁盘。而这些日志显然是有时效的,因此根 据存入的有效时间存入不同的日志段(LogSegment)。

  • 磁盘结构:

参考计算机组成原理相关知识,磁盘是通过磁头读写信息的,因此在读写指定信息的过程中,磁头需要经过寻道过程,找到对应磁道的对应扇区后才能进行读写。在这个过程中如果采取随机写等不连续的写磁盘方法,磁头寻道所花费的时间成本较高,因此采取顺序读写的方式进行磁盘存储效果最好,因此kafka采取的顺序写的方式降低时间成本。

Broker读取

基本流程:Consumer通过发送FetchRequest请求消息数据,Broker通过索引取出消息,按照时间窗口和信息大小发送给Consumer。而Broker有两种文件索引方式

  • 偏移量索引:通过二分法寻找小于目标offset的最大文件。

  • 时间戳索引:通过二分法找到小于目标时间戳最大的索引位置。

数据拷贝

不同于传统拷贝方式,kafka拷贝数据的流程不经过用户态空间,而是在读取磁盘后直接将Read Buffer中的数据传输到NIC Buffer,通过NIC Buffer直接交付给消费者进程。这种拷贝方式减少了在不同进程于缓存中进行数据拷贝的次数,从而提高了读取效率。

消费者(Consumer)

分配消息
  • 手动分配:在代码中配置Consumer与Partition的对应关系,即告知某个Consumer应该处理某个Partition。这种方法效率高,但缺点在于容灾能力差,若某个Consumer停止工作,则对应的及之后的Partition无法被处理。

  • 自动分配(Rebalence):在Broker中选取一台作为协调者(Coordinator),自动根据需求将空闲的消费者分配为一组,由这一组Consumer负责处理该部分的Partition。若处理过程中某台Comsumer出现故障,此时Coordinator会将故障的Comsumer踢出小组,同时将分配给故障机的partition均摊给其他组内的Comsumer(均摊策略:优先选择负载最低的Comsumer),同时Coordinator还可以在小组中选取一个Comsumer作为leader(一般是第一台机器),负责确定分配方式。

6、缺陷

kafka的升级,替换,扩缩容流程很繁琐,由于kafka只能单台重启(多台并行重启回到是Topic不可以因此不支持),同时重启后还要经历数据同步与leader回调的步骤,因此在执行升级和扩缩容时会产生很大的时间开销,同时由于kafka缺少负载均衡与缓存手段,因此kafka面临负载不均衡的问题以及依赖外部Cache。总结其缺点如下:

  1. 运维成本高
  2. 负载不均衡,解决方案复杂
  3. 没有自己的缓存,需要依赖外部Cache
  4. 若Controller和Coordinator和Broker在同一个进程中,大量IO会导致性能下降

总结

今天主要学习了消息队列的基本概念和kafka消息处理系统,在后面还将继续学习其他两个消息队列处理架构,同时在课后也会尝试建立kafka集群,在实践中熟悉学到的知识。