1.kafka集群中的controller、rebalance、HW
1.controller
- 集群中谁来充当controller
每个broker启动时会向zk创建一个临时序号节点,获得的序号最小的的那个broker将会作为集群中的controller,负责这么几件事: - 当集群中有一个副本的leader挂掉,需要在集群中选举出一个新的leader,选举的规则是从isr集合中最左边获得。
- 当集群中有broker新增或减少,controller会同步信息给其他broker
- 当集群中有分区新增或减少,controller会同步信息给其他broker
2.Rebalance机制
- **前提:**消费组中的消费者没有指明分区来消费
- 触发的条件:当消费组中的消费者和分区的关系发生变化的时候
- 分区分配的策略:在rebalance之前,分区怎么分配会有这么三种策略
- orange:根据公示计算得到每个消费消费哪几个分区:前面的消费者是分区总数/消费者数量+1,之后的消费者是分区总数消费者数量sum/n+1 sum是分区数,n是消费者数。如果消费者是3个
消费者消费分区数量关系图
消费者/分区 | 消费者1 | 消费者2 | 消费者3 |
---|---|---|---|
7分区 | 3(p0,p1,p2) | 2(p3,p4) | 2(p5,p6) |
8分区 | 3(p0,p1,p2) | 3(p3,p4,p5) | 2(p6,p7) |
9分区 | 3(p0,p1,p2) | 3 (p3,p4,p5) | 3(p6,p7,p8) |
10分区 | 4(p0,p1,p2,p3) | 3 (p4,p5,p6) | 3(p7,p8.p9) |
- 轮询:大家轮着来(按照分区1到 n ,一个一个轮询,出发rebalance后,之前的分配关系取消,重新再来一遍)
- sticky:粘合策略,如果需要rebalance,会在之前已分配的基础上调整,不会改变之前的分配情况。如果这个策略没有开,那么
就要进行全部的重新分配。建议开启。
3.HW和LEO
LEO是某个副本最后消息的消息位置(log-end-offset)
HW是已完成同步的位置。消息在写入broker时,且每个broker完成这条消息的同步后,hw才会变化。在这之前消费者是消费不到条
消息的。在同步完成之后,HW更新之后,消费者才能消费到这条消息,这样的目的是防止消息的丢失。
2、Kafka线上问题优化
1.如何防止消息丢失
生产者:
- 使用同步发送
- 把ack设成1或者all,并且设置同步的分区数>=2
消费者: 把自动提交改成手动提交
2.如何防止消息的重复消费
在防止消息丢失的方案中,如果生产者发送完消息后,因为网络抖动,没有收到ack,但实际上broker已经收到了。此时生产者会进行重试,于是broker就会收到多条相同的消息,而造成消费者的重复消费。
怎么解决:
- 生产者关闭重试:会造成丢消息(不建议)
- 消费者解决非幂等性消费问题:
所谓的幂等性:多次访问的结果是一样的。对于rest的请求(get(幂等)、post(非幂等)、put(幂等)、delete(幂等))
解决方案:
。在数据库中创建联合主键,防止相同的主键 创建出多条记录
。使用分布式锁,以业务id为锁。保证只有一条记录能够创建成功
3.如何做到顺序消费
- 生产者:保证消息按顺序消费,且消息不丢失一-使用同步的发送,ack设置成非0的值。
- 消费者:主题只能设置一个分区,消费组中只能有一个消费者
kafka的顺序消费使用场景不多,因为牺牲掉了性能,但是比如rocketmg在这一块有专门的功能已设计好。
4.解决消息积压问题
1)消息积压问题的出现
消息的消费者的消费速度远赶不上生产者的生产消息的速度,导致kafka中有大量的数据没有被消费。随着没有被消费的数据堆积越多消费者寻址的性能会越来越差,最后导致整个kafka对外提供的服务的性能很差,从而造成其他服务也访问速度变慢,造成服务雪崩。
2)消息积压的解决方案
- 在这个消费者中,使用多线程,充分利用机器的性能进行消费消息。
- 通过业务的架构设计,提升业务层面消费的性能。
- 创建多个消费组,多个消费者,部署到其他机器上,一起消费,提高消费者的消费速度
- 创建一个消费者,该消费者在kafka另建一个主题,配上多个分区,多个分区再配上多个消费者。该消费者将po下来的消息,不进行消费,直接转发到新建的主题上。此时,新的主题的多个分区的多个消费者就开始一起消费了。-不常用