1、Kafka 使用场景
Kafka 是采用 Scala 语言开发的一个多分区、多副本且基于 ZooKeeper 协调的分布式消息系统。其定位是一个分布式流式处理平台,它以高吞吐、可持久化、可水平扩展、支持流数据处理等多种特性而被广泛使用。
kafka 本质是一个消息队列(MessageQueue,MQ)。消息队列就是存放消息的队列,用于不同服务、进程、线程间的通信。
* 消息队列使用场景
- 异步处理:消息放入队列但不立即处理,快速返回,减少等待,实现并发处理
- 流量控制(削峰):隔离网关和后端服务,消息队列能够顶住访问压力,后端不会崩溃。
- 系统解耦:独立的扩展和修改队列两边的处理过程
- 缓冲:解决生产和消费消息的处理速度不一致的问题
- 高可用:数据持久化到磁盘,同时提供备份(冗余存储)
kafka 主要的功能有
- 消息系统:与传统的消息中间件一样,具备异步通信、流量削峰、系统解耦、冗余存储、缓冲、扩展性、可恢复性等功能。此外,Kafka 还提供了其他消息系统难以实现的消息顺序性和回溯消费的功能
- 存储系统:由于消息持久化功能(持久化到磁盘)和多副本机制,kafka 可以作为长期的数据存储系统来使用
- 流失处理平台:为每个流行的流式处理框架提供可靠的数据来源和完整的流式处理类库。
2、Kafka 架构
一个典型的 Kafka 体系架构包括
- Producer:生产者,发送消息到消息队列,push(队列 -> 消费者)
- Consumer:消费者,从消息队列接收消息,pull(队列 <- 消费者)
- Broker:服务代理节点。
- ZooKeeper 集群:管理 Kafka 集群。
kafka 体系结构
2.1、工作流程
主题 topic:逻辑概念,可以理解为队列。Kafka 中消息以主题分类,每条消息都要指定一个主题,生产者将消息发送到特定的主题(每条消息都要指定一个主题),而消费者负责订阅主题并进行消费。
分区 partition:物理概念,可以理解为日志。主题可以分为多个分区,同一主题在不同分区包含的消息不同。每个分区在存储层面可以看作一个可追加的日志文件,生产者生产的消息追加到分区日志文件的时候会分配一个特定的偏移量 offfset。offset 是消息在分区中的唯一标识,Kafka 通过 offset 保证消息在分区的顺序性。注意:Kafka只能保证分区消息的有序性,而不能保证主题消息的有序性。
Kafka 的消息组织方式实际上是三级结构:主题 - 分区 - 消息。主题下的每条消息只会保存在某一个分区中,而不会在多个分区中被保存多份。
分区的作用主要提供负载均衡的能力,能够实现系统的高伸缩性(水平扩展)。不同的分区能够被放置到不同节点的机器上,而数据的读写操作也都是针对分区这个粒度而进行的,这样每个节点的机器都能独立地执行各自分区的读写请求处理。这样,当性能不足的时候可以通过添加新的节点机器来增加整体系统的吞吐量。
2.2、副本机制
副本 Replica:是指分布式系统对数据和服务提供的一种冗余方式。副本包括数据副本和服务副本。
- 数据副本:在不同的节点上持久化同一份数据,当某一个节点上存储的数据丢失时,可以从副本上读取改数据,这是解决分布式系统数据丢失最有效的手段
- 服务副本:多个节点提供同样的服务,每个节点都有能力接受来自外部的请求并进行响应的处理
使用副本的好处是:
- 提供数据冗余。高可用。节点宕机,系统仍能正常工作。
- 提供高伸缩性。扩展节点数量,支撑跟高的读请求量。如 fastdfs、mongodb。
- 改善数据局部性。将数据放入与用户地理位置相近的地方,降低系统延时。
目前 Kafka 的多副本机制只实现了第一点,通过增加副本数量来提升数据容灾能力,实现故障自动转移。
副本是相对于分区而言的,副本是特定分区的副本。
Kafka 采取的是基于领导者 leader-based 的副本机制 ,副本分成两类领导 leader 副本和追随者 follower 副本。每个分区在创建时选举一个 leader 副本,其余的副本为 follower 副本。副本之间是一主多从的关系,其中 leader 副本负责处理读写请求,follower 副本只负责与 leader 副本的消息同步,不对外提供服务。
各个副本处于不同的 broker 中,当 leader 副本出现故障,Kafka 依托于 ZooKeeper 提供的监控功能实时感知到,从 follower 副本中重新选举新的 leader 对外提供服务。Kafka 通过多副本机制实现了故障的自动转移,当 Kafka 集群中某个 broker 失效仍能保证服务可用。同时,消费者采用 pull 模式从服务端拉取消息,并且保存消费的具体位置 offset,消费者宕机恢复上线时可以根据之前保存的消费者位置重新拉取需要的消息进行消费,这样就不会造成消息丢失。
分区中的所有副本统称为 AR (Assigned Replicas)。所有与 leader 副本保持一定程度同步的副本(包括 leader 副本)组成 ISR(In-Sync Replicas),ISR 集合是 AR 集合中的一个子集合。消息首先发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步,同步期间内 follower 副本相对于 leader 副本而言会有一定程度的滞后(可以通过参数配置)。leader 副本负责维护跟踪 ISR 集合中所有 follower 副本的滞后状态。
2.3、生产者
2.3.1、生产方式
2.3.2、分区策略
分区策略:决定生产者将消息发送到某个分区的算法。
Round-robin
轮询策略,即顺序分配,默认策略,总能保证消息最大限度平均分配到所有分区上。
Randomness
随机策略,随意地将消息放置到任意一个分区上。
Key-ordering
Kafka 允许为每条消息定义消息键,简称 key。key 可以是一个有明确业务含义的字符串,也可以用来表征消息源数据。一旦消息被定义了 key,就可以保证同一个 key 的所有消息都进入到相同的分区里面,由于每个分区下的消息处理都是有顺序的,所以被称为按消息键保序策略。
2.4、消费者
2.4.1、消息队列模型
- 点对点消息模型:1;1,消息一旦被消费,就会从队列中删除,而且只能被下游的一个消费者消费。例如:传统的消息队列。伸缩性差。
- 发布订阅消息模型:1:n,允许同一消息被多个消费者重复消费。每个订阅者必须订阅主题的全部分区。伸缩性差,不灵活。
Kafka 采用消费者组机制,组内的消费者共用一个 group id,对订阅主题的所有分区进行消费,逻辑上消费者组等于订阅者。一个分区只能由组内一个消费者消费,消费者不一定要订阅主题的所有分区。消费者组间彼此独立,能够订阅相同的一组主题。当消息发布主题后,只会被投递给订阅它的每个消费组中的一个消费者。
Kafka 的消费者组机制,同时实现了传统消息系统的两大模型:如果所有实例属于同一个组,那么它实现的就是消息队列模型。如果所有实例分别属于不同的组,那它实现的就是发布订阅模型。
2.4.2、消费方式
Consumer 采用 pull 模式从 Broker 中读取数据,这样可以根据消费者的消费能力匹配消费信息的速率。但是因为消费者从 Broker 主动拉取数据,需要维护一个长轮询,这也造成若 Kafka 没有数据时,消费者可能会陷入循环中,一直返回空数据的情况发生。针对这一点,Kafka 消费者在消费数据是会传入 timeout 参数,当没有数据可供消费时,消费者等待 timeout 后再返回。
2.4.3、分区策略
消费者组订阅主体的分区 partition 交由组内哪个消费者 consumer 消费。
Range
按照主题划分,分区数量 / 组内消费者线程数量,决定每个消费者消费的分区数。
如图所示:topic A | topic B 有 3 个分区,消费者组有 2 个消费者,可能存在分区不均匀的问题。
RoundRobin
将所有分区作为整体进行 hash 排序,解决多消费者分配不均的问题,可能造成消费混乱。
2.5、消息可靠性
- 持久化,保存到本地磁盘
- 高可用,提供冗余服务,副本(冗余数据)
- 一致性,ACK
为保证生产者发送的数据能可靠地发送到指定的主题,主题的每个分区收到生产者发送的数据后,都需要向生产者发送 ACK。当生产者收到 ACK,就会进行下一轮的发送,否则重发数据。确保有 follower 与 leader 同步完成,leader 再发送 ACK。