写点什么

Kafka 核心逻辑介绍 | 京东云技术团队

  • 2023-12-19
    北京
  • 本文字数:3449 字

    阅读完需:约 11 分钟

Kafka核心逻辑介绍 | 京东云技术团队

1、概念

Kafka 是最初由 Linkedin 公司开发,是一个分布式、支持分区的(partition)、多副本的(replica)分布式消息系统(kafka2.8.0 版本之后接触了对 zk 的依赖,使用自己的 kRaft 做集群管理,新增内部主体 @metadata 存储元数据信息),它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于 hadoop 的批处理系统、低延迟的实时系统、storm/Spark 流式处理引擎,web/nginx 日志、访问日志,消息服务等等,用 scala 语言编写,Linkedin 于 2010 年贡献给了 Apache 基金会并成为顶级开源 项目。


类似产品还有 JBoss、MQ(ActiveMQ、RabbitMQ-erlang、RocketMQ-支持事务型消息)

2、kafka 的特性

  • 高吞吐量、低延迟:kafka 每秒可以处理几十万条消息,它的延迟最低只有几毫秒。(RecordAccumulate

  • 可扩展性:kafka 集群支持热扩展

  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失

  • 容错性:允许集群中节点失败(若副本数量为 n,则允许 n-1 个节点失败)

  • 高并发:支持数千个客户端同时读写

3、为什么要使用 kafka

① 异步处理


② 服务解耦


③ 流量控制

4、kafka 原理解析

消息是 kafka 的基本单位,消息是一串字节构成的。主要是 key、value,key 根据一定的策略,将消息体路由到不同的 partition 分区中。


kafka 消息全部持久化到磁盘,其使用日志文件的方式来保存。Partition 以文件的形式存储在文件系统中


命名规则:<topic_name>-<partition_id>




**Producer:**消息⽣产者,向 Kafka Broker 发消息的客户端。


**Consumer:**消息消费者,从 Kafka Broker 取消息的客户端。Kafka 支持持久化,生产者退出后,未消费的消息仍可被消费。


**Consumer Group:**消费者组(CG),消费者组内每个消费者负责消费不同分区的数据,提⾼消费能⼒。⼀个分区只能由组内⼀个消费者消费,消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的⼀个订阅者。


**Broker:**⼀台 Kafka 机器就是⼀个 Broker。⼀个集群(kafka cluster)由多个 Broker 组成。⼀个 Broker 可以容纳多个 Topic。


**Controller:**由 zookeeper 选举其中一个 Broker 产生。它的主要作用是在 Apache ZooKeeper 的帮助下管理和协调整个 Kafka 集群。Broker 都在 ZooKeeper 的 Controller 节点上注册一个 Watcher,当 controller 发生故障的时候,注册在其上的 Watcher 会被触发,竞选成为新的 controller


**Topic:**可以理解为⼀个队列,Topic 将消息分类,⽣产者和消费者⾯向的是同⼀个 Topic。


**Partition:**为了实现扩展性,提⾼并发能⼒,⼀个⾮常⼤的 Topic 可以分布到多个 Broker 上,⼀个 Topic 可以分为多个 Partition,同⼀个 topic 在不同的分区的数据是不重复的,每个 Partition 是⼀个有序的队列,其表现形式就是⼀个⼀个的⽂件夹。不同 Partition 可以部署在同一台机器上,但不建议这么做。


**Replication:**每⼀个分区都有多个副本,副本的作⽤是做备胎。当主分区(Leader)故障的时候会选择⼀个备胎(Follower)上位,成为 Leader。在 kafka 中默认副本的最⼤数量是 10 个,且副本的数量不能⼤于 Broker 的数量,follower 和 leader 绝对是在不同的机器,同⼀机器对同⼀个分区也只可能存放⼀个副本(包括⾃⼰)。


**Message:**每⼀条发送的消息主体。


**Leader:**每个分区多个副本的“主”副本,⽣产者发送数据的对象,以及消费者消费数据的对象,都是 Leader。


**Follower:**每个分区多个副本的“从”副本,使用发布订阅模式主动拉取 Leader 的数据(与 redis 不同),实时从 Leader 中同步数据,保持和 Leader 数据的同步。Leader 发⽣故障时,某个 Follower 还会成为新的 Leader。


**Offset:**消费者消费的位置信息,监控数据消费到什么位置,当消费者挂掉再重新恢复的时候,可以从消费位置继续消费。


**ZooKeeper:**Kafka 集群能够正常⼯作,需要依赖于 ZooKeeper,ZooKeeper 帮助 Kafka 存储和管理集群信息。


High Level API 和 Low Level API :高水平 API,kafka 本身定义的行为,屏蔽细节管理,使用方便;低水平 API 细节需要自己处理,较为灵活但是复杂。


kafka 的高吞吐量


1,数据批量发送


kafka 消息从 producer 发送出去时并不是一条一条发送的,而是先发送到一个消息批次(RecordAccumulate)中,然后由 sender 线程异步的将消息批次中的消息发到 broker。这也是 kafka 吞吐量高的主要原因之一



消息发送 ---> 放入队列 ---> 申请内存 ---> 消费消息



之所以用到 CopyOnWriteMap (采用写时复制),读不需要加锁,适用于读多写少的情况。而 kafka 只有当某个 topic+partition 下的第一条消息进行写入时才会写入数据,大部分情况都是读,符合读多写少的情况。


kafka 的高可用



每个 partition 分区至少有一个副本,各个副本同步 leader 副本,一主多从的模式。


  • AR:分区中的所有 Replica 统称为 AR

  • ISR:所有与 Leader 副本保持一定程度同步的 Replica(包括 Leader 副本在内)组成 ISR

  • OSR:与 Leader 副本同步滞后过多的 Replica 组成了 OSR


有效的分区副本是一个 ISR 集合,ISR 集合保存的是有效的副本集合,如果发现某一个副本同步非常慢,则可以自动剔除。leader 副本和 fllower 副本同步的时候会有延迟,但是只要未超过阈值都是可以接受的


ISR 集合的存在只要是解决分区 leader 和 follwer 同步复制和异步复制带来的问题


持同步不是指与 Leader 数据保持完全一致,只需在 replica.lag.time.max.ms 时间内与 Leader 保持有效连接


Follower 周期性地向 Leader 发送 FetchRequest 请求,发送时间间隔配置在 replica.fetch.wait.max.ms 中,默认值为 500ms


极端情况下,如果 ISR 集合内的所有节点都 down 了,有两种情况:


1,等待 ISR 集合中的某一个节点恢复并担任 leader


2,选择所有节点(包含 ISR 之外的) 第一个恢复的担当 leader


那么目前 kafka 的策略是第二点,这样会有一个问题就是 ISR 集合之外的节点可能数据不全,会和有效 ISR 集合内节点的数据有出入,造成数据不准确,但是保持了可用性


ACK 机制


① 0:生产者无需等待服务端的任何确认,消息被添加到生产者套接字缓冲区后就视为已发送,因此 acks=0 不能保证服务端已收到消息


② 1:只要 Partition Leader 接收到消息而且写入本地磁盘了,就认为成功了,不管它其他的 Follower 有没有同步过去这条消息了


③ all:Leader 将等待 ISR 中的所有副本确认后再做出应答,因此只要 ISR 中任何一个副本还存活着,这条应答过的消息就不会丢失


2,磁盘的顺序读写


3,数据压缩传输


4,topic 划分多个 partition 分区,提高并发能力


kafka 高性能


普通文件读取:


磁盘文件 --①-> 内核缓冲区 --②-> 用户缓存区 --③-> 内核 socket 缓存区 --④-> 网卡接口 ---> 消费者


零拷贝技术


磁盘文件 --①-> 内核缓冲区 --②(transferTo)-> 网卡接口 ---> 消费者


划重点: 零拷贝并不是不需要拷贝,而是减少拷贝的次数。


DMA


DMA 技术使得 数据文件在各个层之间的传输,则可以直接绕过 CPU。


linux 系统中,零拷贝依赖于底层的 sendfile() 方法实现,java 中,FileChannel.transfeTo 方法的底层实现了 sendfile 方法。




kafka 消费方式


推拉结合:生产者 push,消费组 pull


① enable.auto.commit 是否自动提交自己的 offset 值;默认值时 true


auto.commit.interval.ms 自动提交时长间隔;默认值时 5000 ms


③ consumer.commitSync(); offset 提交命令;


**at most onece:**最多消费一次,存在数据丢失的情况


**at least once:**最少消费一次,保证数据不丢,存在重复消费 (kafka 默认消费方式)


**exactly once:**精确一次,无论何种情况下,消息只会消费一次 (依赖于外部存储系统协调)


最多一次、最少一次的主要区别:是消费消息再记录 offset 还是先记录 offset 再消费消息。

5、kafka 消息丢失问题

场景:


消费端从 leader 副本 poll 了一批消息消费之后,leader 副本挂机了,之后从 ISR 选举出的副本中的消息可能是比 leader 少了的。如果此时 consumer 处理完这批数据提交 offset,消费端会丢失这部分新产生而在 kafka 中实实在在保存着的数据。


解决方式:


HW(high Watermark)高水位


它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个 offset 之前的消息。


分区 ISR 集合中的每个副本都会维护自身的 LEO(Log End Offset):俗称日志末端位移,而 ISR 集合中最小的 LEO 即为分区的 HW,对消费者而言只能消费 HW 之前的消息。

1.kafka 的消费组如果需要增加组员,最多增加到和 partition 数量一致,否则超过的组员只会占用资源而没有作用


2.Raft 协议是啥? 比较流行的分布式协议算法(leader 选举、日志复制)


3.分区设置:一天一亿消息大致分为 8 个分区资源可满足。


参考: https://www.jianshu.com/p/6cbe28a44543


作者:京东零售 张继

来源:京东云开发者社区 转载请注明来源

发布于: 刚刚阅读数: 6
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
Kafka核心逻辑介绍 | 京东云技术团队_云计算_京东科技开发者_InfoQ写作社区