Kafka 分布式消息队列
Kafka 分布式消息队列
Kafka 集群是一个高可用的消息队列。
对于分布式系统,满足 CAP定理 ,只能同时满足以下三项中的两个:
- 一致性(Consistency):对于客户端,访问任意节点都能获得相同的最新数据副本
- 可用性(Availability):服务在正常响应时间内一直可用,能返回结果
- 分区容错性(Partition tolerance):当节点之间网络故障时,能够提供服务
其中,如 Zookeeper 保证 CP (如果刚好是 master 节点网络断开 ,会触发选举,这期间是不可用的),Eureka 保证 AP (微服务查到的信息可能不是最新的)。
而 kafka 保证的是 CA,基于 ISR (In-Sync Replica)的动态复制方案,如果 follower 网络故障,那么将被 leader 从ISR中移除,除非追上数据,不然不能加入集群。
数据传输的事务定义通常有以下三种级别:
-
最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输
-
最少一次 ( at least once): 消息不会被漏发送,最少被传输一次,但也有可能被重复传输
-
精确的一次(exactly once): 不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次
生产者 (KafkaProducer)
发送消息有三种方式
- 发送并忘记( send-and-forget ) :把消息发送给服务器,但井不关心它是否正常到达
- 同步发送 :
send()
方怯发送消息 , 它会返回一个 Futher 对象 ,返回错误或偏移量 - 异步发送 :调用
send()
方怯,需要指定一个回调函数
acks 参数指定了重发的行为
acks | 行为 | 后果 |
---|---|---|
0 | 生产者在成功写入悄息之前不会等待broker响应 | 可能会数据丢失 |
1 | 只要集群的 leader 节点收到消息,生产者就会收到一个来自服务器的成功响应 | 如果 leader 挂掉,可能会数据丢失 |
-1/all | 会等所有的 follower 的副本受到数据后成功响应,请求会被保存在一个叫作炼狱的缓冲区里,直到首领发现所有跟随者副本都复制了消息,晌应才会被返回给客户端 | 保证数据不会丢失 |
序列化器有 Json、Avro、Thrift、protobuf 等多种方案
消费者 (KafkaConsumer)
Kafka 消费者从属于 消费者群组 。一个群组里的消费者订阅的是同一个 主题( Topic ),每个消费者 接收主题一部分 分区 ( Partition )的消息。
消费者数量不能多于消费者数量,多的消费者会闲置。多个消费者群组可以订阅同一个主题,群组独立且分开计算。
分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为 再均衡 ,会造成整个群组一小段时间的不可用 。
提交偏移量有多种方式
-
自动提交:每隔一段时间(默认5s),消费者会自动把从
poll()
方法接收到的最大偏移量提交上去,会数据丢失。 -
提交当前偏移量:使用
commmitASync()
方法提交偏移量,如果发生了再均衡 ,可能会发生重复处理。 -
异步提交:同步提交的方式,可能会阻塞,使用
commmitSync()
方法,可采用回调处理。 -
同步和异步组合提交 : 确保再均衡前的最后一次提交能够提交成功。
-
也可以提交特定的偏移量
还要注意如何优雅地退出循环的问题,以及反序列化。
分区 ( Partition )
Kafka 使用 zookeeper 来维护集群成员的信息,控制器使用 epoch 来避免 脑裂 问题。元数据可以用来分区选首领,偏移量也是元数据。
消费者只能看到已经复制到 ISR 的消息。
Kafka 使用零复制技术向客户端发送消息一一也就是说, Kafka 直接把消息从文件(或者更确切地说是 Linux 文件系统缓存)里发送到网络通道,而不需要经过任何中间缓冲区。
分区副本数量 = 分区的主题 * 复制系数 ,broker 平均分配分区副本和 leader ,同一主题的分区副本不会分到同一个 broker 上。
Partition 文件下有多个 segment (默认大小 1g)。如果达到设置大小时,会滚动一个新的 segment 并且以上一个 segment 最后一条消息的偏移
可以制定清理策略。
可靠的数据传递
需要保证ACID。
broker 通过禁止不同步的副本成为首领 ( unclean.leader.election.enable=false ),保证一致性。通过最少同步副本的设置 ( min.insync.replicas ),保证可靠性 。
生产者可以设置重试参数,在遇到可重试错误时能够保持重试 ,这里需要注意幂等性。
消费者要注意提交了偏移量却未能处理完消息。以及重试问题,可以提交最后一个处理成功的偏移量,然后把还没有处理好的消息保存到缓冲区,或者错误写入一个独立的主题。
在消费者解决最少一次和精确的一次的问题时,可以把结果写到一个支持唯一键的系统,也就是幂等性写入。
Kafka Connect 是 kafka 的一个客户端 API,可保证
- 及时性:kafka 扮演的是一个大型缓冲区的角色
- 可靠性 :至少一次传递和精确的一次的问题
- 高吞吐量和动态吞吐量
- 安全性(数据加密)和故障处理能力
Kafka Streams 可以做流式处理,事件流模型 具有以下属性
- 事件流是有序的
- 不可变的数据记录
- 事件流是可重播的
- 选择请求与响应或批处理范式,或者两者之间的流式处理