团队在日常工作中,个别状况下应用的音讯队列是腾讯云 CKafka。CKafka 提供了高牢靠的开箱即用音讯队列能力,让咱们在日常可能放心使用,缩小花在运维上的投入。不过即便如此,咱们还是须要学习 Kafka 的一些基本概念和性能,从而在理论利用中嗯可能充沛高效、高质量地利用 Kafka 的能力。
业务基本概念
本大节次要阐明的是在软件业务层面,咱们应用 Kafka 中会接触到的概念
音讯 Message
对于一个音讯队列零碎,最根底的天然是“音讯”。在 Kafka 中,“音讯”就是 Message
,是在 Kafka 中数据传输的根本单位。多个音讯会被分 批次 写入 Kafka 中。这同一批次的音讯,就称为一 组音讯。
生产者 和消费者
生产者和消费者的概念就很好了解了:产生音讯的服务就称为“生产者”Producer
,也称为“发布者”Publisher
或 Writer
。
而须要获取音讯的服务就称为“消费者”Consumer
,也称为“订阅者”SubScriber
或 Reader
。
主题 Topic 和 分区 Partition
在 Kafka 中,所有的音讯并不是还有一条队列。Kafka 的音讯通过 Topic
进行分类。而一个 Topic 能够被辨别为多个“分区”Partitions
。
这里须要留神的是,在 同一个 partition 外部,音讯的程序是可能保障的。也就是说:如果音讯 A 达到 partition 的工夫早于音讯 B,那么消费者在获取音讯的时候,必然是先取得音讯 A 之后,才可能获取到音讯 B。
然而,如果在多个 partitions 之间,音讯的程序就无奈保障了。比方当消费者监听多个 partitions 时的话,音讯 A 和音讯 B 被读取进去的工夫无奈保障。
那这么一来,partition 有什么用呢?实际上 Partition 是用来做负载平衡的。当 comsumer 将音讯发到一个 topic 上时,Kafka 默认会将音讯尽量平衡地散发到多个 partitions 上。作为消费者监听 topic 时,须要配置监听哪些 partitions。一个 consumer 能够监听多个 partitions,comsumer 和 partition(s) 的对应关系也称为“所有权关系”。
偏移量 Offset
Offset
是一个递增的整数值,由 Kafka 主动递增后主动写入每一个 partition 中。在同一个 partition 中,一个 offset 值惟一对应着一条 message。此外,因为 offset 是递增的,因而也能够用来辨别多个 message 之间的程序。Consumer 的重启动作并不影响 offset 的值,因为这是 Kafka 来进行保护的数值。
Broker 和 集群
一个独立的 Kafka server 就称为一个 broker
。一个或多个 broker 能够组成一个“集群”broker cluster
。Kafka 尽管是一个分布式的音讯队列零碎,然而在集群中,Kafka 仍然是准中心化的零碎架构。也就是说每一个集群中仍然是有一台主 broker,称为 controller
。
每一个 cluster 会主动选举一个 cluster controller
进去,controller 须要负责以下操作:
- 治理 cluster
- 将 partition 调配给 broker 和监控 broker。
在 cluster 中,一个 partition 会从属于一个 broker,这个 broker 也会称作该 partition 的 leader
。同时该 partition 也能够调配给多个 broker,进行 分区复制——如果其中一个 broker 生效了,那么其余的 broker 能够尽快接管 leader 的地位。如果是应用云原生的 Kafka,咱们个别就不须要太放心这个问题。
装置 / 运维基本概念
Kafka 部署架构
如果是运维本人装置 Kafka 的话,须要提前装置的软件是 Java
和 Zookeeper
。我过后就十分纳闷怎么多了一个 Zookeeper
?实际上 Kafka 是应用 Zookeeper 来保留 cluster 中的元数据和消费者信息。这里体现出了 Java 弱小和欠缺的生态圈,各种计划都可能找到已有的轮子。
Zookeeper 也反对集群部署。Zookeeper 集群称为“群组”Ensemble
。因为 ensemble 也是应用了选举机制,因而每个 ensemble 中有奇数个节点,不倡议超过 7 个。如果咱们应用了云原生的 Kafka,就不须要过多关怀这个细节啦。
Topic 参数
部署好了 broker 和 Zookeeper 之后,咱们就能够创立 topics 了。创立 topic 时有一些参数须要进行配置。次要的有以下几项须要特地注意:
num.partitions
: 新 topic 默认的分区数。在后续运维中,partition 的数量只会减少,不会缩小。在腾讯云 CKafka 中,这对应着“分区数”配置log.retension.ms
: 依照工夫决定 topic 中的数据能够保留多久。这对应 CKafka 界面中的“retension.ms”参数log.retension.bytes
: 依照存储空间决定 topic 中的数据能够保留多少。该参数在 CKafka 中不反对log.segment.bytes
: 示意依照存储空间决定日志片段文件的大小。该参数在 CKafka 中不反对log.segment.ms
: 示意依照时长决定日志片段大小。对应 CKafka 界面中的“segment.ms”参数。不是必要参数
如何抉择 Partitions 的数量?
后面提到,在同一个 partition 中,音讯的程序是可能失去保障的。因而对于一个小型的、对可靠性要求不高、然而对程序性要求很高的零碎而言,或者能够应用单 partition 的计划。
然而这个计划其实是十分危险的:
- 首先,繁多 partition 就意味着 consumer 也只能有一个,否则会呈现音讯反复生产的问题。在一个生产我的项目中进行单点部署,这简直是不可承受的
- 尽管在 Kafka 外部,繁多 partition 内的音讯程序可能失去保障,但如果生产者未能失去保障的话,那么 kafka 内的音讯程序仍然不是实在的。因而对于有强程序要求的音讯队列零碎中,不倡议应用工夫程序,而是采纳逻辑程序 / 逻辑时钟来辨别音讯的先后。
因而在理论生产环境中,咱们该当适当地调配 partition 的数量。如果对程序性有要求,那么不应该依赖 kafka 的程序机制,而是应用额定的机制来保障。
Kafka 生产者
架构图
生产者向 Kafka broker 发送音讯个别是用各语言的 SDK 来实现的。上面框图中是 SDK 实现的逻辑。首先 producer 在发送 message 之前,须要将 message 封装到 producer record
中,record 蕴含的必填信息是 topic 和 value(也就是 message 注释)信息。此外还可选 partition 和 key 信息,不过绝对少用。Key 参数的作用后文会作阐明。
当音讯被写入 Kafka broker 之后,broker 会回调到 SDK 中,将音讯最终落地的 partition 和 partition 中的 offset 信息返回给 SDK,并最终视须要返回给 Producer。
音讯发送
Kafka 生产者有两种音讯发送形式:同步 和 异步。
同步发送形式就是生产者收回的每一个音讯,都须要依照下面的结构图的流程解决:音讯收回后期待 Kafka broker 的后果响应之后再做进一步的解决。Kafka broker 返回的谬误中蕴含了两种谬误:
- 可重试谬误: 当遇到这一类谬误时,生产者能够间接从新尝试发送。比方网络谬误、集群谬误等等。
- 不可重试谬误: 当遇到这一类谬误时,生产者只能思考告警、记录、批改软件逻辑等等。比方音讯过大等等。
异步发送形式就是生产者通过 SDK 发送音讯之后就间接返回;SDK 在后盾解决音讯的发送、响应解决,而后通过回调告知生产者以进行进一步的解决。
生产者参数
生产者启动之前也有一些参数可进行配置。读者能够在各语言的 SDK 中具体查找:
-
acks
: 音讯发送给 Kafka broker,因为实际上会有多个 broker,因而音讯是须要复制多份的。该参数示意须要期待多少个 broker 的响应,才视为音讯发送胜利:- 0: 示意不须要期待 broker 响应
- 1: 示意 leader 响应即可
- all: 示意须要所有的 broker 响应
buffer.memory
: 生产者的缓冲区大小。单位是 message 的数量。当缓冲区满了之后,SDK 会依据maxblock.ms
期待并阻塞一段时间之后再进行重试。如果缓冲区还是满了的状态,则会抛出异样或返回谬误compression.type
: 消息压缩格局,可选值为:snappy
,gzip
,lz4
retries
: 重试次数,重试距离为retry.backoff.ms
,默认是 100msbatch.size
: 一个批次的数据大小,字节数。为了缩小网络传输中的耗费,Kafka 生产者并不是一个音讯就通过一次发送收回去,而是组成一个个批次进行发送。当一个批次的大小达到这个参数时,则会马上收回。linger.ms
: 一个批次发送之前的缓冲工夫。当批次的尺寸未达到batch.size
的话,SDK 也不会始终按住 message 不发送,而是期待一段时间之后也会把内存中的批次收回client id
: 自定义字符串,用于标识生产者max.id.flight.requests.per.connection
: 这个参数指的是收到服务器响应之前,生产者能够发送的音讯数。设置为 1 能够保障音讯程序,然而相应的效率就降落了request.timeout.ms
: 生产者发送数据之后期待响应的工夫
Key 的作用
在 producer record 中的 key
有两个用处:
- 作为音讯的附加音讯
- 能够用来决定写入到哪一个分区。默认分区器能够使领有雷同 key 的音讯写入同一个分区。
- 如果 key == null,则默认采纳轮询形式写入分区
- 如果 key 非空,则依据哈希后果决定分区
生产者也能够通过自定义分区器来实现业务的具体分区性能,具体参见各语言的 SDK
Kafka 消费者
一个 Kafka 的消费者是从属于其对应的 comsumer group 的,每一个 group 订阅一个 topic,每个 consumer 生产一部分的音讯。整个 group 外部通过生产不同的 partition 实现负载平衡。每一个 group 都有一个 group.id
用于标识一个消费者群组,这在业务中就对应着一个消费者业务。
不要让消费者数量多于分区数量,否则会导致呈现反复生产的问题。因而在 partition 选用时,宜多不宜省。更多的分区数量也可能更加正当地调配 consumer 之间的负载。
分区再平衡 Partitions Reoke / Rebalance
每个消费者能够对应一个或多个 partition;多个 consumer 组成一个 group,笼罩 topic 的全副 partitions。然而当 consumer 和 partitions 数量发生变化时,须要重新分配 所有权关系。这个动作就称为 Rebalance
。至于是热切换还是冷切换,则由业务方决定。
消费者在调用 subscribe()
监听音讯时,能够传入一个 ConsumerRebalanceListener
实例来监听事件。其中须要关注的事件有:
onPartitionsRevoked()
: 这是再均衡开始之前的事件。留神此时消费者应进行生产,并且 commit 已实现但尚未 commit 的 offset 值onPartitionsAssigned()
: 这是再均衡完结,也就是重新分配分区完结之后的工夫。大部分状况下消费者也不须要特地解决什么,不过能够在这里进行一些生产过程的重启动作
Commit 和 Offset
前文提到,一个 message 可能与 kafka 中的一个 partition 中的一个 offset 值一一对应。对于消费者而言,partition-offset 对也能够用于标识以后 comsumer 曾经获取到的音讯的进度,也能够用于消费者在 kafka 中进行历史音讯的寻址。
当对某个 message 生产实现后,消费者会将 offset 值提交到 kafka 中,从而让 Kafka 辨认并保留某个 comsumer group 的生产进度。下一次 consumer 再申请事件时,默认会从该 offset 往后持续获取。Consummer 向 Kafka 更新 offset 的这一动作就称为“提交”commit
。
如果 consumer 产生解体,或者有新的 consumer 退出 group,就会触发 rebalance。实现 rebalancing 之后,每个 consumer 有可能会被调配到不同的分区。为了可能持续之前的工作,consumer 须要读取每一个分区最初一次提交的 offset,而后从指定的 offset 持续解决。这个操作,个别在 SDK 中就实现了。然而在上述切换过程中,因为分布式系统的分布式、异步个性,咱们不可避免的还是可能遇到一些不统一的状况,具体表现为音讯的反复解决和漏解决。所以咱们在任何时候都不能简略依赖 Kafka 自身提供的音讯队列机制,而是在各自的业务零碎中也须要进行肯定的进攻式编程,防止错误处理呈现。
一般而言,SDK 有上面几种 commit 形式:
- 主动提交:
enable.auto.commit
为true
时,API 定时、异步地进行 commit。因而,如果在触发了再平衡的时候还有局部数据未 commit,那么在再平衡之后在其余的消费者中就有可能产生反复生产 - 被动提交:
enable.auto.commit
为false
时,业务方须要被动调用相干 API 进行 commit。 - (被动的)异步提交: 其实就是被动提交的异步版,简略而言就是开一个后盾异步 commit 的过程。
- 提交特定的 offset: 这种模式就是显式地 commit 具体 partition 的某个 offset 值。
参考资料
- Kafka 权威指南 – 本文的框图基本上都是参照该书绘制的
本文章采纳 常识共享署名 - 非商业性应用 - 雷同形式共享 4.0 国内许可协定 进行许可。
原作者:amc,欢送转载,但须要依照以上许可协定注明出处。
本文链接: https://segmentfault.com/a/1190000038592433
原文题目:入门 Kafka 你所须要理解的基本概念和开发模式
公布日期:2020-12-01
原文链接:https://cloud.tencent.com/developer/article/1755160。也是自己的博客