上个月30日,confluent发表文章称,Kafka 2.8版将支持内部的quorum服务,而不是ZooKeeper的工作。
ZooKeeper 的作用
ZooKeeper是一个开源分布式协作服务框架,也可以被认为是一个确保一致性的分布式(少量)存储系统。 特别适用于保存通用的配置信息、集群的元数据等。
有永久节点和临时节点,但临时节点与Watcher机制配合使用非常有用。
创建临时节点的客户端与ZooKeeper断开连接后,临时节点将消失,订阅节点状态更改的客户端将收到该节点状态更改的通知。
因此,会检测到集群中的某个服务处于在线或脱机状态。 因此,可以实现服务发现和故障转移拦截机制。
Kafka高度依赖ZooKeeper,如果没有ZooKeeper,Kafka将无法工作。 ZooKeeper为Kafka提供元数据管理,包括一些Broker信息、主题数据和分区数据。
每个Broker启动时都会与ZooKeeper进行交互,ZooKeeper存储集群中的所有主题、配置和副本等信息。
选举和扩大等机制也依赖ZooKeeper。
例如,控制器选举:每个Broker启动都尝试在ZooKeeper中注册/controller虚拟节点来竞选控制器,而第一个创建/controller节点的Broker被指定为控制器。
失败的节点也依赖于watcher的工作原理,监听此节点,在控制器故障后,其他Broker继续前来争夺,实现控制器故障恢复。
综上所述,ZooKeeper对Kafka来说是很重要
那为什么要抛弃 ZooKeeper软件体系结构正在发展,但对其进行更改一定是因为存在瓶颈。
先来看看运维的层面的问题。
首先作为中间件,需要依赖另一个中间件,感觉有点奇怪。
如果要依靠Netty的话,那一定没问题。 但是,运行Kafka需要提供ZooKeeper群集。 这其实有点奇怪。
你们公司去Kafka必须跟着ZooKeeper,等于被动地增加了运输的复杂性。
就像去百货商店买衣服,买上衣一样。 店员说不仅要卖,买还得买一套。 这笔钱花多了吗?
所以运输业者不仅要照顾Kafka集群,还要照顾ZooKeeper集群。
再看性能层面的问题。
ZooKeeper很有特点,强一致性
如果ZooKeeper群集中某个节点的数据发生更改,则会通知其他ZooKeeper节点同时执行更新,并且必须等待大家写完,这样会降低写入性能。
然后,你看到了上面我说的小量存储系统吧。 通常,ZooKeeper只适用于简单的配置和存储群集元数据,而不是真正意义上的存储系统。
写入的数据量过多可能会降低ZooKeeper的性能和稳定性,导致Watch延迟或丢失。
因此,如果Kafka群集较大且分区数量较大,则ZooKeeper中存储的元数据会变多,性能会下降。
另外,ZooKeeper也很分散,需要选举,选举也不舒服,选举发生时不提供服务
基于 ZooKeeper 的性能问题 Kafka 之前就做了一些升级
例如,以前Consumer的位移数据存储在ZooKeeper中,因此在提交位移或获取位移时需要访问ZooKeeper,如果量大,ZooKeeper将无法承受。
因此,后来引入位移主题(Topic为__consumer_offsets ),将位移的提交和获取像消息一样处理,并保存在日志中,避免了频繁访问ZooKeeper而性能差的问题
此外,可能需要支持百万分区级别,就像一些大型公司一样。 这在当前的Kafka单群集体系结构中不支持稳定运行。 也就是说,当前单个群集可以包含的分区数量有限。
所以Kafka需要去ZooKeeper。
33558www.Sina.com/zookeeper消失了Kafka将元数据存储在自己的内部,并使用以前的Log存储机制存储元数据。
与上述位移主题类似,有一个元数据主题,元数据像普通消息一样存储在Log中。
因此,元数据和以前的位移一样,利用现有的消息存储机制稍微改造以实现功能,是完美的
!然后还搞了个 KRaft 来实现 Controller Quorum。
图来自 confluent
这个协议是基于 Raft 的,协议具体就不展开了,就理解为它能解决 Controller Leader 的选举,并且让所有节点达成共识。
在之前基于 Zookeeper 实现的单个 Controller 在分区数太大的时候还有个问题,故障转移太慢了。
当 Controller 变更的时候,需要重新加载所有的元数据到新的 Controller 身上,并且需要把这些元数据同步给集群内的所有 Broker。
而 Controller Quorum 中的 Leader 选举切换则很快,因为元数据都已经在 quorum 中同步了,也就是 quorum 的 Broker 都已经有全部了元数据,所以不需要重新加载元数据!
并且其它 Broker 已经基于 Log 存储了一些元数据,所以只需要增量更新即可,不需要全量了。
这波改造下来就解决了之前元数据过多的问题,可以支持更多的分区!
最后可能看到这里有人会说,那为何一开始不这么实现?
因为 ZooKeeper 是一个功能强大且经过验证的工具,在早期利用它来实现一些功能,多简单哟,都不需要自己实现。
要不是 ZooKeeper 的机制导致了这个瓶颈,也不可能会有这个改造的。
软件就是这样,没必要重复造轮子,合适就好。