消息队列:Kafka常见问题

Kafka如何保证全链路消息不丢失,kafka如何实现高性能、高吞吐

全链路保证消息不丟失

生产端

数据丢失场景:为了提高吞吐量,生产端异步发送消息的情况下,会先存储再本地缓存中,当缓冲区大小、时间间隔到达会触发send操作,发送消息;

  1. 生产端宕机,会导致缓冲区的数据丢失;
  2. ACK策略过低;(网络因素)

方案:

  • 数据一致性要求高,使用同步发送消息:最少一次的实现;
  • 生产端使用Kafka事务消息;保证精准一次;
  • 存储到中间介质,如:发送失败的消息转储,另外进行重试(前提实现幂等Kafka事务);或告警;
  • ACK策略采用 >= 1

kakfa服务端

服务端消息丢失场景:

Kafka是异步落盘:kafka接收到消息,只要数据写入PageCache中,就会返回ACK,不需要等待落;如果pageCache落盘前宕机,会发生消息丢失的现象;概率很小;

解决:服务端保证消息可靠一般通过副本机制:

  • 可用选择落盘策略,降低这两个参数,提高数据一致性:
    • log.flush.interval.messages = 10000
      ,设置多少条消息,触发一次刷盘操作;
    • log.flush.interval.ms = 10000
      :间隔多少时间,触发刷盘;
  • 增加ISR副本数:
    min.insync.replicas
    >= 2;

消费端

消息丢失场景:消费失败 + 自动提交机制,是基于一定的时间间隔,异步自动提交数据;

解决

  • 使用手动提交,并且将消费逻辑和手动提交绑定在一个事务中,保证原子性;只有消费成功才提交offset;可用做到:最少一次
    • enable.auto.commit = false
  • 要实现精确一次,还需保证幂等;

Kafka的高性能

1. Parition的并行消费

当消费者数量对应Partition数量,可以达到最大消费速率;

可以增加Partition数量,横向扩展并行度;

2. 生产消费批处理

批量发送 和 批量拉取极大提升吞吐量;

3. 零拷贝技术

减少数据拷贝次数,线程上下文切换次数;

  • 索引文件:mmap + write;通常是消费端指定offset读取时用到;
  • 消息文件:sendfile;通过索引,找到消息后,通过sendfile发送消息;

4. 顺序写/顺序读/磁盘预读

  • 顺序写只需要数据写入时间,减少寻道、磁头旋转时间
  • 大量利用page cache,写数据不需要真正写入磁盘
  • 读操作可以利用磁盘预读,连续读取多个页面,减少磁盘IO;

5. 高效存储:稀疏索引 + 二分搜索

二分搜索 + 稀疏索引 实现高效查询操作(通过时间戳和offset)

  • 通过时间戳和offset 进行二分搜索;
  • 稀疏索引:多条消息才会生成一个索引;

6. 消息压缩

消耗一定的CPU,提高网络传输效率,提高吞吐量;

  • 生产端可用通过配置:
    compression.type = gzip
    对消息进行单个或批量压缩;减少数据大小;
  • 生产端同样配置有压缩算法;当与生产端压缩算法相同,则不需要解压缩,并且能够用到零拷贝;
    • 当压缩算法不一致,就需要对数据进行解压,再次压缩,势必需要将数据拷贝到用户空间进行处理;
    • 当压缩算法一致,不需要对消息进行额外处理,
  • 消费端直接拉取压缩的数据,在客户端进行解压缩;