注意:仍處於 alpha 階段。 API 可能會發生變化。
(此儲存庫鏡像到 https://codeberg.org/flowerinthenight/zgroup)。
zgroup是一個 Zig 函式庫,可以管理叢集成員資格和成員故障偵測。它結合了 SWIM 協議的八卦式資訊傳播和 Raft 的領導者選舉演算法(減去日誌管理)來追蹤集群變化。
zgroup 的主要目標之一是能夠以最小的依賴性和網路負載來追蹤大小可隨時間動態變化的叢集(例如 Kubernetes 部署、GCP 實例群組、AWS 自動縮放群組等)。到目前為止,我之前的所有相關工作都依賴一些外部服務(參見spindle、hedge),使用傳統的心跳來實現這一點。隨著叢集變大,這種心跳技術通常會受到負載大小(與叢集大小成比例)增加的影響。但我想要一個不會受到這種副作用影響的系統。輸入 SWIM 的感染式訊息傳播。無論叢集大小如何,它都可以使用恆定的有效負載大小。 SWIM 使用PING
、 INDIRECT-PING
和ACK
的組合來偵測成員故障,同時搭載這些相同的訊息來傳播成員更新(八卦協定)。目前,zgroup僅使用SWIM的直接探測協定;它尚未完全實作 Suspicion 子協定。
目前,zgroup 對所有訊息使用單一 64 位元組有效負載,包括領導者選舉(見下文)。
我還想要某種不依賴外部鎖定服務的領導者選舉功能。目前,zgroup使用Raft的領導者選舉演算法子協定(沒有日誌管理)來實現這一點。需要注意的是,Raft 的領導者選舉演算法依賴穩定的成員資格才能正常運作,因此 zgroup 的領導者選舉只是盡力而為的基礎;當簇大小仍在變化時,裂腦仍然可能發生。添加了額外的代碼保護以最大限度地減少這些場景中的裂腦,但它並沒有完全消除。在我的用例(和測試)中,逐漸的叢集大小變化大多是穩定的,而具有巨大大小增量的突然變化則不然。例如,由於自動縮放,從三個節點(zgroup 的最小大小)突然大幅跳躍到一百個節點,會導致裂腦。然而,一旦達到目標規模,將始終選出一位領導者。
關於領導者選舉期間 Raft 的隨機超時範圍的說明:zgroup 的領導者跟踪 ping 延遲平均值並嘗試相應地調整超時範圍以適應集群大小隨時間的變化。
對於要加入現有叢集的節點,它需要一個加入位址。雖然 zgroup 為此公開了join()
函數,但它也提供了回呼機制,為呼叫者提供加入位址。然後可以將該位址儲存到外部儲存中以供其他節點使用。在內部,zgroup 使用群組中具有最高 IP(v4) 位址的節點。
提供了一個範例二進位來展示使用該庫的方法。有兩種方法可以運行範例:
# Build the sample binary:
$ zig build --summary all
# Run the 1st process. The expected args look like:
#
# ./zgroup groupname member_ip:port [join_ip:port]
#
# Run the first process (join to self).
$ ./zig-out/bin/zgroup group1 0.0.0.0:8080 0.0.0.0:8080
# Then you can run additional instances.
# Join through the 1st process/node (different terminal):
$ ./zig-out/bin/zgroup group1 0.0.0.0:8081 0.0.0.0:8080
# Join through the 2nd process/node (different terminal):
$ ./zig-out/bin/zgroup group1 0.0.0.0:8082 0.0.0.0:8081
# Join through the 1st process/node (different terminal):
$ ./zig-out/bin/zgroup group1 0.0.0.0:8083 0.0.0.0:8080
# and so on...
如果配置,範例二進位檔案將使用免費服務 https://keyvalue.immanuel.co/ 作為加入位址的儲存。
# Build the sample binary:
$ zig build --summary all
# Generate UUID:
$ uuidgen
{output}
# Run the 1st process. The expected args look like:
#
# ./zgroup groupname member_ip:port
#
# Run the first process:
$ ZGROUP_JOIN_PREFIX={output} ./zig-out/bin/zgroup group1 0.0.0.0:8080
# Add a second node (different terminal):
$ ZGROUP_JOIN_PREFIX={output} ./zig-out/bin/zgroup group1 0.0.0.0:8081
# Add a third node (different terminal):
$ ZGROUP_JOIN_PREFIX={output} ./zig-out/bin/zgroup group1 0.0.0.0:8082
# Add a fourth node (different terminal):
$ ZGROUP_JOIN_PREFIX={output} ./zig-out/bin/zgroup group1 0.0.0.0:8083
# and so on...
提供了一個範例 Kubernetes 部署檔案來在 Kubernetes 部署上嘗試 zgroup。不過,在部署之前,請確保更新ZGROUP_JOIN_PREFIX
環境變量,如下所示:
# Generate UUID:
$ uuidgen
{output}
# Update the 'value' part with your output.
...
- name: ZGROUP_JOIN_PREFIX
value: " {output} "
...
# Deploy to Kubernetes:
$ kubectl create -f k8s.yaml
# You will notice some initial errors in the logs.
# Wait for a while before the K/V store is updated.
提供了一個範例啟動腳本來在 GCP MIG 上嘗試 zgroup。不過,在部署之前,請確保更新腳本中的ZGROUP_JOIN_PREFIX
值,如下所示:
# Generate UUID:
$ uuidgen
{output}
# Update the 'value' part of ZGROUP_JOIN_PREFIX with your output.
...
ZGROUP_JOIN_PREFIX={output} ./zgroup group1 ...
# Create an instance template:
$ gcloud compute instance-templates create zgroup-tmpl
--machine-type e2-micro
--metadata=startup-script= ' ' " $( cat startup-gcp-mig.sh ) " ' '
# Create a regional MIG:
$ gcloud compute instance-groups managed create rmig
--template zgroup-tmpl --size 3 --region {your-region}
# You can view the logs through:
$ tail -f /var/log/messages
提供了一個範例啟動腳本來在 AWS ASG 上嘗試 zgroup。不過,在部署之前,請確保更新腳本中的ZGROUP_JOIN_PREFIX
值,如下所示:
# Generate UUID:
$ uuidgen
{output}
# Update the 'value' part of ZGROUP_JOIN_PREFIX with your output.
...
ZGROUP_JOIN_PREFIX={output} ./zgroup group1 ...
# Create a launch template. ImageId here is Amazon Linux, default VPC.
# (Added newlines for readability. Might not run when copied as is.)
$ aws ec2 create-launch-template
--launch-template-name zgroup-lt
--version-description version1
--launch-template-data '
{
"UserData":" ' " $( cat startup-aws-asg.sh | base64 -w 0 ) " ' ",
"ImageId":"ami-0f75d1a8c9141bd00",
"InstanceType":"t2.micro"
} '
# Create the ASG:
$ aws autoscaling create-auto-scaling-group
--auto-scaling-group-name zgroup-asg
--launch-template LaunchTemplateName=zgroup-lt,Version= ' 1 '
--min-size 3
--max-size 3
--availability-zones {target-zone}
# You can view the logs through:
$ [sudo] journalctl -f
若要取得該群組的目前成員,您可以嘗試以下操作:
const members = try fleet . getMembers ( gpa . allocator ());
defer members . deinit ();
for ( members . items , 0 .. ) | v , i | {
defer gpa . allocator (). free ( v );
log . info ( "member[{d}]: {s}" , .{ i , v });
}
使用 zgroup 的棘手部分是配置逾時以最佳化狀態傳播和收斂。目前的實作僅在本地網路內進行了測試。
歡迎 PR。