严格消费顺序、无消息丢失的Kafka配置

强可靠的Kafka配置

​ 前段时间做了一次基于binlog的数据同步,由于binlog的场景需要严格的顺序性和可靠的消息存储,所以基于Kafka好好的研究了一下相关配置


1.强可靠的含义

我目前的场景需要MQ能够做到无消息丢失、严格顺序消费,但是Kafka的默认配置是走吞吐量的,所以在配置上牺牲了Kafka的可用性和性能来尽可能的增强了顺序消费的特点,最终使得Kafka集群的特性为以下四点:
可靠存储、严格顺序、低可用、低性能
我称之为强可靠Kafka,要做到强可靠,不仅需要Kafka集群的配置更改,同时也要生产者和消费者共同努力才能实现,接下来讲具体细节。

2.Kafka集群配置

更改在kafka集群中的配置(config/server.properties ),以下是对于强可靠比较重要的参数,其他的仍保持默认配置,总体来说就是牺牲了kafka本来的性能和可用性来换取消息不丢失,经过以下配置后,三台Kafka集群只能容忍一台broker发生故障。

  1. num.partitions=1
    kafka只保障了单个分区内消息消费的有序性,所以这里分区数设为1
  2. unclean.leader.election.enable=false
    非ISR的broker无法成为leader,损失了可用性来保障可靠的消息存储。
  3. offsets.topic.replication.factor=3
  4. min.insync.replicas=2
    topic副本数设置为3,并且ISR设置最小两个存活,含义为最多允许有一个broker宕机,kafka仍能保证消息不会丢失并正常提供服务。
    损失了可用性来保障可靠的消息存储。
  5. log.retention.hours=720
    消息保留最大时间30天,防止意外情况发生时能够回溯
  6. log.flush.interval.ms=3000
    消息每3S刷盘一次,kafka收到消息会先写入pageCache而不会直接落盘,每3S强制刷新一次,最极端的情况下也只会丢失3S的消息。损失了吞吐量来保障可靠的消息存储。

3.生产者配置

在生产端同样要进行配置项更改,这里主要是为了进行严格顺序的控制,严格顺序消费需要生产者和消费者的共同努力。
以下是总体的生产者代码配置

		props.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION, 1);
		props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);

		// 发送重试
		props.put(ProducerConfig.RETRIES_CONFIG, 100);
		props.put(ProducerConfig.RETRY_BACKOFF_MS_CONFIG, 500);

		// 发送缓存区配置
		props.put(ProducerConfig.BATCH_SIZE_CONFIG, 128);
		props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 1024 * 1024 * 50);
		props.put(ProducerConfig.LINGER_MS_CONFIG, 500);

		props.put(ProducerConfig.ACKS_CONFIG, "all");

每项的具体含义如下

  1. acks=all
    所有副本收到消息后才认为消息发送成功,损失了吞吐量来保障可靠的消息存储。
  2. enable.idempotence=true
    在消息发送端确保消息不会重发,防止消息重发带来消息顺序错乱的问题。
  3. max.in.flight.requests.per.connection=1
    只能有一个批次在进行发送消息的操作,损失了吞吐量来严格顺序性。
  4. retries=0
    消息发送的重试次数,这个不能设置重试,因为发生重试会将消息进行重新投递,打乱顺序性。
  5. retry.backoff.ms=500
    每次重试的阻塞时间
  6. batch.size
  7. buffer.memory
  8. linger.ms
    该三个参数修改了每个批次的消息容量和发送间隔,主要与消息发送的吞吐量有关,自行确认修改

4.消费者配置

消费者在消费时也要更改相关的操作,来进行消息顺序消费的保障,并且由于原生的kafka消费者没有消费重试和死信队列的配置,所以这里引入了spring-kafka。以下是消费端的代码配置

	@Bean
	public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
		ConcurrentKafkaListenerContainerFactory<String, String> factory =
				new ConcurrentKafkaListenerContainerFactory<>();
		factory.setConsumerFactory(consumerFactory());
		factory.setMissingTopicsFatal(false);
		factory.setConcurrency(1);
		factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL);
		// 设置重试
		factory.setErrorHandler(new SeekToCurrentErrorHandler(new FixedBackOff(600L, 8)));
		return factory;
	}

	@Bean
	public ConsumerFactory<String, String> consumerFactory() {
		return new DefaultKafkaConsumerFactory<>(consumerConfigs());
	}

	@Bean
	public Map<String, Object> consumerConfigs() {
		Map<String, Object> props = new HashMap<>(16);
		props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "xxxx:9092");
		props.put(ConsumerConfig.GROUP_ID_CONFIG, "ha-test");
		props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
		props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 30000);

		// 消费者最重要参数 控制拉取消息的间隔
		props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 20000);
		props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 50);

		props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
		props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
		return props;
	}

比较关键的地方就是要设置手动提交setAckMode(ContainerProperties.AckMode.MANUAL),手动提交是顺序消费的必要条件。
另一个就是spring-kafka附加的消费重试配置,可以解决一部分消息消费丢失的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值