1. kafka消息架构
1.1. 生产者消息分区机制原理剖析
Kafka轮询策略:轮询策略是Kafka Java生产者API默认提供的分区策略。如果你未指定partitioner.class参数,那么你的生产者程序会按照轮询的方式在主题的所有分区间均匀地“码放”消息, 轮询策略有非常优秀的负载均衡表现,它总是能保证消息最大限度地被平均分配到所有分区上,故默认情况下它是最合理的分区策略,也是我们最常用的分区策略之一。
随机策略:也称Randomness策略。所谓随机就是我们随意地将消息放置到任意一个分区上.
- 按消息键保序策略:
1.2. 生产者压缩算法
在生产者启用压缩算法,使用gzip压缩,生产者端启用压缩,在Broker端也可能进行压缩
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 开启GZIP压缩
props.put("compression.type", "gzip");
Producer<String, String> producer = new KafkaProducer<>(props);
总结:Producer端压缩、Broker端保持、Consumer端解压缩
1.3. 如何配置Kafka无消息丢失
一句话概括,Kafka只对“已提交”的消息(committed message)做有限度的持久化保证
Producer永远要使用带有回调通知的发送API,也就是说不要使用producer.send(msg),而要使用producer.send(msg, callback)
解决消费者程序丢失数据:维持先消费消息,再更新位移的顺序。
如果是多线程异步处理消费消息,Consumer程序不要开启自动提交位移,而是要应用程序手动提交位移
总结:最佳实践
- 不要使用producer.send(msg),而要使用producer.send(msg, callback)。记住,一定要使用带有回调通知的send方法
- 设置acks = all。acks是Producer的一个参数,代表了你对“已提交”消息的定义。如果设置成all,则表明所有副本Broker都要接收到消息,该消息才算是“已提交”。这是最高等级的“已提交”定义。
- 设置retries为一个较大的值。这里的retries同样是Producer的参数,对应前面提到的Producer自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了retries > 0的Producer能够自动重试消息发送,避免消息丢失
- 设置unclean.leader.election.enable = false
- 设置replication.factor >= 3。这也是Broker端的参数。其实这里想表述的是,最好将消息多保存几份,毕竟目前防止消息丢失的主要机制就是冗余
- 设置min.insync.replicas > 1。这依然是Broker端参数,控制的是消息至少要被写入到多少个副本才算是“已提交”。设置成大于1可以提升消息持久性。在实际环境中千万不要使用默认值1。
- 确保replication.factor > min.insync.replicas。如果两者相等,那么只要有一个副本挂机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要在不降低可用性的基础上完成。推荐设置成replication.factor = min.insync.replicas + 1
- 确保消息消费完成再提交。Consumer端有个参数enable.auto.commit,最好把它设置成false,并采用手动提交位移的方式。就像前面说的,这对于单Consumer多线程处理的场景而言是至关重要的。
1.4. Kafka拦截器
Kafka拦截器分为生产者拦截器和消费者拦截器
Kafka拦截器可以应用于包括客户端监控、端到端系统性能检测、消息审计等多种功能在内的场景
1.5. Java生产者是如何管理TCP连接的
- KafkaProducer实例创建时启动Sender线程,从而创建与bootstrap.servers中所有Broker的TCP连接
- KafkaProducer实例首次更新元数据信息之后,还会再次创建与集群中所有Broker的TCP连接
- 如果Producer端发送消息到某台Broker时发现没有与该Broker的TCP连接,那么也会立即创建连接。
- 如果设置Producer端connections.max.idle.ms参数大于0,则步骤1中创建的TCP连接会被自动关闭;如果设置该参数=-1,那么步骤1中创建的TCP连接将无法被关闭,从而成为“僵尸”连接。
Producer端关闭TCP连接的方式有两种:一种是用户主动关闭;一种是Kafka自动关闭。
1.6. Kafka消息交付可靠性保障以及精确处理一次语义的实现。
- 最多一次(at most once):消息可能会丢失,但绝不会被重复发送。
- 至少一次(at least once):消息不会丢失,但有可能被重复发送。
- 精确一次(exactly once):消息不会丢失,也不会被重复发送。
kafka默认提供的交付可靠保障是第二针:至少一次。
Kafka如何做到精确一次的消息交付:这是通过两种机制:幂等性(Idempotence)和事务(Transaction)
幂等性Producer只能保证单分区、单会话上的消息幂等性;而事务能够保证跨分区、跨会话间的幂等性。从交付语义上来看,自然是事务型Producer能做的更多。
1.7. 消费者组到底是什么
1.8. Kafka中位移提交那些事儿
Kafka Consumer的位移提交,是实现Consumer端语义保障的重要手段。位移提交分为自动提交和手动提交,而手动提交又分为同步提交和异步提交。在实际使用过程中,推荐你使用手动提交机制,因为它更加可控,也更加灵活。另外,建议你同时采用同步提交和异步提交两种方式,这样既不影响TPS,又支持自动重试,改善Consumer应用的高可用性。总之,Kafka Consumer API提供了多种灵活的提交方法,方便你根据自己的业务场景定制你的提交策略。
1.9. Kafka副本机制详解
所谓的副本机制(Replication),也可以称之为备份机制,通常是指分布式系统在多台网络互联的机器上保存有相同的数据拷贝。副本机制有什么好处呢?
- 提供数据冗余。即使系统部分组件失效,系统依然能够继续运转,因而增加了整体可用性以及数据持久性。
- 提供高伸缩性。支持横向扩展,能够通过增加机器的方式来提升读性能,进而提高读操作吞吐量。
- 改善数据局部性。允许将数据放入与用户地理位置相近的地方,从而降低系统延时。