試想當一個節點啟動時,遠端節點該如何知道它的存在? 在 Moleculer 框架就有一個內建模組可以用來探索及定期 Heartbeat 驗證。節點一開始啟動時不需要知道其他節點的相關服務資訊,但它會向其他節點宣告它的存在,以便每個節點都可以獲得自己的本地服務註冊清單。假如節點掛掉或是停止的時候,其它節點會偵測受影響的服務,並且將它從本地註冊清單移除,如此一來才能將請求路由到活躍的節點。
Moleculer 預設的本地探索會使用 Transporter 模組來交換節點資訊及 Heartbeat 封包(關於封包結構請參考 Moleculer 協定[2] )。本地是內建機制中最簡單且最快的,它是個不需要任何外部依賴的解決方案。但是此方法也有缺點,尤其是超過 100 個節點的大型部署。它在傳輸 Heartbeat 封包時會產生大量流量,當通訊傳輸流量滿載時,將造成請求與響應的速度變慢,進而影響 Action 與事件的效率。
注意,因為 TCP Transporter 使用了 Gossip 協定及 UDP 封包進行探索及實施 Heartbeat 機制,因此它只能選擇使用本地探索方式。
範例:快速使用
moleculer.config.js
module.exports = {
registry: {
discoverer: "Local"
}
}
範例:選項設定方式
moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Local",
options: {
// 每 10 秒發送一次 heartbeat 封包
heartbeatInterval: 10,
// Heartbeat 逾時 30 秒
heartbeatTimeout: 30,
// 停用 heartbeat 驗證機制
disableHeartbeatChecks: false,
// 停用離線節點移除機制
disableOfflineNodeRemoving: false,
// 10 分鐘後移除離線節點
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
Redis[3] 是透過一個專用的連線服務來交換探索資訊及 Heartbeat 封包,這種方法可以降低 Transporter 模組的負擔,使得它可以專注於處理請求、響應、事件封包的傳遞。當啟用 Redis 探索方法時,Moleculer 節點會定期向 Redis 收發遠端節點資訊,並更新本地服務註冊清單。當節點的 Heartbeat 封包於一定時間內沒有回應,也就是該節點已斷線的話,Redis 將會自動移除過期的密鑰。
注意,由於此方法必須依賴 Redis 服務做定期 Heartbeat 檢查,因此檢測新節點的速度較慢,如果你想要快一點可以調整
heartbeatInterval
選項。
使用前請安裝 ioredis 套件
npm install ioredis --save
。
範例:快速使用
moleculer.config.js
module.exports = {
registry: {
discoverer: "Redis"
}
}
範例:連線到遠端 Redis 服務器
moleculer.config.js
module.exports = {
registry: {
discoverer: "redis://redis-server:6379"
}
}
範例:選項設定方式
moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Redis",
options: {
redis: {
// Redis 連線選項
// 更多資訊: https://github.com/luin/ioredis#connect-to-redis
port: 6379,
host: "redis-server",
password: "123456",
db: 3
}
// 序列化器
serializer: "JSON",
// 使用完整的 heartbeat 檢測將消耗更多的流量
// 10 表示每 10 個週期執行一次
fullCheck: 10,
// 一次掃描的大小
scanLength: 100,
// 顯示 Redis 命令
monitor: true,
// 以下為通用探索選項
// 每 10 秒發送一次 heartbeat 封包
heartbeatInterval: 10,
// Heartbeat 逾時 30 秒
heartbeatTimeout: 30,
// 停用 heartbeat 驗證機制
disableHeartbeatChecks: false,
// 停用離線節點移除機制
disableOfflineNodeRemoving: false,
// 10 分鐘後移除離線節點
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
若要進一步減少流量,請參考前一篇網路連結中的序列化工具,而非使用 JSON 序列化。
Etcd3[4] 的探索方法與 Redis 相似,會在 Etcd3 服務器上儲存探索資訊及 Heartbeat 封包。etcd3 會透過 Lease 機制來檢測活躍度,當叢集的 Heartbeat 封包於一定時間內沒有回應,會將過期節點的密鑰都刪除[5] 。因此 Etcd3 與 Redis 的探索具有相同的優缺點,它不會使用 Transporter 模組進行探索,也因此檢測新節點的速度較慢。
使用前請安裝 etcd3 套件
npm install etcd3 --save
。
範例:快速使用
moleculer.config.js
module.exports = {
registry: {
discoverer: "Etcd3"
}
}
範例:連線到遠端 Redis 服務器
moleculer.config.js
module.exports = {
registry: {
discoverer: "etcd3://etcd-server:2379"
}
}
範例:選項設定方式
moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Etcd3",
options: {
etcd: {
// etcd3 連線選項
// 更多資訊: https://mixer.github.io/etcd3/interfaces/options_.ioptions.html
hosts: "etcd-server:2379",
auth: "12345678"
}
// 序列化器
serializer: "JSON",
// 使用完整的 heartbeat 檢測將消耗更多的流量
// 10 表示每 10 個週期執行一次
fullCheck: 10,
// 以下為通用探索選項
// 每 10 秒發送一次 heartbeat 封包
heartbeatInterval: 10,
// Heartbeat 逾時 30 秒
heartbeatTimeout: 30,
// 停用 heartbeat 驗證機制
disableHeartbeatChecks: false,
// 停用離線節點移除機制
disableOfflineNodeRemoving: false,
// 10 分鐘後移除離線節點
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
你可以建立客製化探索器模組,官方建議可以參考 Redis 探索器的原始碼[6] 來修改,再實作必要的方法。
Moleculer 有一個內建的服務註冊模組,它儲存了關於服務、 Actions 、事件監聽和節點資訊。當你呼叫 Action 或發送事件時, Broker 會由註冊表查詢可執行請求的節點。假如存在多個節點,則會根據負載平衡規則來選擇節點。
註冊清單可由服務呼叫
broker.call("$node.list");
取得。
關於負載平衡規則將在下一個章節進行說明。
[1] Registry & Discovery, https://moleculer.services/docs/0.14/registry.html
[2] Protocol 4.0 (rev. 1), https://github.com/moleculer-framework/protocol/blob/master/4.0/PROTOCOL.md
[3] Redis, https://redis.io/
[4] etcd, https://etcd.io/
[5] Lease API, https://etcd.io/docs/v3.5/learning/api/#lease-api
[6] Redis discoverer, https://github.com/moleculerjs/moleculer/blob/master/src/registry/discoverers/redis.js