因为一次 Kafka 宕机,我明白了 Kafka 高可用原理!
Kafka 的多副本冗余设计
=================
不管是传统的基于关系型数据库设计的系统,还是分布式的如 zookeeper 、Redis 、 Kafka 、 HDFS 等等,实现高可用的办法通常是采用冗余设计,通过冗余来解决节点宕机不可用问题。首先简单了解 Kafka 的几个概念:
物理模型
逻辑模型
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 就会来拉取数据进行数据同步。
就这么简单?是的,基于上面这张多副本架构图就实现了 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 的一个节点宕机后为什么不可用?
评论