檢視原始碼 分散式應用程式
簡介
在具有多個 Erlang 節點的分散式系統中,可能需要以分散式方式控制應用程式。如果執行特定應用程式的節點關閉,則該應用程式應在另一個節點上重新啟動。
此類應用程式稱為分散式應用程式。請注意,分散的是應用程式的控制。所有應用程式都可以在某種意義上是分散式的,例如,它們可以使用其他節點上的服務。
由於分散式應用程式可以在節點之間移動,因此需要一些定址機制,以確保其他應用程式可以對其進行定址,而不管它目前在哪個節點上執行。此處不討論此問題,但可以使用 Kernel 中的 global
或 pg
模組。
指定分散式應用程式
分散式應用程式由應用程式控制器和名為 dist_ac
的分散式應用程式控制器程序控制。這兩個程序都是 Kernel 應用程式的一部分。因此,分散式應用程式是透過使用以下組態參數來設定 Kernel 應用程式來指定的 (另請參閱 Kernel):
distributed = [{Application, [Timeout,] NodeDesc}]
- 指定應用程式
Application = atom()
可以執行的位置。 NodeDesc = [Node | {Node,...,Node}]
是依優先順序排列的節點名稱清單。元組中節點之間的順序是未定義的。Timeout = integer()
指定在另一個節點重新啟動應用程式之前要等待的毫秒數。預設值為 0。
為了使應用程式控制的分散正常運作,可以執行分散式應用程式的節點必須彼此聯繫並協商在哪裡啟動應用程式。這是使用 Kernel 中的以下組態參數完成的:
sync_nodes_mandatory = [Node]
- 指定必須啟動的其他節點(在sync_nodes_timeout
指定的逾時時間內)。sync_nodes_optional = [Node]
- 指定可以啟動的其他節點(在sync_nodes_timeout
指定的逾時時間內)。sync_nodes_timeout = integer() | infinity
- 指定等待其他節點啟動的毫秒數。
啟動時,節點會等待所有由 sync_nodes_mandatory
和 sync_nodes_optional
指定的節點啟動。當所有節點都啟動時,或當所有必要節點都啟動且 sync_nodes_timeout
指定的時間已過時,所有應用程式都會啟動。如果並非所有必要節點都啟動,則節點會終止。
範例
應用程式 myapp
將在節點 cp1@cave
上執行。如果此節點關閉,則 myapp
將在 cp2@cave
或 cp3@cave
上重新啟動。 cp1@cave
的系統組態檔案 cp1.config
可以如下所示:
[{kernel,
[{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]},
{sync_nodes_mandatory, [cp2@cave, cp3@cave]},
{sync_nodes_timeout, 5000}
]
}
].
cp2@cave
和 cp3@cave
的系統組態檔案相同,除了必要節點清單外,對於 cp2@cave
,該清單為 [cp1@cave, cp3@cave]
,對於 cp3@cave
,該清單為 [cp1@cave, cp2@cave]
。
注意
所有相關節點的
distributed
和sync_nodes_timeout
值必須相同。否則,系統行為將是未定義的。
啟動和停止分散式應用程式
當所有相關(必要)節點都已啟動時,可以透過在所有這些節點上呼叫 application:start(Application)
來啟動分散式應用程式。
可以使用自動啟動應用程式的啟動腳本(請參閱 版本)。
應用程式會從 distributed
組態參數的節點清單中列出的第一個可運作節點啟動。應用程式會像往常一樣啟動。也就是說,會建立應用程式主節點並呼叫應用程式回呼函式:
Module:start(normal, StartArgs)
範例
繼續上一節的範例,啟動三個節點,並指定系統組態檔案:
> erl -sname cp1 -config cp1
> erl -sname cp2 -config cp2
> erl -sname cp3 -config cp3
當所有節點都可運作時,可以啟動 myapp
。這是透過在所有三個節點上呼叫 application:start(myapp)
來實現的。然後,它會在 cp1
上啟動,如下圖所示:
同樣地,必須在所有相關節點上呼叫 application:stop(Application)
來停止應用程式。
故障轉移
如果執行應用程式的節點關閉,則會在(指定的逾時時間後) distributed
組態參數的節點清單中列出的第一個可運作節點上重新啟動應用程式。這稱為故障轉移。
應用程式會在新的節點上以正常方式啟動,也就是由應用程式主節點呼叫:
Module:start(normal, StartArgs)
如果應用程式定義了 start_phases
金鑰,則是一個例外(請參閱包含的應用程式)。然後,應用程式會改為透過呼叫以下函式來啟動:
Module:start({failover, Node}, StartArgs)
此處 Node
是已終止的節點。
範例
如果 cp1
關閉,系統會檢查其他節點 cp2
或 cp3
中哪一個節點執行的應用程式數量最少,但會等待 5 秒讓 cp1
重新啟動。如果 cp1
沒有重新啟動,且 cp2
執行的應用程式少於 cp3
,則 myapp
會在 cp2
上重新啟動。
現在假設 cp2
也關閉,且在 5 秒內沒有重新啟動。現在 myapp
會在 cp3
上重新啟動。
接管
如果啟動的節點根據 distributed
的優先順序高於執行分散式應用程式的節點,則該應用程式會在新的節點上重新啟動,並在舊的節點上停止。這稱為接管。
應用程式會由應用程式主節點呼叫以下函式來啟動:
Module:start({takeover, Node}, StartArgs)
此處 Node
是舊的節點。
範例
如果 myapp
在 cp3
上執行,且如果 cp2
現在重新啟動,它不會重新啟動 myapp
,因為 cp2
和 cp3
節點之間的順序是未定義的。
但是,如果 cp1
也重新啟動,則函式 application:takeover/2
會將 myapp
移至 cp1
,因為對於此應用程式,cp1
的優先順序高於 cp3
。在這種情況下,會在 cp1
上執行 Module:start({takeover, cp3@cave}, StartArgs)
以啟動應用程式。