因为一次 Kafka 宕机,我明白了 Kafka 高可用原理!
Kafka 的多副本冗余设计
=================
不管是传统的基于关系型数据库设计的系统,还是分布式的如 zookeeper 、Redis 、 Kafka 、 HDFS 等等,实现高可用的办法通常是采用冗余设计,通过冗余来解决节点宕机不可用问题。首先简单了解 Kafka 的几个概念:
物理模型
![](https://static001.geekbang.org/infoq/d6/d6f409dcacbcd0539b5473661de72dbe.jpeg?x-oss-process=image/resize,p_80/auto-orient,1)
逻辑模型
![](https://static001.geekbang.org/infoq/83/83678317147d2dfa86fe2d5bd5f92bfa.jpeg?x-oss-process=image/resize,p_80/auto-orient,1)
Broker (节点):Kafka 服务节点,简单来说一个 Broker 就是一台 Kafka 服务器,一个物理节点。
Topic (主题):在 Kafka 中消息以主题为单位进行归类,每个主题都有一个 Topic Name ,生产者根据 Topic Name 将消息发送到特定的 Topic,消费者则同样根据 Topic Name 从对应的 Topic 进行消费。
Partition (分区):Topic (主题)是消息归类的一个单位,但每一个主题还能再细分为一个或多个 Partition (分区),一个分区只能属于一个主题。主题和分区都是逻辑上的概念,举个例子,消息 1 和消息 2 都发送到主题 1,它们可能进入同一个分区也可能进入不同的分区(所以同一个主题下的不同分区包含的消息是不同的),之后便会发送到分区对应的 Broker 节点上。
Offset (偏移量):分区可以看作是一个只进不出的队列(Kafka 只保证一个分区内的消息是有序的),消息会往这个队列的尾部追加,每个消息进入分区后都会有一个偏移量,标识该消息在该分区中的位置,消费者要消费该消息就是通过偏移量来识别。
其实,根据上述的几个概念,是不是也多少猜到了 Kafka 的多副本冗余设计实现了?别急,咱继续往下看。
在 Kafka 0.8 版本以前,是没有多副本冗余机制的,一旦一个节点挂掉,那么这个节点上的所有 Partition 的数据就无法再被消费。这就等于发送到 Topic 的有一部分数据丢失了。
在 0.8 版本后引入副本记者则很好地解决宕机后数据丢失的问题。副本是以 Topic 中每个 Partition 的数据为单位,每个 Partition 的数据会同步到其他物理节点上,形成多个副本。
每个 Partition 的副本都包括一个 Leader 副本和多个 Follower 副本,Leader 由所有的副本共同选举得出,其他副本则都为 Follower 副本。在生产者写或者消费者读的时候,都只会与 Leader 打交道,在写入数据后 Fo
llower 就会来拉取数据进行数据同步。
![](https://static001.geekbang.org/infoq/15/152e0ed8f03928f78be879bdb32d6ed0.jpeg?x-oss-process=image/resize,p_80/auto-orient,1)
就这么简单?是的,基于上面这张多副本架构图就实现了 Kafka 的高可用。当某个 Broker 挂掉了,甭担心,这个 Broker 上的 Partition 在其他 Broker 节点上还有副本。你说如果挂掉的是 Leader 怎么办?那就在 Follower 中在选举出一个 Leader 即可,生产者和消费者又可以和新的 Leader 愉快地玩耍了,这就是高可用。
你可能还有疑问,那要多少个副本才算够用?Follower 和 Leader 之间没有完全同步怎么办?一个节点宕机后 Leader 的选举规则是什么?
直接抛结论:
多少个副本才算够用?
副本肯定越多越能保证 Kafka 的高可用,但越多的副本意味着网络、磁盘资源的消耗更多,性能会有所下降,通常来说副本数为 3 即可保证高可用,极端情况下将 replication-factor 参数调大即可。
Follower 和 Lead 之间没有完全同步怎么办?
Follower 和 Leader 之间并不是完全同步,但也不是完全异步,而是采用一种 ISR 机制( In-Sync Replica)。每个 Leader 会动态维护一个 ISR 列表,该列表里存储的是和 Leader 基本同步的 Follower。如果有 Follower 由于网络、GC 等原因而没有向 Leader 发起拉取数据请求,此时 Follower 相对于 Leader 是不同步的,则会被踢出 ISR 列表。所以说,ISR 列表中的 Follower 都是跟得上 Leader 的副本。
一个节点宕机后 Leader 的选举规则是什么?
分布式相关的选举规则有很多,像 Zookeeper 的 Zab 、 Raft 、 Viewstamped Replication 、微软的 PacificA 等。而 Kafka 的 Leader 选举思路很简单,基于我们上述提到的 ISR 列表,当宕机后会从所有副本中顺序查找,如果查找到的副本在 ISR 列表中,则当选为 Leader。另外还要保证前任 Leader 已经是退位状态了,否则会出现脑裂情况(有两个 Leader)。怎么保证?Kafka 通过设置了一个 controller 来保证只有一个 Leader。
Ack 参数决定了可靠程度
另外,这里补充一个面试考 Kafka 高可用必备知识点:request.required.asks 参数。
Asks 这个参数是生产者客户端的重要配置,发送消息的时候就可设置这个参数。该参数有三个值可配置:0、1、All 。
第一种是设为 0
意思是生产者把消息发送出去之后,之后这消息是死是活咱就不管了,有那么点发后即忘的意思,说出去的话就不负责了。不负责自然这消息就有可能丢失,那就把可用性也丢失了。
第二种是设为 1
意思是生产者把消息发送出去之后,这消息只要顺利传达给了 Leader,其他 Follower 有没有同步就无所谓了。存在一种情况,Leader 刚收到了消息,Follower 还没来得及同步 Broker 就宕机了,但生产者已经认为消息发送成功了,那么此时消息就丢失了。注意,
设为 1 是 Kafka 的默认配置
可见 Kafka 的默认配置也不是那么高可用,而是对高可用和高吞吐量做了权衡折中。
第三种是设为 All(或者-1)
意思是生产者把消息发送出去之后,不仅 Leader 要接收到,ISR 列表中的 Follower 也要同步到,生产者才会任务消息发送成功。
进一步思考, Asks=All 就不会出现丢失消息的情况吗?答案是否。当 ISR 列表只剩 Leader 的情况下, Asks=All 相当于 Asks=1 ,这种情况下如果节点宕机了,还能保证数据不丢失吗?因此只有在 Asks=All 并且有 ISR 中有两个副本的情况下才能保证数据不丢失。
解决问题
绕了一大圈,了解了 Kafka 的高可用机制,终于回到我们一开始的问题本身, Kafka 的一个节点宕机后为什么不可用?
评论