檢視原始碼 分散式應用程式

簡介

在具有多個 Erlang 節點的分散式系統中,可能需要以分散式方式控制應用程式。如果執行特定應用程式的節點關閉,則該應用程式應在另一個節點上重新啟動。

此類應用程式稱為分散式應用程式。請注意,分散的是應用程式的控制。所有應用程式都可以在某種意義上是分散式的,例如,它們可以使用其他節點上的服務。

由於分散式應用程式可以在節點之間移動,因此需要一些定址機制,以確保其他應用程式可以對其進行定址,而不管它目前在哪個節點上執行。此處不討論此問題,但可以使用 Kernel 中的 globalpg 模組。

指定分散式應用程式

分散式應用程式由應用程式控制器和名為 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_mandatorysync_nodes_optional 指定的節點啟動。當所有節點都啟動時,或當所有必要節點都啟動且 sync_nodes_timeout 指定的時間已過時,所有應用程式都會啟動。如果並非所有必要節點都啟動,則節點會終止。

範例

應用程式 myapp 將在節點 cp1@cave 上執行。如果此節點關閉,則 myapp 將在 cp2@cavecp3@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@cavecp3@cave 的系統組態檔案相同,除了必要節點清單外,對於 cp2@cave,該清單為 [cp1@cave, cp3@cave],對於 cp3@cave,該清單為 [cp1@cave, cp2@cave]

注意

所有相關節點的 distributedsync_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 myapp - Situation 1

同樣地,必須在所有相關節點上呼叫 application:stop(Application) 來停止應用程式。

故障轉移

如果執行應用程式的節點關閉,則會在(指定的逾時時間後) distributed 組態參數的節點清單中列出的第一個可運作節點上重新啟動應用程式。這稱為故障轉移

應用程式會在新的節點上以正常方式啟動,也就是由應用程式主節點呼叫:

Module:start(normal, StartArgs)

如果應用程式定義了 start_phases 金鑰,則是一個例外(請參閱包含的應用程式)。然後,應用程式會改為透過呼叫以下函式來啟動:

Module:start({failover, Node}, StartArgs)

此處 Node 是已終止的節點。

範例

如果 cp1 關閉,系統會檢查其他節點 cp2cp3 中哪一個節點執行的應用程式數量最少,但會等待 5 秒讓 cp1 重新啟動。如果 cp1 沒有重新啟動,且 cp2 執行的應用程式少於 cp3,則 myapp 會在 cp2 上重新啟動。

Application myapp - Situation 2

現在假設 cp2 也關閉,且在 5 秒內沒有重新啟動。現在 myapp 會在 cp3 上重新啟動。

Application myapp - Situation 3

接管

如果啟動的節點根據 distributed 的優先順序高於執行分散式應用程式的節點,則該應用程式會在新的節點上重新啟動,並在舊的節點上停止。這稱為接管

應用程式會由應用程式主節點呼叫以下函式來啟動:

Module:start({takeover, Node}, StartArgs)

此處 Node 是舊的節點。

範例

如果 myappcp3 上執行,且如果 cp2 現在重新啟動,它不會重新啟動 myapp,因為 cp2cp3 節點之間的順序是未定義的。

Application myapp - Situation 4

但是,如果 cp1 也重新啟動,則函式 application:takeover/2 會將 myapp 移至 cp1,因為對於此應用程式,cp1 的優先順序高於 cp3。在這種情況下,會在 cp1 上執行 Module:start({takeover, cp3@cave}, StartArgs) 以啟動應用程式。

Application myapp - Situation 5