:::warning kafka是什么? ::: kafka是apache开源的、高吞吐量的、分布式的、消息发布订阅系统。
    为什么没说是是消息队列,因为kafka并不是安装AMQP协议进行设计的。所以并没有消息队列的一些特性,包括事务消息、失败重投、顺序消费等。

    :::warning kafka的使用场景? ::: 在了解kafka的局限性依然适合业务架构之后,kafka带来的能力就非常有价值了。和普通mq一样,提供:
    1、异步通信
    2、削峰填谷
    3、系统解耦
    还提供:
    1、高吞吐量(10W+TPS)
    2、水平扩展:通过不断增加broker的数量,可以支持更多的topic和性能提升。
    3、高可用性:通过replica机制,可以在可控有损的情况下,提高系统的可用性。

    :::warning kafka的系统架构? ::: kafka从架构角色上来分:
    1、producer:消息生产者。
    2、broker:消息存储、消息复制。
    3、zookeeper:集群信息协调,主要用于leader选取、offset的记录等。
    4、consumer:消息消费者,可以通过group的方式来水平扩展消费能力。

    :::warning kafka的高可用是怎么做的? ::: kafka的使用的时候,可以为一个topic设定需要多少个replica,副本的数量决定的可用性等级。最大不要超过broker数量-1。在topic_partition的维度下,如果有n个副本,那么会根据在zookeeper的抢占注册成功的情况来决定leader,其他都是follower。
    消息进入之后,存储在leader,并返回成功。其他follower定时拉取leader的数据进行备份,并将本次同步后的offset上报给zk,zk会维护一个ISR列表,也就是所有follower的同步水位的情况,用于后续的选主。
    这种pull方式的好处在于replica的数量多少不会影响leader的性能,这里存在一个问题就是一旦leader挂掉那么存在数据丢失。所以如果系统对消息的丢失不可容忍(其实如果不可容忍就不应该选择kafka),那么需要采用另外一种方式,就是找1个或n个replica进行push同步,之后push同步完成后,才返回消息发送成功。随着n的大小,会影响leader的读写性能。所以这就是一种架构上需要的均衡。

    :::warning kafka的选主是怎么处理的? ::: 按上所述,当leader挂掉之后,在ISR列表中的follower都会收到信息(应该是用监听子节点删除的watch机制),于是会和首次启动一样,进行节点抢占注册,成功的为leader。
    那么这里的ISR列表的中的follower是不是就是所有的replica呢?并不是!
    ISR也叫in-sync-replica,就是同步列表,如果某些follower的机器因为某些原因(性能差、网络差、被内部其他进程干扰)导致同步leader的数据慢了,也就是offset和leader的offset相差值过大会被踢出ISR,也就是不参与选主。这个差值是可以配置的。

    :::warning kafka的高吞吐量的原因? ::: 在broker中的存储方式是:

    • cluster ——1:n——-> broker(一个集群包含多个broker)
    • broker ——1:n——-> topic(一个broker可以存储多个topic的数据,包括leader和replica)
    • topic ——1:n——-> partition(一个topic的数据可能被分散到多个broker,也就是partition)
    • partition ——1:n——> log(partition可以拆分成多个log,类似于/topic1/partition_1/0001.log)
    • log ——1:n——> message(一个日志文件会包含多条消息内容,每条消息都有一个唯一offset)

    也即是说kafka是通过追加日志的方式进行数据持久化,我们都知道到追加日志是顺序IO,性能较高。如果了解过mysql的redolog的话,这里还可以再加一步优化,就是开启操作系统的文件缓存,减少fsync带来的性能损耗。再加上现如今的SSD设备发展,kafka的高吞吐量也就不足为奇了。

    :::warning kafka如何进行数据清理? ::: 如上所述,因为是通过日志进行数据持久化,且每条日志都有offset,所以kafka可以通过配置后的过期offset值、过期文件大小、过期时间等方式进行日志文件删除。

    :::warning kafka消费者组是什么? ::: 消费者组是水平扩展消费能力的机制,可以通过不断增加机器来提升消费能力。
    consumer group的数量扩展最多和partition的数量相等,再添加无法达到消费能力扩展的目的。
    消费者组中的多个实例可以【瓜分】topic下leader中的消息数据,这里存在两个问题:

    1. 多个实例之间的offset如何同步?批量获取消息之后,如果消费者组挂掉后,未消费完的消息如何处理?
      1. consumer之间不需要进行offset同步,因为一个partition只能给一个consumer,所以按理说consumer自己管理offset即可,比如存放在内存中。但考虑下面两个场景:一个是rebalance可能将当前partition分配给其他consumer,一个是当前consumer可能重启。这两者都需要将offset持久化保存。
      2. offset的保存方式:在老版本中,这个offset是通过zk保存的。在新版本中,这个offset是通过broker中保存_conusmer_offsets。
      3. offset的保存时机:consumer消费完提交后的offset称为committed offset。但这个提交既不是单条消费完毕提交,页不是把单次poll下来的消息消费完毕提交,而是通过定时进行提交,默认5s。这里存在问题:consumer消费完N条之后,没到5s系统宕机,那么那次会从老的committed offset重新获取进行消费,显然这里就有重复消费的问题。这是在消费的时候必须要考虑的因素,比如业务需要幂等处理,或者通过offset进行去重处理。
        1. 还有一种方式就是利用kafka提供的rebalance监听器,提供rebalance前(停止poll之后)和rebalance后(重新分配partition完成)两个事件监听入口,通过该监听器进行一些操作,比如手动提交offset,并清空剩余的消息。
      4. 如果采用了本地缓存消息的方式进行消息消费,那么还可能出现消息丢失。offset已上报,但是consumer宕机,导致本地缓存丢失。
      5. 还有一种方式是关闭自动提交,业务手动提交(不建议)。
    2. 新建的消费组如何消费?
      1. 这种情况类似于committed offset丢失。
      2. 默认方式是【lastest】,从最新消息开始消费。
      3. 还有【earlist】,从最早开始消费,适用于消息量不大的场景。
      4. 还有【none】,直接抛异常。
    3. consumer节点的扩缩容如何进行partition的重分配?
      1. 消费者组在实例扩缩容时会触发rebalance,rebalance的工作就是暂停所有实例的消费,并对patition和消费者实例的关系进行重新分配映射。类似于JVM的STW。而且是非常耗时的操作。
      2. 消费者实例扩缩容如果是人为触发,比e如机器上下线是可以预料且低频的,还有几种种情况是自动触发。
      3. Coordinator是负责管理Consumer Group的组件,能获取到该组中的实例列表,如果因为网络原因导致消费者没能定时上报,那么zk会将该实例剔出列表,触发rebalance。这种方式是不可预料且如果网络不好的话会触发大量rebalance,导致消费停滞。
      4. 消费者实例会定期poll一批消息进行消费,如果期间没能消费完毕,也会被移出列表,触发rebalance。这个可以通过设置参数增加poll间隔,减少poll数量来降低这种情况的概率。

    :::warning kafka的rebalance机制? ::: 触发时机:

    • 有新的消费者加入Consumer Group
    • 有消费者宕机下线。消费者不一定真的宕机了,比如长时间的GC,网络的延迟导致消费者长时间未向GroupCoordinator发送HeartbeatRequest时,GroupCoordinator会认为消费者下线。
    • 有消费者主动退出Consumer Group(消费能力不足)。
    • Consumer Group订阅的任何一个Topic出现分区数量的变化。
    • 消费者调用unsubscribe()取消对某个Topic的订阅。

    所有Consumer会和Broker保持心跳连接,GroupCoordinator部署在broker上,第一个连接到GroupCoordinator的Consumer是leader,由它向GroupCoordinator发起rebalance请求。

    • Consumer Groups 用于多个Consumer并行消费消息。为了防止两个消费者重复消费一条消息,Kafka不允许同一个Consumer Group中的两个Consumer读取同一个partition(所以offset由实例自己保存)。
    • Group Coordinator 用于维护Consumer Group信息。
    • Consumer Rebalance 是为Consumer Group中的Consumer分配partition的过程。一旦一个Consumer Group中的成员发生变化,就会触发Rebalance行为。
    • Group leader 是第一个加入Consumer Group的Consumer,它负责Consumer Rebalance的执行。
    • Consumer Rebalance策略主要有Range和Round Robin。

    :::warning ISR机制? ::: 先来看几个单词:
    HW:high watermark最高水位,消费者poll时只能拉取offset < HW的消息。
    LEO:log end offset日志待写入位,也就是partition下一个消息进来的插入的位置,也就是当前消息位置。
    partition的每个replica都有这2个属性,且因为机器性能和网络原因,这两个属性各不相同。其中HW