如何系列 如何确保Kafka消息可靠性/防止消息丢失

文章目录

从Kafka架构来看,理论上仍有消息丢失的可能性,但实际发生的概率极低,只有在所有副本的机器都宕机时才会丢失。

当所有代理(broker)都确认消息时,这并不意味着消息已经存储在磁盘上,而是仍在代理的内存中。这可能成为一个问题,特别是在所有代理服务器同时down的情况下。如果所有代理都位于同一可用区,这种情况更有可能发生,这是最糟糕的设计实践之一。

因此,尽管Kafka的设计大大降低了消息丢失的概率,但完全避免消息丢失是不可能的。

Producer
  • 使用回调通知,不要使用producer.send(msg),而要使用producer.send(msg, callback)。记住,一定要使用带有回调通知的send方法。回调可以帮助你在消息发送失败时捕获异常并进行处理。

    java 复制代码
    producer.send(new ProducerRecord<>("topic", "key", "value"), new Callback() {
        public void onCompletion(RecordMetadata metadata, Exception exception) {
            if (exception != null) {
                // 处理异常
            }
        }
    });
  • 设置acks = all。acks是Producer的一个参数,代表了你对"已提交"消息的定义。如果设置成all,则表明所有副本Broker都要接收到消息,该消息才算是"已提交"。这是最高等级的"已提交"定义。

    一旦领导者收到来自同步副本的确认,告诉他们已经复制了消息,它就会将确认发送回生产者。这保证了只要至少一个同步副本保持活动状态,记录就不会丢失。

    java 复制代码
    props.put("acks", "all");
  • 设置重试机制,设置retries为一个较大的值。这里的retries同样是Producer的参数,对应前面提到的Producer自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了retries > 0的Producer能够自动重试消息发送,避免消息丢失。

  • 启用幂等性 ,设置enable.idempotence 为 true 来启用幂等生产者。这可以防止重试期间出现重复,确保从生产者的角度来看,消息只传送到代理一次。

  • 设置交付超时时间 ,设置 delivery.timeout.ms 用于设置所有重试的超时时间。因此,如果 retries 是一个很大的数字,但超时很短,消息传递无论如何都会失败。

    java 复制代码
    props.put("delivery.timeout.ms", "120000");  // 2分钟
Broker
  • 禁用非干净的领导者选举 ,设置unclean.leader.election.enable = false。这是Broker端的参数,它控制的是哪些Broker有资格竞选分区的Leader。如果一个Broker落后原先的Leader太多,那么它一旦成为新的Leader,必然会造成消息的丢失。故一般都要将该参数设置成false,即不允许这种情况的发生。

    防止落后太多的 Broker 选举为 Leader,从而避免消息丢失。

  • 配置副本数量 ,设置replication.factor >= 3。这也是Broker端的参数。其实这里想表述的是,最好将消息多保存几份,毕竟目前防止消息丢失的主要机制就是冗余。副本replica总数,包括Leader和Follower

  • 设置最小同步副本数 ,设置min.insync.replicas > 1。这依然是Broker端参数,控制的是消息至少要被写入到多少个副本才算是"已提交"。设置成大于1可以提升消息持久性。在实际环境中千万不要使用默认值1。min.insync.replicas只有在acks=-1(all)时才生效

  • 确保副本数量大于最小同步副本数 ,确保replication.factor > min.insync.replicas。如果两者相等,那么只要有一个副本挂机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要在不降低可用性的基础上完成。

    推荐设置成replication.factor = min.insync.replicas + 1。

Consumer
  • 确保消息消费完成再提交。Consumer端有个参数enable.auto.commit,最好把它设置成false,并采用手动提交位移的方式。

维持先消费消息(阅读),再更新位移(书签)的顺序

  • 使用 commitSync ;为了更好的性能,使用 commitAsync ,如果处理和提交之间发生故障,可能会出现重复。
流程

当设置 acks=all 并且生产者调用 send() 方法时,它会等待领导者的确认。一旦领导者收到来自同步副本的确认,并告知它们已经复制了消息,领导者将把确认发送回给生产者。

属性 min.insync.replicas 指定了在领导者向客户端发送确认之前必须确认的最小副本数。如果未达到这个最小值,生产者将抛出异常(例如 NotEnoughReplicas 或 NotEnoughReplicasAfterAppend)。

在典型场景中,如果创建一个复制因子为 3 的主题,并将 min.insync.replicas 设置为 2,并使用 acks=all,这将确保只有在大多数副本都写入成功时生产者才会确认消息提交。

当生产者在设定的 request.timeout.ms 时间内未收到确认时,它将会重新发送消息,间隔时间由 retry.backoff.ms 定义。生产者将根据设定的 retries 次数重试发送失败的消息。

另外,属性 delivery.timeout.ms 定义了调用 send() 后返回成功或失败的时间上限。

在达到最大重试次数后,如果消息仍未能成功记录,或出现其他异常情况,可以考虑将消息保存到其他数据存储。这可以通过在 send() 方法中设置回调来处理,在此类错误情况下会触发回调函数。

这些属性和机制确保了在不同网络和节点故障情况下,Kafka生产者能够尽可能地保证消息的可靠性和最终一致性。

相关推荐
黄俊懿11 小时前
【架构师从入门到进阶】第六章:服务集群优化——第八节:线程数公式
java·服务器·数据库·分布式·性能优化·架构·系统架构
大菠萝爱上小西瓜13 小时前
基于 Spark + Iceberg 湖仓一体的 Netflix 流媒体用户行为全链路数仓与 ALS 智能推荐决策系统(含穿透下钻大屏)
大数据·分布式·spark
吴建旭 智宅焕13 小时前
智能家居售后服务体系的架构设计:分布式售后风险的集中式兜底方案
分布式·智能家居
lisanmengmeng1 天前
Ganglia分布式集群监控系统安装手册
分布式
我不会起名字3221 天前
Kafka 分区数到底设几个:吞吐量、顺序性与 rebalance 代价的取舍
kafka·消息队列·调优·分区
Smoothcloud润云1 天前
GPU算力平台推荐:新手租GPU时,镜像环境和显存应该怎么选?
大数据·人工智能·pytorch·分布式·深度学习·gpu算力
程序员大阳1 天前
副队长大数据教程(6)--四节点分布式集群搭建
大数据·分布式·集群·搭建·四节点
马六六i1 天前
目前知名的分布式Ai数智共享商城哪家好
人工智能·分布式
大鹏说大话1 天前
分布式事务怎么选型?2PC、TCC、SAGA、本地消息表一次讲清
分布式
Eloudy1 天前
ASTRA-sim 3.0:通过高保真GPU和基础设施建模进行下一级分布式机器学习模拟
人工智能·分布式·机器学习