Kafka学习笔记(5)——消息队列

消息丢失

可能发生消息丢失的环节:

  • 生产者投递消息, 因为网络波动等原因, 没有发送成功;
  • 消费者消费消息, 消费者未处理完消息就宕机, 消息没有成功消费;
  • 分区中的Leader所在的Broker宕机, Leader的数据在同步到Follower前的这段时间内的消息丢失;

解决方案:

  • 生产者: 使用带有返回值的消息发送方式, 通过callback得知消息是否发送成功, 如果发送失败进行重发;
  • 消费者: 开启手动提交, 先消费消息, 再更新offset;
  • Broker: 调整分区的Replica数量, 调整acks参数.

消息重复消费

发生重复消费的场景: 已经消费了消息, 但是offset没有提交. 产生的原因:

  • 消费者消费完消息, 还没有提交offset, 消费者线程就被强制kill掉;
  • 消费者消费消息耗时过长, 超过了timeout, 与分区断开连接, 并且offset没有提交, 触发Rebalance后重复消费;

解决方案:

  • 在有消费者线程的应用中, 尽量避免kill -9等操作;
  • 合理设置max.poll.interval.msmax.poll.records, 提高消费者处理消息的速度;
  • 对消费的接口幂等处理, 例如设置唯一id等方式达到单次和多次操作达到一样的效果.

消息顺序消费

同一个Partition内的消息能保证消费的顺序性, 但不同Partition之间不能保证顺序.

解决方案: 发送消息时指定分区, 需要顺序消费的消息发送到同一分区.

消息积压

可能产生消息积压的场景:

  • 消费者宕机, 在重新启动消费者服务前, 数据量很大, 造成消息挤压;
    • 解决方案1: 消费者服务重启后直接消费最新的消息, 积压的旧消息通过离线程序补漏;
    • 解决方案2: 增大消费者的处理能力, 从上次提交offset处开始消费.
  • Kafka分区不合理, 通常是分区太少, 导致消费能力不足;
    • 解决方案: 适当增加分区数.
  • Kafka消息的key不均匀, 分区数据不平衡;
    • 解决方案: 生产者给key增加随机后缀, 使其均衡.

Kafka 高性能的原因

顺序写

Kafka虽然是写磁盘, 但因为顺序写, 直接追加数据到末尾, 性能极高.

零拷贝

Kafka高吞吐量的原因: 零拷贝. 主要是利用Java NIO中FileChannel的transferTo方法.

传统IO实际经过4次文件内容复制:

  1. 将磁盘文件数据copy到操作系统内核buffer;
  2. 将内核buffer的数据copy到应用程序的buffer;
  3. 将应用程序buffer中的数据copy到socket buffer;
  4. 将socket buffer中的数据copy到网卡buffer进行网络传输.

零拷贝只有两次复制:

  1. 将磁盘文件数据copy到操作系统内核buffer;
  2. 将内核buffer的数据copy到网卡buffer进行网络传输.