博客
关于我
Kafka Producer机制优化-提高发送消息可靠性
阅读量:710 次
发布时间:2019-03-21

本文共 2985 字,大约阅读时间需要 9 分钟。

Kafka消息发送失效转移的解决方案

背景

在Kafka集群中,消息生产者(Producer)在构造消息时,会传入一个key参数。在消息发送过程中,Producer会根据key确定目标Partition。当某个Partition的所有活跃节点(Broker)失效或挂掉时, Producer会尝试以MaxSendRetries(默认值3次)为上限重发送消息, 每次发送之间会Sleep(默认值100ms)。最终, 如果所有重发送都失败, Producer会抛出异常,导致消息发送进度阻塞或本地发送缓存的消息丢失。这种情况下,消息的可靠性和可用性会受到严重影响。


解决思路

为了解决上述问题,我们可以在Kafka中保持默认的消息发送方式,同时为用户提供一个可选的开关,实现消息发送失效转移。当Producer发送消息到目标Partition的所有副本节点均失效时,消息可以转移到其他Partition,依靠Kafka的集群通信机制,最终将消息发送到其他活跃节点上。这种方式能够在失效恢复之前,确保消息不会被丢失,同时避免了消息发送进度的阻塞。

在实现方案中,Partition被分为两种角色:

  • M(Master):即Partition的主分区,负责消息的写入和读取。
  • S(Slave):即Partition的副本分区,与主分区保持数据一致。

消息在发送过程中,会按照一定规则轮询发送到不同的Partition(如0到3)。当某个目标Partition的所有活跃节点全部失效时,消息会自动转移到其他有效的Partition,依赖Kafka集群的自我恢复机制,直到失效的Broker恢复为止。


Producer代码修改

为实现上述功能,我们需要对Kafka的ProducerConfig进行相应的修改。以下是关键步骤:

  • 首先,在ProducerConfig类中,引入新的配置参数:

    val sendSwitchBrokerEnabled = props.getBoolean("send.switch.broker.enable", false)
  • DefaultEventHandler.scala类中,添加以下代码:

    val isSendSwitchBrokerEnabled = config.sendSwitchBrokerEnabled
  • 最后,在getPartition方法中进行如下修改:

    private def getPartition(topic: String, key: Any, topicPartitionList: Seq[PartitionAndLeader], isSendSwitchBrokerEnabled: Boolean) = {    val numPartitions = topicPartitionList.size    if (numPartitions <= 0) {        throw new UnknownTopicOrPartitionException("Topic $topic doesn't exist")    }    var partition = if (key == null) {        val id = sendPartitionPerTopicCache.get(topic)        id match {            case Some(partitionId) =>                partitionId            case None =>                val availablePartitions = topicPartitionList.filter(_.leaderBrokerIdOpt.isDefined)                if (availablePartitions.isEmpty) {                    throw new LeaderNotAvailableException("No leader for any partition in topic $topic")                }                val index = Utils.abs(Random.nextInt) % availablePartitions.size                val partitionId = availablePartitions(index).partitionId                sendPartitionPerTopicCache.put(topic, partitionId)                partitionId        }    } else {        partitioner.partition(key, numPartitions)    }    if (partition < 0 || partition >= numPartitions) {        throw new UnknownTopicOrPartitionException("Invalid partition id: $partition for topic $topic; Valid values are in the inclusive range of [0, $including...]")    }    if (isSendSwitchBrokerEnabled) {        if (!partitionsLeaderInTopicsCache.containsKey(TopicAndPartition(topic, partition))) {            val availablePartitions = topicPartitionList.filter(_.leaderBrokerIdOpt.isDefined)            if (availablePartitions.isEmpty) {                throw new LeaderNotAvailableException("No leader for any partition in topic $topic")            }            val index = Utils.abs(Random.nextInt) % availablePartitions.size            partition = availablePartitions(index).partitionId        }    }    partition}

  • 总结

    通过上述方法,我们增加了消息发送的鲁棒性,确保了在Broker失效时,消息能够自动转移到其他活跃的Partition,最大限度地减少消息丢失和发送进度阻塞的风险。这一解决方案既保持了Kafka的核心特性,又通过可配置的开关,满足了用户对消息可靠性的需求。

    转载地址:http://qjcrz.baihongyu.com/

    你可能感兴趣的文章
    Mysql 整形列的字节与存储范围
    查看>>
    mysql 断电数据损坏,无法启动
    查看>>
    MySQL 日期时间类型的选择
    查看>>
    Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
    查看>>
    MySQL 是如何加锁的?
    查看>>
    MySQL 是怎样运行的 - InnoDB数据页结构
    查看>>
    mysql 更新子表_mysql 在update中实现子查询的方式
    查看>>
    MySQL 有什么优点?
    查看>>
    mysql 权限整理记录
    查看>>
    mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
    查看>>
    MYSQL 查看最大连接数和修改最大连接数
    查看>>
    MySQL 查看有哪些表
    查看>>
    mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
    查看>>
    MySql 查询以逗号分隔的字符串的方法(正则)
    查看>>
    MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
    查看>>
    mysql 查询数据库所有表的字段信息
    查看>>
    【Java基础】什么是面向对象?
    查看>>
    mysql 查询,正数降序排序,负数升序排序
    查看>>
    MySQL 树形结构 根据指定节点 获取其下属的所有子节点(包含路径上的枝干节点和叶子节点)...
    查看>>
    mysql 死锁 Deadlock found when trying to get lock; try restarting transaction
    查看>>