openguass的dcf是一个分布式一致性协议的实现(基于paxos协议,类似raft),能够实现分布式一致性数据传输和存储。
dcf通过传入json字符串来传递配置数据,如:
#1. 使能dcf特性开关
enable_dcf = on
#2. 当前节点id, 如果集群为3节点则每个节点可分别配置为1、2、3
dcf_node_id = 1
#3. 指定dcf数据目录
dcf_data_path = '/xxx/cluster/data1/dn1/dcf_data'
#4. 指定dcf集群配置信息,每个节点上dcf_config内容一致,其中配置的ip/端口专用于dcf节点间通信链路,注意与所有其他已使用的ip/端口不要配置冲突
dcf_config = '[{"stream_id":1,"node_id":1,"ip":"x.x.x.21","port":xx,"role":"LEADER"},{"stream_id":1,"node_id":2,"ip":"x.x.x.22","port":xx,"role":"FOLLOWER"},{"stream_id":1,"node_id":3,"ip":"x.x.x.23","port":xx,"role":"FOLLOWER"}]'
其中重点关注如下json字符串,
[{
"stream_id": 1,
"node_id": 1,
"ip": "x.x.x.21",
"port": 1712,
"role": "LEADER"
}, {
"stream_id": 1,
"node_id": 2,
"ip": "x.x.x.22",
"port": 1713,
"role": "FOLLOWER"
}, {
"stream_id": 1,
"node_id": 3,
"ip": "x.x.x.23",
"port": 1714,
"role": "FOLLOWER"
}]
dcf解析json字符串的流程大致如下:
在start的时候传入cfg_str,然后在parse_streams_cfg中解析到内存中。
json字符串是以json数组方式传入的,在解析前会判断是否是json数组,如果不是json数组就会报错退出。json数组里的对象就是stream,可以配置stream相关的信息,配置了多条流后会循环解析每个stream对象。
若dcf不是第一次启动,而是之前已经启动过并保留了元数据,则在执行md_init时会先读取元数据,若能读取到元数据,即使再传入json字符串也不会再解析。也就是说,只有在第一次启动dcf时才会解析json字符串,一旦启动过一次保存了元数据后就不会再解析传入的json字符串了。
对于单个stream调用parse_stream_cfg_single,解析结果保存到dcf_streams_t,其实就是放到内存里,最终放到全局变量g_metadata中。
typedef struct st_ptlist {
pointer_t *items;
uint32 capacity;
uint32 count;
} ptlist_t;
typedef struct st_streams_t {
ptlist_t stream_list;
} dcf_streams_t;
在parse_stream_cfg_single中解析时,会解析如下配置:
typedef struct st_dcf_node {
uint32 node_id; // 节点id
char ip[CM_MAX_IP_LEN]; // 节点监听的ip
uint32 port; // 节点监听的端口
dcf_role_t default_role; // 节点默认角色
uint32 voting_weight; // 投票的权重
uint32 group; // 分组id
uint64 priority; // 优先级
} dcf_node_t;
都解析成功后会将这些参数添加到stream里,
add_stream_member(streams, stream_id, &node_info);
dcf最多支持64条流,在添加时会对stream_id进行校验,节点数最多支持256个,会对node_id校验,voting_weight与node_id对应,也不能超过256.
在添加流之前还会确认这条流是否存在,如果流已经存在则无法添加成功,确认流存在后还会确认节点是否已经在这条流里面了。即流已经存在并且节点已经在这条流里面了是无法添加流成功的。
if (stream_isexists(stream_list, stream_id)) {
if (MD_GET_STREAMS_NODE(stream_list, stream_id, node_id) != NULL) {
return CM_TRUE;
}
}
最终所有的流都被保存到了全局静态变量g_metadata的streams链表里,streams前面已经列举过。
typedef struct st_dcf_meta {
latch_t latch;
meta_status_t status;
uint32 current_node_id;
dcf_node_t* all_nodes[CM_MAX_NODE_COUNT];
dcf_streams_t* streams;
char* buffer;
uint32 checksum;
} dcf_meta_t;
static dcf_meta_t g_metadata;
按照当前分析来看,一个节点可以有多条流。比如json字符串配置成这样也是可以的,
[{
"stream_id": 1,
"node_id": 1,
"ip": "127.0.0.1",
"port": 1712,
"role": "LEADER"
}, {
"stream_id": 1,
"node_id": 2,
"ip": "127.0.0.1",
"port": 1713,
"role": "FOLLOWER"
}, {
"stream_id": 2,
"node_id": 3,
"ip": "127.0.0.1",
"port": 1714,
"role": "FOLLOWER"
}]
到这里json字符串就被解析到dcf进程中了,这里其实就是解析到了stream的配置。