Kafka 开发相关问题

版权声明:欢迎转载,转载请说明出处. 大数据Github项目地址https://github.com/SeanYanxml/bigdata。 https://blog.csdn.net/u010416101/article/details/89791986

前言

本章记录下Kafka在使用过程中的相关问题.
数据量: 5000-2W条/分钟.


相关问题

  • 数据丢失&数据重发
    发送数据端, 在压力过大的时候, 又可能出现数据丢失的情况. 这时可以启动Kafka的重发机制. 极端情况, 可以将判断值调成99999, 这样Kafka一旦出现消息发送错误, 就会无限制的重复发送.
    此外, 还可以通过记录日志的情况. 将数据发送失败的数据通过异常记录下来.

  • 数据重复发送
    数据重复发送, 这个问题是因为数据重发导致的. 数据发送后,由于网络IO延迟,Kafka端并未收到消息, 数据会进行重发. 但是之前的消息其实发送成功了, 这样便导致Kafka端接收到两条相同的消息. 这么说还是有点抽象, 我们通过如下流程详细表示:

Step1: Producer向Kafka集群发送消息A-1;
Step2: Kafka端并未收到消息;
Step3: Producer未收到Kafka集群的响应, 重发时间已到, 重新发送消息A-2;
Step4: Kafka端收到消息A-1,A-2, 写入并发送回应;
Step5: Producer端收到消息, 不在重发;

这样的情况, 可以通过幂等方式在消费时进行避免. 比如: 使用唯一ID, 这样数据消费的时候会将其认为是同一条消息.

  • 数据消费丢失
    在消费端, 突然停电. 会导致部分消息丢失. 这么说比较抽象, 举个例子:
Step1: Kafka内 offset为 100;
Step2: 消费端消费100条消息, 正在计算;
Step3: 由于消费端消费数据, Kafka内 offset为 200;
Step4: 消费端进程突然被杀死, 电脑突然断电;
Step5: 其中100-200这部分数据就会丢失.

OK, 上方的流程就是我们经常会遇到的数据丢失. 这样的情况如何解决? 答案也非常简单, 手动控制ACK结点的提交. 我们可以在数据完成后, 再去更新offset.

流程变成这样:

Step1: Kafka内 offset为 100;
Step2: 消费端消费100条消息, 正在计算;
Step3: 由于消费端消费数据. 但是并为返回提交值, Kafka内 offset并不会改变, 仍然为100;
Step4: 消费端进程突然被杀死, 电脑突然断电;
Step5: 消费端重新启动, 仍然拉取100条数据,进行处理, 处理结束;
Step6: Kafka内Offset置为200.
  • 数据消费重复
    数据重复消费有两种情况: 1. Kafka内的标示位错误导致; 2. 数据内有重复数据.
    对于第二种情况, 我们之前已经说过. 使用幂等的方式. 给每一条记录, 设置一个独立的ID即可.
    对于第一种情况, 通过上方的手动控制ACK提交即可. (Kafka这边有的时候网络IO延迟时候, 会导致这种抽风问题.)

  • 数据顺序性
    数据的顺序性, 是Kafka的最难的地方. 网上给出的答案是: 单个Topic, 单个Producer.
    这就是扯淡! 这完全浪费了Kafka的设计原理背道而驰.

Kafka内不需要消息的完全顺序性, 只要做到局部的顺序性即可. 通过Hash槽思想即可做到.

前提条件1: 每个消息都有两种一种是: 生成订单, 一个是完成订单.
前提条件2: Kafka端有1个Topic, 这个Topic有2个Partition, 分别为Partition1 和 Partition2.
Step1: Producer发送消息, 消息的订单号为1, 记录唯一ID为1-123(时间戳 随便写一个)
通过Hash算法, 消息1-123发送到Partition1内.
Step2: Producer发送消息, 消息的订单号为2, 记录唯一ID为2-145(时间戳 随便写一个)
通过Hash算法, 消息2-145发送到Partition2内.
Step3: Producer发送消息, 消息的订单号为3, 记录唯一ID为3-146(时间戳 随便写一个)
通过Hash算法, 消息3-146发送到Partition1内.
Step4: Producer发送消息, 消息的订单号为1, 记录唯一ID为1-147(时间戳 随便写一个)
通过Hash算法, 消息1-147发送到Partition1内.
Step5: Producer发送消息, 消息的订单号为2, 记录唯一ID为2-148(时间戳 随便写一个)
通过Hash算法, 消息2-148发送到Partition2内.
Step6: Producer发送消息, 消息的订单号为3, 记录唯一ID为3-149(时间戳 随便写一个)
通过Hash算法, 消息3-149发送到Partition1内.

OK, 发送消息流程结束. 让我们看下两个Partion里面的消息;

Partion1:
消息1-123
消息3-146
消息1-147
消息3-149
Partion1:
消息2-145
消息2-148

分别启动两个Consumer来进行消费.
Consumer1消费-Topic1
Conusmer2消费-Topic2

这样就可以实现局部有序了. 这个方法是我之前的领导讲给我听的, 大赞.

这样做是参考了Hash槽的分片做法. 不懂的读者可以了解小Hash槽.

另外值得一提的是, 如果是重复导致的数据顺序错乱. 比如两个操作:<1001-开始><1001-结束>因为数据延迟重发导致的数据顺序错乱如何解决?

个人认为首先有2种解决办法:

  1. 数据在处理的时候重排序. 这种方式适用于数据量较小, 间隔较小的情况;
  2. 开始单独放在一个Partion里面, 关闭放在一个Partition里面. (分成两个Topic也可以.)
  3. 如果有更好的解决办法, 不妨在评论处告诉我.

注: 步骤用文字表示还是有点抽象, 有时间换成甘特图进行描述.
有人有可能不知道为什么Kafka是无序的, 这个我后续补充下.


Reference

[1]. 消息队列常见问题和解决方案
[2]. 消息队列顺序
[3] 不推荐做法
[4] 分布式服务接口的幂等性如何设计
[5] mq如何保证消息的幂等性
[6] (很通用)什么是分布式系统中的幂等性
[7] 什么是幂等,什么情况下需要幂等,如何实现幂等
[8] 解决方案:如何防止数据重复插入?

展开阅读全文

没有更多推荐了,返回首页