Elixir 可以執行在主/從, 故障轉移/接管模式下. 要使Elixir應用程式能夠執行故障轉移/接管, Elixir應用程式必須是一個OTP應用程式.
下面來建立一個包含Supervisor的Elixir專案
mix new distro --sup
修改distro.ex
新增logger
模組. 以記錄當觸發故障轉移/接管操作時的日誌記錄.
defmodule Distro do
use Application
require Logger
def start(type, _args) do
import Supervisor.Spec, warn: false
Logger.info("Distro application in #{inspect type} mode")
children = [
worker(Distro.Worker, [])
]
opts = [strategy: :one_for_one, name: Distro.Supervisor]
Supervisor.start_link(children, opts)
end
end
Distro.Worker
是一個GenServer
: 它使用全域性名稱註冊, 假設其執行在叢集中的一個節點上, 全域性註冊讓我們不用考慮其實際的執行位置, 只需要提供註冊名稱就可以訪問.
defmodule Distro.Worker do
use GenServer
require Logger
def start_link do
GenServer.start_link(__MODULE__, [], name: {:global, __MODULE__})
end
def init([]) do
{:ok, [], 1000}
end
def handle_info(:timeout, state) do
Logger.debug "timeout"
{:noreply, state, 1000}
end
end
編譯
$ mix compile
應用程式分佈
本節闡述瞭如何把一個應用程式分佈到多個節點上
假設應用程式執行在3個節點上, 名稱分別為abc
, bcd
, def
. 建立三個配置檔案如下:
touch config/abc.config
touch config/bcd.config
touch config/def.config
配置檔案中有3個重要的鍵值對. distributed
, sync_nodes_mandatory
和 sync_nodes_timeout
, 其中:
-
distributed
定義了分散式應用的啟動延遲, 備用節點. -
sync_nodes_mandatory
定義強制要求的節點 -
sync_nodes_timeout
定義了distributed
中所有節點都啟動完成需要等待的時間, 如果在此時間內要求的節點沒有全部啟動, 那麼所有節點上的應用啟動失敗.
abc.config
[
{logger,[{console,[{format,<<"$date $time $metadata[$level] $message
">>}]}]},
{kernel,
[{distributed, [
{`distro`, 5000, [`abc@192.168.8.104`, {`bcd@192.168.8.104`, `def@192.168.8.104`}]}]},
{sync_nodes_mandatory, [`bcd@192.168.8.104`, `def@192.168.8.104`]},
{sync_nodes_timeout, 30000}
]}].
bcd.config
[
{logger,[{console,[{format,<<"$date $time $metadata[$level] $message
">>}]}]},
{kernel,
[{distributed, [
{distro,5000, [`abc@192.168.8.104`, {`bcd@192.168.8.104`, `def@192.168.8.104`}]}]},
{sync_nodes_mandatory, [`abc@192.168.8.104`, `def@192.168.8.104`]},
{sync_nodes_timeout, 30000}
]}].
def.config
[
{logger,[{console,[{format,<<"$date $time $metadata[$level] $message
">>}]}]},
{kernel,
[{distributed, [
{distro,5000, [`abc@192.168.8.104`, {`bcd@192.168.8.104`, `def@192.168.8.104`}]}]},
{sync_nodes_mandatory, [`abc@192.168.8.104`, `bcd@192.168.8.104`]},
{sync_nodes_timeout, 30000}
]}].
在不同的終端自動全部3個節點
iex --name abc@192.168.8.104 -pa _build/dev/lib/distro/ebin/ --app distro
--erl "-config config/abc"
iex --name bcd@192.168.8.104 -pa _build/dev/lib/distro/ebin/ --app distro
--erl "-config config/bcd"
iex --name def@192.168.8.104 -pa _build/dev/lib/distro/ebin/ --app distro
--erl "-config config/def"
驗證步驟
bcd
, def
是 abc
的備用節點. bcd
優先於def
, 如果abc
死掉, 應用程式會在bcd
上重啟, 如果bcd
死掉, 應用程式會轉移到def
, 這時候abc
, bcd
修復啟動後, 應用會被abc
接管.
-
終止(Ctrl+C兩次)節點
abc@192.168.8.104
後,5秒內會在節點bcd@192.168.8.104
上重啟應用 -
再次啟動節點
abc@192.168.8.104
後,應用在bcd@192.168.8.104
上停止, 應用被恢復後的abc@192.168.8.104
節點接管(Takeover)