静态 / 动态配置的实现
静态配置信息一般以 YAML、JSON、Properties 等格式存,在服务启动时加载配置文件到内存当中,进行业务逻辑处理。
动态配置是指服务可以从某个地方动态加载配置信息。一种是基于第三方组件,另一种是基于本地文件。
基于 ZooKeeper 是指我们可以在 ZooKeeper 创建持久节点存储配置信息,然后 Broker 通过 ZooKeeper 提供的 Watch 机制来监听节点。当节点内容变更时可以及时感知,并进行后续的处理。
基于本地文件的思路是指在代码实现中,通过代码技巧监听本地配置文件的变更,只要本地文件变更了,就进行配置变更的操作。
集群和节点元数据的设计
集群元数据是用来保存集群维度的一些基本信息。最简单的集群元数据一般只需要包含集群 ID 和集群名字两个信息。
{
"ClusterId":"bmfursdfk",
"ClusterName":"Trade"
}
集群维度的元数据需要持久化存储,所以我们可以在 ZooKeeper 上创建持久化节点 /Cluster 来存储集群的的元数据。
节点元数据是用来保存 Broker 维度的一些基本信息。Broker 元数据一般至少要包含节点的唯一标识 BrokerID、节点的 IP、节点监听的端口 3 个字段。
{
"BrokerID":1, //BrokerID的类型可以是Int型,也可以是字符串型,区别不大。
"BrokerIP":"192.2.1.1",
"BrokerPort":8901
}
节点的元数据存储一般有这样两个思路:
- 所有 Broker 元数据都存储在一个 ZooKeeper Node,比如 /node
- 每个 Broker 元数据独立一个 ZooKeeper Node 存储,比如 /nodes/broker1、/nodes/broker2 等
目前业界主要使用的是第二个思路,主要的原因是:Broker 元数据分开存储方便管理,避免节点间相互影响,也可以避免单个 ZooKeeper Node 的数据量过大存不下。
Topic 和分区的支持
在消息队列中 Topic 和分区是必须的概念,Topic 是用来组织分区的逻辑概念,分区用来存储实体的消息数据。
Topic 至少需要 TopicID、Topic 名称、分区和副本在集群中的分布 3 个元素。
{
"TopicID": "shlnjdlfsakw",
"TopicName": "test",
"Replica": [
{
"Partition": 0,
"Leader": 0,
"Rep": [
0,
1
]
}
]
}
我们可以在 ZooKeeper 集群中创建一个持久化的节点来存储 Topic 的相关信息。
消费分组(订阅)的管理
根据“消费分组 + Topic + 分区号”三元组来记录消费进度,一般存储的格式会用 JSON 格式或者自定义的行格式:
// 存储格式:
{
"GroupName":"group1",
"TopicName": "topic1",
"Partition":0,
"Offset":0
}
// 行格式
group1,topic1,0,0
最常用的保存消费进度的思路有存 ZooKeeper、存本地文件、存内部的 Topic、存其他存储引擎 4 种思路。
-
存 ZooKeeper 是当前架构下一种最简单直观的方法。通过在 ZooKeeper 中为每个消费分组创建一个持久化的节点,比如 /groups/group1,来保存每个消费分组的消费进度信息。
-
存本地文件也是一种常用的思路。这种方案需要选择合适的数据结构来存储数据,以便进行高效的写入和更新。
-
存内部的 Topic 是指在集群中创建一个特殊名字的 Topic,比如 consumer_group_offset。此时这个 Topic 不允许普通用户读写,只允许用来保存消费进度。提供有压缩功能的 Topic,即 Topic 支持根据消息的 Key 对消息进行压缩。根据消息的 Key 进行压缩,只保留最后一条数据。
-
存其他存储引擎是指将消费进度存储在其他的存储引擎中,比如 MySQL、Redis 或其他第三方引擎等。这种方案本质上和存 ZooKeeper 的思路是一样的。得单独为存储消费进度信息而引入一个存储组件,这样会增加系统复杂度,还要考虑第三方组件的稳定性问题。
目前 Kafka 的消费位点保存方案最开始用的是存 ZooKeeper,后来用的是存内部的 Topic 的方案。RocketMQ 用的是存本地文件的方案。Pulsar 用的是存其他存储引擎 BookKeeper 的方案,Pulsar 能用这种方案的原因在于它是存算分离的架构,天然自带了存储引擎 BookKeeper,因此不会因为存储消费进度而引入额外的复杂度和成本。
此文章为11月Day27学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》