檢視原始碼 global (核心程式 v10.2)

全域名稱註冊機制。

此模組包含以下服務

  • 全域名稱註冊
  • 全域鎖定
  • 維護完全連接的網路

從 OTP 25 開始,預設情況下,global 將會主動斷開與回報已失去與其他節點連線的節點的連線,以防止因網路問題導致的重疊分割。這將導致形成完全連接的分割區,而不是讓網路處於重疊分割的狀態。

警告

可以使用 prevent_overlapping_partitions 核心參數停用防止重疊分割的功能,讓 global 的行為與過去相同。然而,這對於所有期望提供完全連接網路的應用程式(例如 mnesia),以及對於 global 本身而言,都是有問題的。重疊分割的網路可能會導致 global 的內部狀態變得不一致。即使在這些分割區重新組合形成完全連接的網路之後,這種不一致性仍然可能存在。對於期望維護完全連接網路的其他應用程式的影響可能各有不同,但在這種分割期間,它們可能會以非常細微且難以偵測的方式發生錯誤。由於您可能會遇到沒有此修復程式而難以偵測的問題,因此強烈建議不要停用此修復程式。另請注意,此修復程式必須在網路中的所有節點上啟用才能正常運作。

注意

除非同時啟用核心參數 connect_allprevent_overlapping_partitions,否則上述任何服務都無法可靠地交付。但是,即使停用其中一個或兩個參數,呼叫 global API 也不會失敗。您只會得到不可靠的結果。

這些服務透過每個節點上存在的程序 global_name_server 來控制。當啟動節點時,全域名稱伺服器會自動啟動。術語全域是指由許多 Erlang 節點組成的系統。

全域註冊名稱的能力是分散式 Erlang 系統程式設計中的核心概念。在此模組中,提供了相當於 register/2whereis/1 BIF (用於本機名稱註冊) 的功能,但適用於 Erlang 節點網路。註冊的名稱是程序識別碼 (pid) 的別名。全域名稱伺服器會監視全域註冊的 pid。如果程序終止,名稱也會全域取消註冊。

註冊的名稱會儲存在每個節點上的複本全域名稱表中。沒有中央儲存點。因此,將名稱轉換為 pid 的速度很快,因為它始終是在本機完成的。對於任何導致全域名稱表發生變更的動作,其他節點上的所有表格都會自動更新。

全域鎖定具有鎖定識別碼,並設定在特定資源上。例如,指定的資源可以是 pid。當設定全域鎖定時,除鎖定請求者之外的所有資源都將拒絕存取已鎖定的資源。

註冊和鎖定服務都是原子性的。參與這些動作的所有節點都具有相同的資訊檢視。

全域名稱伺服器還執行持續監視節點設定變更的關鍵任務。如果執行全域註冊程序的節點關閉,則該名稱會全域取消註冊。為此,全域名稱伺服器會訂閱從模組 net_kernel 傳送的 nodeupnodedown 訊息。此內容中的相關核心應用程式變數為 net_setuptimenet_ticktimedist_auto_connect

名稱伺服器也會維護完全連接的網路。例如,如果節點 N1 連線至節點 N2 (後者已連線至 N3),則節點 N1N3 上的全域名稱伺服器會確保 N1N3 也已連線。在這種情況下,無法使用名稱註冊服務,但鎖定機制仍然有效。

如果全域名稱伺服器無法連線節點 (範例中的 N1N3),則會將警告事件傳送至錯誤記錄器。此類事件的存在並不排除節點稍後連線的可能性 (例如,您可以在 Erlang shell 中嘗試命令 rpc:call(N1, net_adm, ping, [N2])),但它表示存在網路問題。

注意

如果未正確設定完全連接的網路,請先嘗試增加 net_setuptime 的值。

另請參閱

global_groupnet_kernel

摘要

類型

代表 LockRequesterId 設定或刪除 ResourceId 的鎖定 ID。

函式

同步刪除鎖定 Id

global 已知的所有其他節點斷線。

此函式會取消註冊兩個 pid,並將訊息 {global_name_conflict, Name, OtherPid} 傳送至這兩個程序。

此函式會隨機選取其中一個 pid 進行註冊,並終止另一個 pid。

此函式會隨機選取其中一個 pid 進行註冊,並將訊息 {global_name_conflict, Name} 傳送至另一個 pid。

以原子方式變更所有節點上參照 Pid 的已註冊名稱 Name

將名稱 Name 與 pid 全域關聯,也就是說,在全球 Erlang 節點網路中通知所有節點新的全域名稱。

傳回所有全域註冊名稱的清單。

將訊息 Msg 傳送至全域註冊為 Name 的 pid。

使用 id/0 在指定的節點上設定鎖定。

將全域名稱伺服器與此節點已知的所有節點同步。

Id 上設定鎖定 (使用 set_lock/3)。

從 Erlang 節點網路中移除全域註冊的名稱 Name

傳回具有全域註冊名稱 Name 的 pid。如果未全域註冊名稱,則傳回 undefined

類型

-type id() :: {ResourceId :: term(), LockRequesterId :: term()}.

代表 LockRequesterId 設定或刪除 ResourceId 的鎖定 ID。

-type method() :: fun((Name :: term(), Pid :: pid(), Pid2 :: pid()) -> pid() | none).
-type retries() :: non_neg_integer() | infinity.
-type trans_fun() :: function() | {module(), atom()}.

函式

-spec del_lock(Id) -> true when Id :: id().

相當於 del_lock(Id, [node() | nodes()])

-spec del_lock(Id, Nodes) -> true when Id :: id(), Nodes :: [node()].

同步刪除鎖定 Id

連結至此函式

disconnect()

檢視原始碼 (自 OTP 25.1 起)
-spec disconnect() -> [node()].

global 已知的所有其他節點斷線。

傳回的節點名稱清單 (順序未指定) 對應於已斷線的節點。當 global:disconnect/0 傳回時,已完成執行的所有斷線操作。

斷線的執行方式為,僅會從 global 節點的叢集中移除目前節點。如果在 prevent_overlapping_partitions 啟用的情況下,您透過其他方式與 global 節點叢集中的其他節點斷線,則其他節點上的 global 可能會分割其餘節點,以確保不會出現重疊的分割區。即使停用了 prevent_overlapping_partitions,您最好還是使用 global:disconnect/0global 節點的叢集中移除目前節點,否則很可能會建立可能會導致問題的重疊分割區。

請注意,如果要停止節點,無需在停止節點之前明確呼叫 global:disconnect/0global 節點的叢集中移除該節點。無論是否啟用 prevent_overlapping_partitions,當節點停止時,都會自動處理從叢集中的移除。

如果目前節點已設定為 全域群組 的一部分,則只有該群組中已連線和/或同步的節點為 global 所知,因此 global:disconnect/0與這些節點斷線。如果目前節點不是 全域群組 的一部分,則所有 已連線的可見節點 都會為 global 所知,因此 global:disconnect/0 將與所有這些節點斷線。

請注意,關於已連線節點的資訊並不會立即傳遞到 global,因此呼叫者可能會看到 nodes() 返回的結果中包含某個節點,但該節點仍未被 global 所知。然而,當 prevent_overlapping_partitions 啟用時,斷線操作仍然不會造成任何重疊分割區。如果 prevent_overlapping_partitions 停用,則可能會在此情況下形成重疊分割區。

請注意,當 prevent_overlapping_partitions 啟用時,您可能會在其他節點上看到關於它們偵測到目前節點已斷線的警告報告。在這種情況下,這些警告完全無害,可以忽略。

連結至此函式

notify_all_name(Name, Pid1, Pid2)

檢視原始碼
-spec notify_all_name(Name, Pid1, Pid2) -> none when Name :: term(), Pid1 :: pid(), Pid2 :: pid().

此函式會取消註冊兩個 pid,並將訊息 {global_name_conflict, Name, OtherPid} 傳送至這兩個程序。

可以用作 register_name/3re_register_name/3 的名稱解析函式。

連結至此函式

random_exit_name(Name, Pid1, Pid2)

檢視原始碼
-spec random_exit_name(Name, Pid1, Pid2) -> pid() when Name :: term(), Pid1 :: pid(), Pid2 :: pid().

此函式會隨機選取其中一個 pid 進行註冊,並終止另一個 pid。

可以用作 register_name/3re_register_name/3 的名稱解析函式。

連結至此函式

random_notify_name(Name, Pid1, Pid2)

檢視原始碼
-spec random_notify_name(Name, Pid1, Pid2) -> pid() when Name :: term(), Pid1 :: pid(), Pid2 :: pid().

此函式會隨機選取其中一個 pid 進行註冊,並將訊息 {global_name_conflict, Name} 傳送至另一個 pid。

可以用作 register_name/3re_register_name/3 的名稱解析函式。

連結至此函式

re_register_name(Name, Pid)

檢視原始碼
-spec re_register_name(Name, Pid) -> yes when Name :: term(), Pid :: pid().

相當於 re_register_name(Name, Pid, fun random_exit_name/3)

連結至此函式

re_register_name(Name, Pid, Resolve)

檢視原始碼
-spec re_register_name(Name, Pid, Resolve) -> yes when Name :: term(), Pid :: pid(), Resolve :: method().

以原子方式變更所有節點上參照 Pid 的已註冊名稱 Name

函式 Resolve 的行為與 register_name/2,3 中的行為相同。

連結至此函式

register_name(Name, Pid)

檢視原始碼
-spec register_name(Name, Pid) -> yes | no when Name :: term(), Pid :: pid().

相當於 register_name(Name, Pid, fun random_exit_name/3)

連結至此函式

register_name(Name, Pid, Resolve)

檢視原始碼
-spec register_name(Name, Pid, Resolve) -> yes | no
                       when Name :: term(), Pid :: pid(), Resolve :: method().

將名稱 Name 與 pid 全域關聯,也就是說,在全球 Erlang 節點網路中通知所有節點新的全域名稱。

當新的節點加入網路時,它們會被告知已存在的全域註冊名稱。網路也會被告知新連線節點中的任何全域名稱。如果發現任何名稱衝突,則會呼叫函式 Resolve。其目的是決定哪個 PID 是正確的。如果該函式崩潰,或返回任何不是 PID 的值,則該名稱會被取消註冊。此函式針對每個名稱衝突呼叫一次。

警告

如果您計劃在不重新啟動系統的情況下更改程式碼,則必須使用外部函式 (fun Module:Function/Arity) 作為函式 Resolve。如果您使用本地函式,您將永遠無法替換該函式所屬模組的程式碼。

存在三個預定義的解析函式:random_exit_name/3random_notify_name/3notify_all_name/3

此函式是完全同步的,也就是說,當此函式返回時,名稱會註冊在所有節點上或都不註冊。

如果成功,函式返回 yes,如果失敗,則返回 no。例如,如果嘗試註冊已註冊的進程,或註冊一個已在使用的名稱的進程,則返回 no

注意

Erlang/OTP R10 及更早版本並未檢查進程是否已註冊。因此,全域名稱表可能變得不一致。可以通過將 Kernel 應用程式變數 global_multi_name_action 設定為值 allow 來選擇舊的(有錯誤的)行為。

如果具有註冊名稱的進程死亡,或節點關閉,則該名稱會在所有節點上取消註冊。

-spec registered_names() -> [Name] when Name :: term().

傳回所有全域註冊名稱的清單。

-spec send(Name, Msg) -> Pid when Name :: term(), Msg :: term(), Pid :: pid().

將訊息 Msg 傳送至全域註冊為 Name 的 pid。

如果 Name 不是全域註冊的名稱,則呼叫函式會因 {badarg, {Name, Msg}} 的原因而退出。

-spec set_lock(Id) -> boolean() when Id :: id().

相當於 set_lock(Id, [node() | nodes()], infinity)

-spec set_lock(Id, Nodes) -> boolean() when Id :: id(), Nodes :: [node()].

相當於 set_lock(Id, Nodes, infinity)

連結至此函式

set_lock(Id, Nodes, Retries)

檢視原始碼
-spec set_lock(Id, Nodes, Retries) -> boolean() when Id :: id(), Nodes :: [node()], Retries :: retries().

使用 id/0 在指定的節點上設定鎖定。

如果 ResourceId 上已存在另一個請求者(而非 LockRequesterId)的鎖,並且 Retries 不等於 0,則進程會休眠一段時間,然後稍後嘗試執行該操作。當嘗試 Retries 次後,返回 false,否則返回 true。如果 Retriesinfinity,則最終返回 true(除非鎖永遠不會被釋放)。

此函式是完全同步的。

如果持有鎖的進程死亡,或節點關閉,則該進程持有的鎖將被刪除。

全域名稱伺服器會追蹤所有共享同一鎖的進程,也就是說,如果兩個進程設定相同的鎖,則兩個進程都必須刪除該鎖。

此函式不會解決死鎖問題。只要進程一次只鎖定一個資源,就不會發生死鎖。如果某些進程嘗試鎖定兩個或更多資源,則可能會發生死鎖。檢測和糾正死鎖是應用程式的責任。

注意

避免使用以下 ResourceId 值,否則 Erlang/OTP 將無法正常運作

  • dist_ac
  • global
  • mnesia_adjust_log_writes
  • mnesia_table_lock
-spec sync() -> ok | {error, Reason :: term()}.

將全域名稱伺服器與此節點已知的所有節點同步。

這些是從 nodes() 返回的節點。當此函式返回時,全域名稱伺服器會接收來自所有節點的全域資訊。當新的節點加入網路時,可以呼叫此函式。

唯一可能的錯誤原因 Reason{"global_groups definition error", Error}

-spec trans(Id, Fun) -> Res | aborted when Id :: id(), Fun :: trans_fun(), Res :: term().

相當於 trans(Id, Fun, [node() | nodes()], infinity)

-spec trans(Id, Fun, Nodes) -> Res | aborted
               when Id :: id(), Fun :: trans_fun(), Nodes :: [node()], Res :: term().

相當於 trans(Id, Fun, Nodes, infinity)

連結至此函式

trans(Id, Fun, Nodes, Retries)

檢視原始碼
-spec trans(Id, Fun, Nodes, Retries) -> Res | aborted
               when
                   Id :: id(),
                   Fun :: trans_fun(),
                   Nodes :: [node()],
                   Retries :: retries(),
                   Res :: term().

Id 上設定鎖定 (使用 set_lock/3)。

如果成功,則會評估 Fun() 並返回結果 Res。如果鎖定嘗試失敗,則返回 aborted。如果 Retries 設定為 infinity,則交易不會中止。

infinity 是預設設定,如果未指定 Retries 的值,則會使用它。

-spec unregister_name(Name) -> _ when Name :: term().

從 Erlang 節點網路中移除全域註冊的名稱 Name

-spec whereis_name(Name) -> pid() | undefined when Name :: term().

傳回具有全域註冊名稱 Name 的 pid。如果未全域註冊名稱,則傳回 undefined