Kafka-杂记

零碎

  1. 每个 topic 是分区的,消息按照 topic 分类
  2. 一个 partition 同时只能被同一个 consumer group 中的某一个 consumer 消费
  3. topic 是逻辑上概念,partition 是物理概念
  4. 一般修改kafka的config配置文件server.properties
    • broker.id:唯一整数
    • delete.topic.enable=true:能否删除主题
    • log.dirs:运行日志存储地址
    • zookeeper.connect:zk集群地址
  5. 创建 topic 后,会在配置的 log.dirs 下生成文件名为 [topicName]-[partitionName] 的几个文件夹,用来存放数据
    • 00000000000000000000.log:配置项为 log.segment.bytes,只存储数据,默认存7天,默认大小1G,超过了就会重新创建,其命名以当前 segment 的第一条消息的 offset 命名
    • 00000000000000000000.index:存储相应 log 的索引与偏移量、大小等,之后去 log 中迅速查找消息
    • 00000000000000000000.timeindex:
    • leader-epoch-checkpoint:
  6. 每个 partition 中维护一个从头开始的 offset,仅区内有序,不一定全局有序

生产者

1. 分区策略

  1. 指明 partition ,直接使用其值
  2. 未指明 partition 但有 key 值,将 key 的 hash 值与 topic 的 partition 数取余,作为 partition 数
  3. 未指明 partition 也没有 key 值,第一次调用时生成一个随机整数的绝对值(之后再其上自增),将其值与 topic 的可用 partition 数取余,作为 partition 数,这种方式称为 round-robin 算法(轮询算法)

2. 数据可靠保证(ISR)

topic的每个partition的leader收到生产者发送的数据后,会向生产者发送ack ,生产者收到后会进行下一轮发送,否则会重新发送

2.1. 副本数据同步策略(发送 ack 时机)

策略 优点 缺点
半数以上完成 延迟低 选举新leader时,容忍n台节点故障,需要2n+1个副本
全部完成 选举新leader时,容忍n台节点故障,需要n+1个副本 延迟高

2.2. kafka的同步策略(全部完成的升级版)

ISR(in-sysc replica set),由leader维护,意为与leader保持同步的的follower集合,集合中的follower完成数据同步后,则会发送ack。当其长时间未向leader同步数据,则将该follower踢出ISR。时间阈值配置项为replica.lag.time.max.ms。

2.3. ack应答机制

对于不太重要的数据,允许少量丢失,所以没必要等待ISR全部接收成功,此时提供了三种可靠性级别,即ack 参数

  • 0:生产者不等待broker的ack,延迟最低。broker一接收到还没有落盘就返回,broker故障时可能丢失数据
  • 1:生产者等待broker的ack,partition的leader落盘成功后返回ack。如果在follower同步成功前leader故障,可能丢失数据
  • -1(all):生产者等待broker的ack,并且在follower同步成功前后返回ack。如果在follower同步成功后,broker发送ack前,leader故障,则会造成重复数据

2.4. 副本数据一致性

  • LEO(Log End Offset):每个副本中最后一个(即最大的)offset
  • HW(High Watermark):指消费者所能见到的最大的offset,ISR中最小的LEO,HW之前的数据才对消费者可见
2.4.1. follower故障

follower故障后,会被临时踢出ISR,恢复后会读取本地磁盘的HW,并将高于部分截掉,从HW重新开始同步,等到其LEO大于等于该partition的HW时,重新加入ISR

2.4.2. leader故障

leader故障后,会选举出新的leader,其余follower会将各自高于HW的部分截掉,从新的leader开始同步

3. Exactly-Once

3.1. 几个概念

  • At Least Once:至少一次,即ack=-1时,此时不会丢数据,但可能重复数据
  • At Most Once:只多一次,即ack=0时,此时保证每条消息只会被发送一次,不会重复数据,但可能会丢数据
  • 幂等性:无论发送多少次重复数据,都只会保留一条。配置项为 enable.idompotence=true
  • Exactly-Once:等于At Least Once+幂等性

3.2. 语义实现

开启幂等性的生产者初始化时会生成一个PID,发往同一个partition的消息会附带sequence number,而broker端会对<PID,partition,sequence number>做缓存,相同主键的消息只会持久化一条。但是由于PID重启生产者会变化,不同的partition也有不同主键,所以无法做到跨分区跨回话的Exactly-Once

消费者

1. 消费方式

pull模式,优点是适应了消费能力,缺点是如果没有数据会陷入循环中。可使用timeout,消费者会等待一段时间才返回

2. 分区分配策略

2.1. RoundRobin

消费者组的所有消费者,必须订阅相同的主题时,其将所有订阅的主题看成一个整体,按照hash值排序,按照顺序依次分配

2.2. Range

按照相同的topic分别分组,之后在按顺序分配

3. offset

消费者组+topic+partition,唯一确定一个offset

3.1. 保存位置

  • 0.9之前:默认将 offset 保存在 Zookeeper
  • 0.9开始:默认将 offset 保存在 Kafka 一个内置topic,叫__consumer_offsets中

3.2. 如何查看

高效读写

  • 顺序写磁盘
  • 零拷贝

事务

为了实现跨分区会话事务,引入了TransactionID,其与PID绑定,当生产者重启后,可以通过它找回原先的PID

__consumer_offsets

由于 zookeeper 不擅长大批量的频繁写操作,kafka_1.0.2 将 consumer 的位移信息保存在内部的 topic 中,即 __consumer_offsets ,并提供了 kafka_consumer_groups.sh 脚本供用户查看 consumer 信息