找到生成 Cluster ID 的代码,其实不是某种随机法生成的,而是用所有 MemberID hash 出来的。
1func (c *RaftCluster) genID() {
2 mIDs := c.MemberIDs()
3 b := make([]byte, 8*len(mIDs))
4 for i, id := range mIDs {
5 binary.BigEndian.PutUint64(b[8*i:], uint64(id))
6 }
7 hash := sha1.Sum(b)
8 c.cid = types.ID(binary.BigEndian.Uint64(hash[:8]))
9}
那么 Member ID 又是怎么来的呢?
1var b []byte
2sort.Strings(m.PeerURLs)
3for _, p := range m.PeerURLs {
4 b = append(b, []byte(p)...)
5}
6
7b = append(b, []byte(clusterName)...)
8if now != nil {
9 b = append(b, []byte(fmt.Sprintf("%d", now.Unix()))...)
10}
11
12hash := sha1.Sum(b)
13m.ID = types.ID(binary.BigEndian.Uint64(hash[:8]))
这个保证了 bootstrap 的时候,多个节点生成出来相同的 cluster id。
不过这导致一些问题,比如我用相同的配置多次启动集群,会看到 Cluster ID 不变。更麻烦的情况是,如果启动集群后销毁一半的节点,再用原来的配置新启动一套集群,前后两套集群是可以互相通信的。可以看看PD 的这个 issue。
解决办法就是设置启动参数 --initial-cluster-token
,保证每套集群都不一样。