kafka

kafka

定义:kafka是一个开源的分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成、关键任务应用。传统的消息的队列主要的应用场景:缓存/削峰,解耦,异步通信.
消费队列的两种模式

  1. 点对点的模式:消费者主动拉取数据,消息收到后清除消息
  2. 发布订阅模式: 可以有多个topic主题,消费者消费数据后,不删除数据。每个消费者相互独立,都可以消费到数据。

基础架构

  • 生产者Producer:消息生产者,就是kafka broker发消息的客户端。
  • kafka集群:
  1. Broker: 一台kafka服务器就是一个broker,一个broker可以容纳多个topic。
  2. topic: 可以理解为一个队列,生产者消费者面向一个的都是一个topic。
  3. partition: 一个非常大的topic可以分布到多个broker,一个topic可以分为多个partition,每个partition是一个有序的队列。
  4. replica: 一个topic每个分区都有若干个副本,一个leader和若干个follower;
  • 消费者(组)Consumer(Group):消费者组,由多个consumer组成,消费者组内的每个消费者负责消费不同分区的数据,一个分区只能由一个组内的消费者消费;消费者组之间互影响。

常用命令

  • 查看所有topic:bin/kafka-topics.sh --boootstrap-server 192.168.52.0:9092 --list (--create) (--describe) (--alter 分区只能增加不能减少) (--delete)
  • 查看生产者: bin/kafka-console-producer.sh --boootstrap-server 192.168.52.0:9092 (--from-beginning) --topic first

生产者-Producer

在消息发送过程中,涉及到两个线程,main线程以及sender线程,在main线程创建了一个双端队列RecordAccumulator。main线程将消息发送给RecordAccumulator,Sender线程不断从RA中拉取数据发动给kafka broker

key.serializer value.serializer buffer.memory batch.size linger.ms acks retries compression.type
  • 指定发送消息的key value序列化类型,要写全类名
  • 缓冲区总大小,默认32M
  • 缓冲区一批数据量最大值,默认16K
  • 如果数据迟迟未达到batch.size ,sender等待linger.time之后就会发送数据。
  • acks:0生产者发送过来的数据不需要等数据落盘应答;1leader收到数据后应答;-1 (默认)leader和isr队列里面的所有节点收齐数据后应答。
  • 消息发送出现错误时,系统会重发消息,表示重试次数,默认int最大值
  • 生产者发送的所有数据的压缩方式,none(默认)。

生产者分区的好处

  1. 便于合理使用存储资源,每个partition在一个broker存储,可以把海量的数据按照分区切割成一块一块的数据存储在多台broke上,合理控制分区的任务,可以实现负载均衡
  2. 提高并行度,生产者可以以分区为单位发送数据,消费者以分区消费数据
  • 指明partition的情况,直接将指明的值作为partition值
  • 没有指明partition值,但有key的情况下,将key的hash与topic的partition取余得到partition值(顺序消费)
  • 既没有partition又没有key值,采用粘性分区器,会随机选择一个分区,并且尽可能一直使用该分区,待该分区batch已满或者已完成,再随机一个分区进行使用

生产经验

  • 生产者如何提高吞吐量
  • 数据可靠性:ack应答级别
    0:可靠性差,效率高 ,可能丢数 ;1:应答完成后还没开始同步副本,leader挂了,新的leader不会收到信息,可能丢数; -1:可靠性高,效率低,不会丢数,但是若有一个follower因为故障不能与leader同步? 另外数据重复?
    leader维护了一个动态的in-sync replica set (ISR) 意味和leader保持同步到follower+leader集合,如果follower长时间未向leader发送通信请求或者同步数据,则该follower将被提出ISR,这样就不用等长期联系不上或者已经故障的节点

同步判断条件:follower向leader拉取数据的间隔小于replica.lag.time.ms=10000

数据完全可靠性条件=ack级别设置为-1 + 分区副本>=2 +ISR 里应答的的最小副本数量>=2

  • 数据重复
    至少一次(at least once) =数据完全可靠性条件,保证数据不丢失,可能会重复
    最多一次(at most once) =ack级别为0 ,保证数据不重复,可能会丢失
    精确一次(exactly once) ? 幂等性+至少一次

    幂等性原理

    幂等性就是指producer 不论向broker发送多少次重复数据,broker端只会持久化一条,保证单分区单会话不重复,具有<pid(每次重启都会分配一次),partition,seq number(单调递增)>相同主键的消息提交时,只会持久化一条

每个producer 在初始化时会生成一个producer_id ,并为每个目标partition委会一个序列号; producer每发送一条消息,会将对应的序列号加一,broker端会维护一个序列号,对于每收到的一条消息,会判断 服务端的SN_old 和接受到的消息中的SN_new 进行对比
如果old+1=new 正常;old+1>new 重复写入数据直接丢弃;old+1<new 说明中间有数据尚未写入或者发生乱序,或者数据丢失,抛出异常 OutOfOrderSequenceException

  • 数据有序
    单分区有条件有序: 未开启幂等性 max.in.flight.requests.per.connection=1 ;开启幂等性 max.in.flight.requests.per.connection<=5; 启用幂等性后,kafka会缓存producer发来的最近的5个request元数据,无论如何最近5个都是有序的,开启幂等性切缓存请求小于等于5个,会在服务端重新排序。
    多分区无序

生产者事务

transaction coordinator (事务协调器) :开启事务,必须开启幂等性。producer在使用事务功能之前,必须先自定义一个唯一的transactional id 即使客户端挂掉,他重启后也能继续处理未完成的事务。

kafka broker

工作流程

  1. broker (每个kafka是一个broker)启动后在zk中注册 /brokers/ids/ [0,1,2]
  2. controller(每个broker都有一个controller) 谁先注册谁说了算,由选举出来的controller 监听broker节点的变化 controller "brokerid": 0
  3. controller 决定leader选举,选举规则:在ISR中存活为前提,按照在AR(kafka分区所有副本的统称)中排前面的优先
  4. controller将节点信息上传到zk中,其它controller从zk中同步相关信息 /brokers/topics/first/partitions/0/state "leader":0, "isr":[0,1,2]
  5. 假设broker1中leader挂了。controller监听到节点变化,获取ISR
  6. 选举新的leader (在ISR中存活为前提,按照AR中排在前面的优先) 更新leader以及ISR
    Kafka判断一个节点是否活着有两个条件
    1. 节点必须可以维护和ZooKeeper的连接,Zookeeper通过心跳机制检查每个节点的连接。
    2. 如果节点是个follower,他必须能及时的同步leader的写操作,延时不能太久。

kafka 副本--提高数据可靠性

kafka默认副本一个,生产环境一般配置2个,保证数据可靠性;太多副本会增加磁盘存储空间,增加网络上数据传输,降低效率
kafka分区中所有副本的统称为AR,AR=ISR+OSR,ISR表示和leader保持同步的follower,OSR表示follower与leader副本同步时,延迟过多的副本。

leader选举流程

kafka中有一个broker的controller会被选举为controller leader,负责管理集群broker的上下线,所有topic的分区副本分配和leader选举等工作。

leader 和follower故障细节处理

LEO (Log End Offset):每个副本的最后一个offset,最新的offset+1
HW (High Watermark):所有副本中的最小的LEO
LSO (last stable offset):一个事务批次中事务头消息的前一条

HW 用途:消费者只能看到HW之前的数据;leader挂掉,其它同步follower成为新leader要截断HW之后的消息

  • follower故障 : follower发生故障后会被临时提出ISR,这个期间Leader 和Follower 继续接受数据 ,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截掉,从HW开始向leader进行同步、等该follower的LEO大于等于该partition的HW,就可以重新加入ISR
  • leader 故障: leader发生故障之后,会从ISR中选出一个新的leader,为保证多个副本的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。

分区副本分配

生产经验-leader partition 负载平衡

正常情况下,kafka本身会自动把leader partition均匀分散在各个机器上,来保证每台机器的读写吞吐量都是均匀的。但是如果某些broker宕机,会导致过于集中在其他少部分几台broker上,回导致少数几台broker的读写请求压力过高,读写请求很低,造成集群负载不均衡。

文件存储机制

kafka文件存储机制:topic 是逻辑上的概念,partition是物理上的概念,每个partition对应于一个log文件,该log文件存储的就是producer生产数据,producer生产数据会被不断追加到该log文件末端,为防止log文件过大导致数据定位效率低下,kafka采取了分片和索引机制,将每个partition分为多个segment ,这些文件位于一个文件夹下,该文件夹的命名规则为 :topic+分区序号

.index .log .timeindex
偏移量索文件 日志文件 时间戳索引文件

index为稀疏索引,大约每往log文件写入4kb数据(log.index.interval.bytes),会往index文件写入一条索引; index 文件中保存的offset为相对offset,这样确保offset的值所占空间不会过大,因次能将offset的值控制在固定大小

文件清理策略

kafka默认的日志保存文件为7天,日志一旦超过设置时间,提供了两种日志清理策略:

  • delete 日志删除: 将过期数据删除
  • compact 日志压缩: 对于相同的key不同value值,只保留最后一个版本,压缩后的offset可能是不连续的

高效读写数据

  1. kafka本身是分布式集群,可以采用分区技术,并行度高
  2. 读取数据采用稀疏索引,可以快速定位到要消费的数据
  3. 顺序写磁盘
  4. 页缓存+零拷贝 : kafka的数据加工处理操作交由kafka生产者和kafka消费者处理, broker应用层不关系存储的数据,不用走应用层,传输效率高。 kafka重度依赖底层操作系统提供的pagecache功能,当上层有写操作时,操作系统只是将数据写入pagecache。当读操作发生时,先从pagecache查找,查找不到,再去磁盘中读取。

零拷贝:减少CPU拷贝次数,Customer从broker读取数据,采用sendfile(),将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送。通过DMA技术将文件内容复制到内核模式下的read buffer,不管有没有数据复制到socket buffer ,只有包含数据的位置和长度的信息的文件描述符被加到socket buffer,DMA引擎直接将数据从内核模式传递到网卡设备。

kafka消费者

消费方式:pull

工作流程

消费者组(Consumer Group): 由多个consumer组成,形成一个消费者组的条件是所有消费者的groupid相同

  • 消费者组内的每个消费者负责消费不同分区的数据,一个分区只能由一个组内的消费者消费。
  • 如果向消费者组内添加更多的消费者,超过主题分区数量,则有一部分消费者就会闲置,不会接受任何消息。

消费者组初始化流程

  1. coordinator:辅助实现消费者组的初始化和分区分配 ,节点选择:groupid的hashcode值%50 (_consumer_offsets 的分区数量) 在哪个broker上就选择这个节点的coordinator作为这个消费者组的老大,消费者组下的所有消费者提交offset时候就往这个分区提交offset
  2. 选出一个consumer作为leader ,把要消费的topic情况发送给leader消费者,leader会制定消费方案,把消费方案发送给coordinator
  3. coordinator就把消费方案下发给各个consumer, 每个消费者和coordinator保持心跳(3s默认),一旦超时,该消费者会被移除,并触发再平衡,或者消费者处理消息时间过长,也会触发再平衡。

生产经验--分区的分配以及再平衡

  1. 一个consumer group有多个consumer组成,一个topic有多个partition组成,那由那个consumer来消费哪个partition数据
  2. kafka 有四种主流的分区分配策略:Range、RoundRobin、Sticky、CooperativeStickty , 默认策略是Range+CooperativeSticky ,可以同时使用多个分区分配策略
  • Range是针对每个topic而言的,首先对同一个topic 里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。 通过partition/consumer 来决定每个消费者应该消费几个分区 ,容易产生数据倾斜。
  • RoundRobin针对集群所有topic 而言,把所有partition和所有consumer列出来,按照hashcode进行排序,最后通过轮询算法分配给partition给各个消费者
  • Sticky:在执行一次新的分配之前,考虑上一次的分配结果,尽量少的调整分配的变动,可以节省大量的开销。

提交offset

  • 自动提交offset
  • 手动提交offset :提供两种,分别是同步提交和异步提交,两者的相同点是都会将本次提交的一批数据最高的偏移量提交;不同的是同步提交阻塞当前线程,一直到提交成功,并且会自动失败重试,而异步提交则没有失败重试机制,有可能提交失败。

漏消费和重复消费

重复消费:已经消费了数据,但是offset没提交 (自动提交offset引起)
漏消费:先提交offset后消费,有可能会造成数据的漏消费(手动提交offset)

生产经验--消费者事务

posted @ 2022-03-28 19:18  Henry19  阅读(93)  评论(0编辑  收藏  举报