kafka总结

目录

目标

what

三个主要能力

两种典型的应用

集群

四种api

介绍

Topics and Logs 主题和日志

Distribution 分布式

Producer 发布者

Consumer 消费者

Kafka作为消息系统

Kafka作为存储系统

Kafka作为流式进程

使用场景

设计

持久化

效率,为什么快

生产者

消费者 

消息交付机制

复制

log压缩

配额

实现

网络层

消息构成

消息格式

Log

分布式

zk节点结构


目标

kafka,仅支持拉取的分布式流式平台。本文从简介、使用场景、设计、实现四个方面阐述kafka。

kafka系统关系图

what

kafka是仅支持拉取pull方式的分布式流式平台。

三个主要能力

  • 针对记录流进行发布与订阅,类似于消息队列 
  • 存储记录流并且保证故障恢复
  • 实时地执行产生的记录流

两种典型的应用

  • 构建实时流式数据管道,用于系统间可靠的获取数据 
  • 构建实时流式应用,依据数据进行转换或响应

集群

kafka以集群的方式运行,其中的服务器可以分为多个数据中心;集群以主题维度存储数据;每个记录包含key/value/timestamp。

四种api

Producer API,向一个或多个主题发布记录

Consumer API ,订阅一个或多个主题

Streams API,应用作为流处理器,消费来自一个或多个主题的输入记录流,生产一个或多个主题的输出记录流,在输入和输出流之间高效的转换。

Connector API,构建和运行可重用的生产者或消费者,它们将主题与已存在的应用或数据系统进行连接。例如与关系型数据库连接的连接器,可能捕获每个变更并入表。

介绍

Topics and Logs 主题和日志

主题

对记录流的抽象,对发布的记录的分类,允许有多个订阅者。

kafka Logs

图示

由图可了解

  • 针对每个主题,kafka集群会维护一个分区式log,也就是一个主题分为多个分区
  • 每个分区可视为一个commit log,有序的且不可修改的记录序列,可持续追加,顺序写随机读
  • 分区中的每个记录都分配一个offset,在每个分区中,offset就是唯一标识
  • kafka集群会持久化所有发布的记录,无论是否被消费,保留时长是可以配置的,超过时长后就会丢弃并释放空间
  • 实际上,每个消费者需要保留这个offset,且offset可由消费者随意控制
  • 在log中这些分区有两个作用
    • 使得log的大小可伸缩,每个分区的大小伸缩必须与其建立连接的servers匹配,因为一个主题有多个分区,所以主题可以控制任意数量的数据。
    • 分区是平行单元

 

Distribution 分布式

  • Log的所有分区,在kafka集群中是分布式的
  • 每一个server会对一部分分区的数据和请求进行处理
  • 每个分区在集群中会复制多份,以达到容错的目的,复制份数是可以配置的。
  • 针对每个分区,有一个server作为leader,多个server作为followers;
    • leader控制这个分区的所有读写请求,同时followers会复制leader数据。
    • leader故障时,一个follower会自动成为新的leader
      • zk上生成leader节点
  • 针对每个server,既作为某些分区的leader,也作为其它某些分区的follower,因此集群负载是平衡的

 

Producer 发布者

负责向选定的主题发布记录,并决定记录发布到哪个分区,路由机制:轮询 或其他(例如基于记录中某个key)

Consumer 消费者

图示

由图可了解

  • 通过group name将consumer划分为一组
  • 主题的记录log分为多个分区,每个分区的记录只能由组中一个consumer消费
  • kafka仅保证单个分区内记录的顺序性,如果需要主题的所有记录必须被顺序消费,则主题必须仅有一个分区,因此组内只有一个consumer可以进行消费。

 

Kafka作为消息系统

传统消息系统的优缺点

queue

  • 消费者池从queue取数据,使得一个记录被一个消费者处理
  • 优点:将queue中所有记录的处理分割给了多个消费者,这样可以伸缩记录处理能力
  • 缺点:不支持多个订阅者,而仅是一个进程在读queue中记录。

发布-订阅

  • 发布的每个记录会广播给所有订阅者
  • 优点:每个记录广播给所有订阅者,有多个进程在读和处理记录
  • 缺点:无法伸缩处理能力

 

Kafka作为存储系统

写入kafka的数据会落盘并进行容灾复制

生产者等待回告,以判断"数据的持久化和复制"是否成功

 

Kafka作为流式进程

作为一个流式进程,不断的从输入主题获取数据流,处理数据,不断的向输出主题生成数据流

 

使用场景

消息系统

网站用户活动跟踪

各种类型的用户行为被发布到不同的主题,然后被多种消费者订阅,以便完成实时处理\实时监控\存到hadoop或其它离线仓库系统以进行离线处理。

监测数据

日志聚合

流处理

事件发起源

状态改变是以发生的时间顺序进行存储

commit log提交日志

设计

持久化

  • kafka基于文件系统进行数据存储和缓存,(使用"作为磁盘缓存的内存-pagecache",磁盘数据预读到pagecache,数据直接写入pagecache而不是刷新到磁盘,提升磁盘线性读写的速度) 
  • 消息日志存在一个目录中,每个目录对应一个消息序列

 

效率,为什么快

提升读效率

零拷贝

pagecache预读

从文件到字节码传输的传统过程,进行4次拷贝,耗时

  • 操作系统执行读数据  磁盘-->内核空间的pagecache
  • 应用读数据 内核空间pagecache-->用户空间buffer
  • 应用写数据 用户空间-->内核空间的socket buffer
  • 操作系统执行 内核空间的socket buffer-->NIC buffer(数据从此发送到网络)

使用零拷贝后,用户空间不参与拷贝过程,经历3次拷贝,效率提升

  • 操作系统执行读数据  磁盘-->内核空间的pagecache
  • 操作系统执行 内核空间pagecache-->内核空间的socket buffer
  • 操作系统执行 内核空间的socket buffer-->NIC buffer(数据从此发送到网络)

 

提升写效率

直接写入内存的pagecache,之后按照规则刷盘

顺序写

点对点传输,批压缩

一批消息被捆绑压缩,以这种模式发送到一个server;这批消息以压缩的方式写入log;并且只有消费者才可以解压。

kafka支持GZIP, Snappy and LZ4压缩协议

 

生产者

负载均衡

  • 生产者直接将数据发送给"分区的leader",而不需要"选择leader"的路由规则,因为集群中每个server都具有一份元数据,其中包含"存活的所有server"和"每个主题的所有分区的leader信息"
  • 数据发送到哪个分区,需要通过路由规则,如随机或自定义方式(根据数据中某个key进行hash)

异步发送

kafka可以配置为"针对一个请求,积累(不超过)一定大小的数据 或 等待(不超过)一定的时间,如64K或10ms,然后发送给消费者"。优点:一次发送更多的数据,减少IO操作。对单个请求而言增加了延迟,却提升了集群的吞吐量。

 

消费者 

kafka提供消费者pull拉取数据方式 

消费位置

  • 清楚哪些数据已经被消费过,这是消息系统的一个关键能力。
  • kafka在消费者端仅维护分区的消费位置,即offset,下一个消费位置。优点:避免broker维护消费情况的复杂问题,消费者自行控制消费offset,更具有灵活性。

离线数据加载

消费者周期性加载数据到离线数据系统

 

消息交付机制

3种可提供的消息交付保证机制

理解为生产者和消费者两者的交付保证

  • 至多一次,消息丢失后不再交付
  • 至少一次,消息丢失后再次交付
  • 仅一次,消息仅交付一次

"仅一次"的交付机制

从0.11.0.0版本开始,保证生产者生产消息"仅一次"的交付机制

  • 在生产者向broker发送数据时,会携带两个数据"broker会为每个生产者分配一个ID","生产者为每个消息设置一个不重复的序号",以标示数据唯一性。
  • 使用类似事务机制,保证"向多个主题分区发送数据时原子性"

 kafka stream 以及 在生产者和消费者中使用事务,保证"主题间的传输和处理"的仅一次交付。

复制

复制单元是分区,是一个可复制的log

一个分区具有一个独立的leader和多个followers,所有的读写都与leader交互。

存活的节点需要满足两个条件(满足两个条件的节点称为"in sync")

  • 与zk保持心跳
  • 如果是follower,必须从leader复制发生的写,而且不能落后很多

leader会维护'ISR-in sync replicate同步备份'集合,一旦follower宕机/卡顿/落后很多,leader会将其从ISR集合中删除。 

仅当消息在所有ISR的followers中都完成复制后,这个消息才称之为"commited",所以消费者不必担心leader宕机时的消息丢失

考虑消息持久性和可用性进行主题维度配置

  • 关闭 unclean leader election
  • 特定的ISR数量且acks=all,需要权衡可用性和延迟

log压缩

图示

log压缩详情

log cleaner,后台线程池完成"再次复制log/删除记录"

过程

  • 选择log,依据为:log head与log tail的比例较大时
  • 对log head中每个key的最新offset进行简洁的汇总
  • 从头到尾重新拷贝log-->删除最近出现key的历史记录-->立即与log进行交换,因此需要额外的磁盘空间
  • 2中的汇总作为一个压缩hash表

 

配额

两个方面的配置

  • 带宽,字节维度
  • 请求维度,如网络百分比 IO线程数

 

实现

网络层

是一个公平直接的NIO服务器,发送文件的实现是通过MessageSet.writeTo方法,其允许基于文件的消息集合使用更加高效的transferTo方法,而不使用进程内buffer写,其实就是零拷贝。 

线程模型:一个接收器线程,多个处理器线程。

消息构成

可变长度的header+可变长度不透明的key字节数据+可变长度不透明的value字节数据

header的格式是既定的,但key和value字节数据与实际实用的序列化器有关

消息格式

多个消息通常写入到批中,称为a record batch批记录,批记录和记录具有各自的header。

批记录格式

记录格式

Log

主题的log有N个分区,就会对应N个目录,目录名为主题名+分区序号,目录中是存放消息的数据文件。例如:主题名"my_topic",其log具有两个分区,对应两个目录"my_topic_0""my_topic_1"。

log file的内容为 "多个log entry构成的序列"。log entry=代表消息长度的4子节数字 + 消息的子节。

每个消息使用一个64位整数的offset作为ID,offset表示"在这个分区的消息流中,该消息开始的字节位置"。

log file名称为该文件中第一个消息的offset,后缀名为.kafka。

线性追加到最后一个文件,当文件达到最大大小(1G)时会使用新建的文件。

log 写有两个配置项

  • 强制OS进行刷盘前,可以写入的消息数量M
  • 刷盘的间隔时间S

在持久性上做了保证,最多丢失M个数据或S时间间隔内的数据

读时需要传递64位offset和块的上限大小S,返回'S字节缓冲区中包含的消息的遍历器';S应该比单个消息大,但是对于大消息需要进行多次读,且每次S需要翻倍,直到读取成功。

消息的上限大小和缓冲区大小是可以配置的,这样让server可以拒绝大消息,而且也给了client一个最大量的约束-每次都要读取整个消息。

通过offset读取消息的过程

  • 二分查找方式定位所在文件
  • 计算在该文件中的offset
  • 从该offset进行读取

result格式

删除

文件维度进行删除,规则为N天前修改/保存最近NG大小的log

为了不阻塞读,在文件删除时使用copyOnWrite方式,删除同时提供当前log view的快照,删除完成后使用新log view

存储保证

强制刷盘前可写入M个消息,broker每次启动时都会对log分区最新的文件进行遍历并验证消息的合法性(消息大小+其offset要小于文件的长度 且 冗余校验码正确)

 

分布式

消费者offset追踪

高级消费者需要做两点

  • 对自己消费的分区,记录下消费的最高offset
  • 提交"分区-消费的最高offset"集合,便于重启时重新处理

kafka提供配置,为消费者组分配一个broker作为offset manager,因此该组内的所有消费者都要向该offset manager提交和获取offset集合。

高级消费者会自动完成offset追踪,但是对于简单消费者可能需要自行完成。

 

zk节点结构

broker

broker注册

/brokers/ids/[0...N] --> {"jmx_port":...,"timestamp":...,"endpoints":[...],"host":...,"version":...,"port":...} (ephemeral node)

其代表所有存活broker的节点,每个节点使用一个唯一的逻辑ID

borker topic 注册

/brokers/topics/[topic]/partitions/[0...N]/state --> {"controller_epoch":...,"leader":...,"version":...,"leader_epoch":...,"isr":[...]} (ephemeral node)

broker将自己注册到某个主题的某个分区的状态节点中

 

consumer

consumer注册

/consumers/[group_id]/ids/[consumer_id] --> {"version":...,"subscription":{...:...},"pattern":...,"timestamp":...} (ephemeral node)

代表当前存活的consumer,znode具有临时的consumer_id,格式为hostname:uuid,其数据包括该consumer订阅的主题

可以用zk存储consumer offset

/consumers/[group_id]/offsets/[topic]/[partition_id] --> offset_counter_value (persistent node)

记录下某个分区已经消费的最大offset

分区归属哪个消费者

/consumers/[group_id]/owners/[topic]/[partition_id] --> consumer_node_id (ephemeral node)

每个分区由哪个消费者负责

 

cluster集群ID

/cluster/id

 

consumer启动流程

consumer_id注册

监听group内consumer_id的变化,以便在consumer间重平衡各自的职责

监听broker的变化

如果使用topic filter,需要监听broker topic,当topic变化时再次判断哪些topic能通过filter

group内进行一次重新平衡

 

consumer平衡调整

group内消费者重新平衡的作用:在分区分配方面,让消费者保持一致。

重平衡过程

  • topic的所有分区P并排序
  • group内的所有消费者C并排序
  • i作为消费者结合C的index,N作为分区P数量/消费者C数量的比值
  • i*N to (i+1)*N - 1的分区分配给index为i的消费者
  • 删除原来的"分区归属哪个消费"的节点
  • 新建"分区归属哪个消费"节点

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值