天天看點

Akka 指南 之「叢集規範」叢集規範

叢集規範

注釋:本文描述了 Akka 叢集的設計概念。

文章目錄

  • 叢集規範
    • 簡介
    • 術語
    • Membership
      • Gossip
      • Vector Clocks
      • Gossip Convergence
      • Failure Detector
      • Leader
      • Seed Nodes
      • Gossip Protocol
      • Membership Lifecycle
      • Member States
      • User Actions
      • Leader Actions
      • Failure Detection and Unreachability

簡介

Akka 叢集(

Cluster

)提供了一種容錯的、分散的、基于點對點(

peer-to-peer

)的叢集成員(

membership

)服務,不存在單點故障或單點瓶頸。它使用

Gossip

協定和自動故障檢測器(

failure detector

)來實作這一點。

Akka 叢集允許建構分布式應用程式,其中一個應用程式或服務可以跨越多個節點(實際上是多個

ActorSystem

)。另請參見在「何時何地使用 Akka 叢集」中的讨論。

術語

  • 節點(

    node

    ),叢集的邏輯成員。實體計算機上可能有多個節點,由

    hostname:port:uid

    元組定義。
  • 叢集(

    cluster

    ),通過成員服務連接配接在一起的一組節點。
  • 上司(

    leader

    ),叢集中充當上司者的單個節點。管理叢集聚合(

    convergence

    )和成員(

    membership

    )狀态轉換。

Membership

叢集由一組成員節點組成。每個節點的辨別符是

hostname:port:uid

元組。Akka 應用程式可以分布在叢集上,每個節點承載應用程式的某些部分。叢集成員和運作在應用程式節點上的 Actor 是分離的。節點可以是叢集的成員,而不承載任何 Actor。加入叢集是通過向叢集中要加入的一個節點發出

Join

指令來啟動的。

節點辨別符内部還包含一個唯一辨別,即該

hostname:port

處 Actor 系統執行個體的 UID。Akka 使用 UID 能夠可靠地觸發遠端死亡監視(

remote death watch

)。這意味着相同的 Actor 系統在從叢集中删除後,不能再加入該叢集。要将具有相同

hostname:port

的 Actor 系統重新連接配接到叢集,你必須停止 Actor 系統并使用相同

hostname:port

啟動一個新系統,然後該系統将接收一個不同的 UID。

叢集成員狀态是一個特殊的「CRDT」,這意味着它具有一個不變的合并函數。當不同節點上發生并發修改時,更新總是可以合并并收斂到相同的最終結果。

Gossip

Akka 中使用的叢集成員是基于 Amazon 的「Dynamo」系統,特别是在 Basho 的「Riak」分布式資料庫中采用的方法。叢集成員是通過「Gossip Protocol」進行通信的,其中叢集的目前狀态是通過叢集随機傳播的,優先于沒有看到最新版本的成員。

Vector Clocks

「向量時鐘」是一種資料結構和算法,用于生成分布式系統中事件的部分排序和檢測因果關系沖突。

我們使用向量時鐘來協調和合并協定作用期間(

during gossiping

)叢集狀态的差異。向量時鐘是一組

(節點,計數器)

對。對叢集狀态的每次更新都會附帶對向量時鐘的更新。

Gossip Convergence

有關叢集的資訊在特定時間點在節點上本地聚合(

converges locally

)。此時節點可以證明他正在觀察的叢集狀态已被叢集中的所有其他節點觀察到。通過傳遞一組在協定期間看到目前狀态版本的節點來實作聚合。這些資訊被稱為“流言概述(

gossip overview

)”中的“可見集”。當所有節點都包含在可集合中時,就會出現聚合(

Convergence

)。

當任何節點都無法通路(

unreachable

)時,不會發生消息聚合(

Gossip convergence

)。節點需要再次變得可通路(

reachable

),或者移動到

down

removed

狀态(請參見下面的 Membership Lifecycle 部分)。這隻會阻止

leader

執行其叢集成員資格管理,而不會影響叢集頂層運作的應用程式。例如,這意味着在網絡分裂(

network partition

)期間,不可能向叢集添加更多節點。節點可以連接配接,但在分裂修複或關閉不可通路的節點之前,它們不會移動到

up

狀态。

Failure Detector

故障檢測器(

failure detector

)負責檢測一個節點是否無法從叢集的其餘部分通路。為此,我們使用了「The Phi Accrual Failure Detector」的實作。

Accrual Failure Detector 将監控和解釋分離。這使得它們适用于更廣泛的場景領域,并且更适合建構通用的故障檢測服務。其思想是,它儲存一個故障統計的曆史記錄,根據從其他節點接收到的心跳進行計算,并試圖通過考慮多個因素以及它們如何随着時間累積來進行有根據的猜測,以便更好地猜測特定節點是否關閉。而不僅僅是回答“節點是否關閉?”的“是”或“否”的問題“,它傳回一個

phi

值,表示節點關閉的可能性。

作為計算基礎的阙值(

threshold

)可由使用者配置。低阙值容易産生許多錯誤的懷疑,但可以確定在發生真正的崩潰時快速檢測。相反,高阙值産生的錯誤更少,但需要更多的時間來檢測實際的崩潰。預設門檻值為

8

,适用于大多數情況。然而,在雲環境中,例如 Amazon EC2,為了解決此類平台上有時出現的網絡問題,其值可以增加到

12

在叢集中,每個節點都由幾個(預設最多 5 個)其他節點監控,當其中任何一個節點檢測到無法通路該節點時,資訊将通過流言傳播到叢集的其餘部分。換句話說,隻要一個節點需要将一個節點标記為不可通路,則叢集的其餘部分都将該節點标記為不可通路。

要監視的節點是在散列有序節點環中從相鄰節點中挑選出來的。這是為了增加跨資料中心監控的可能性,但所有節點上的順序都相同,這確定了完全覆寫。

心跳每秒發出一次,每一次心跳都在請求/回複握手中執行,回複用于故障檢測器的輸入。

故障檢測器還将檢測節點是否可以再次通路。當監視不可通路節點的所有節點再次檢測到它是可通路的時,在散播流言之後,叢集将認為它是可通路的。

如果系統消息無法傳遞到節點,那麼它将被隔離,然後它将無法從無法通路的狀态傳回。如果有太多未确認的系統消息(例如監視、終止、遠端 Actor 部署、遠端父級監控的 Actor 失敗),則可能發生這種情況。然後需要将節點移動到

down

removed

狀态(請參見下面的 Membership Lifecycle 部分),并且必須重新啟動 Actor 系統,然後才能再次加入叢集。

Leader

在消息聚合之後,可以确定叢集的

leader

。沒有

leader

的選舉過程,隻要有消息聚合,任何一個節點都可以确定地被識别為上司者。

leader

隻是一個角色,任何節點都可以是

leader

,它可以在消息聚合之間切換角色。

leader

是能夠擔任上司角色的第一個按序節點,有關更多成員狀态的資訊,請參見下面的 Membership Lifecycle 部分。

leader

的角色是将成員移入或移出叢集,将

joining

成員更改為

up

狀态,或将

exiting

成員更改為

removed

狀态。目前,

leader

的行為隻是通過接收一個帶有資訊聚合的新的叢集狀态來觸發的。

通過配置,

leader

也有能力“自動關閉(

auto-down

)”一個節點,根據故障檢測器,該節點被認為是不可通路的。這意味着在配置的不可通路時間之後,将

unreachable

節點狀态自動設定為

down

Seed Nodes

種子節點(

seed nodes

)是為加入叢集的新節點配置的聯系點。當一個新節點啟動時,它會向所有種子節點發送一條消息,然後向首先應答的種子節點發送一個

join

指令。

種子節點配置值對正在運作的叢集本身沒有任何影響,它隻與加入叢集的新節點相關,因為它幫助它們找到要向其發送

join

指令的聯系點;新成員可以将此指令發送到叢集的任何目前成員,而不僅僅發送到種子節點。

Gossip Protocol

push-pull gossip

的一種變體被用來減少在叢集中發送的消息資訊量。在

push-pull gossip

中,發送的摘要表示目前版本,而不是實際值;然後,消息的接收者可以傳回其具有較新版本的任何值,也可以請求其具有過時版本的值。Akka 使用一個帶有向量時鐘的單一共享狀态進行版本控制,是以 Akka 中使用的

push-pull gossip

使用此版本僅在需要時推送實際狀态。

周期性地,預設為每 1 秒,每個節點選擇另一個随機節點來啟動一輪流言。如果可見集合(

seen set

)中的節點數少于 ½(已看到新狀态),那麼叢集将進行 3 次流言,而不是每秒一次。這種調整後的流言間隔是在狀态變化後的早期傳播階段加快聚合過程的一種方法。

選擇要傳播的節點是随機的,但是偏向于那些可能沒有看到目前狀态版本的節點。在每一輪的資訊交換中,當還未達到聚合時,一個節點使用非常高的機率(可配置)來與另一個不屬于所見集的節點(即可能具有較舊版本狀态的節點)傳播消息。否則,它會與任何随機活動節點閑聊。

這種有偏選擇是在狀态變化後的後期傳播階段加快聚合過程的一種方法。

對于大于 400 個節點的叢集(可配置,根據經驗建議),0.8 的機率逐漸降低,以避免出現過多并發消息請求的壓倒性單個節點。消息接收者還具有一種機制,通過丢棄在郵箱中排隊時間過長的消息,來保護自己免受過多消息的影響。

當叢集處于聚合狀态(狀态一緻)時,消息發送者隻向所選節點發送包含較小狀态的消息。一旦叢集發生變化(意味着不聚合),它就會再次回到有偏見的消息傳播。

消息狀态或消息狀态的接收者可以使用消息版本(向量時鐘)來确定:

  1. 它有一個新版本的消息狀态,在這種情況下,它會把它發送回消息傳播者。
  2. 它有一個過時的狀态版本,在這種情況下,接收者通過發送消息狀态的版本來請求消息傳播者的目前狀态。
  3. 它有沖突的消息版本,在這種情況下,不同版本的消息被合并,并發送回去。

如果消息接收者和消息的版本相同,則不會發送或請求消息狀态。

消息的周期性具有狀态更改的良好批處理效果,例如,将幾個節點快速地彼此連接配接到一個節點之後,隻會導緻一個狀态更改傳播到叢集中的其他成員。

消息用「protobuf」序列化,也用

gzip

壓縮以減小有效負載的大小。

Membership Lifecycle

節點以

joining

狀态開始。一旦所有節點都看到新節點正在加入(通過消息聚合),則

leader

将會設定成員狀态為

up

如果一個節點以一種安全的、預期的方式離開叢集,那麼它将切換到

leaving

狀态。一旦

leader

看到節點上的收斂處于

leaving

狀态,

leader

就會将其移動到

exiting

狀态。一旦所有節點都看到

exiting

狀态,

leader

将從叢集中删除該節點,并将其标記為

removed

如果一個節點是不可通路的,那麼消息聚合是不可能的,是以

leader

的任何行為也是不可能的(例如,允許一個節點成為叢集的一部分)。為了能夠向前移動,必須更改

unreachable

節點的狀态。它必須可以再次

reachable

或标記為

down

。如果節點要再次加入叢集,那麼必須重新啟動 Actor 系統,并再次執行加入過程。叢集還可以在配置的不可到達時間之後,通過

leader

自動關閉節點。如果

unreachable

節點的新化身(重新啟動,生成新的 UID)嘗試重新加入叢集,則舊的化身将标記為

down

,并且新的化身可以在無需手動幹預的情況下重新加入叢集。

  • 注釋:如果你啟用了自動關閉(

    auto-down

    )并觸發了故障檢測器,那麼如果你沒有采取措施關閉

    unreachable

    的節點,那麼随着時間的推移,你可能會得到許多單節點叢集。這是因為

    unreachable

    節點可能會将叢集的其餘部分視為不可通路,成為自己的

    leader

    并形成自己的叢集。

如前所述,如果一個節點是

unreachable

,那麼消息聚合是不可能的,是以

leader

的任何行為也是不可能的。通過啟用

akka.cluster.allow-weakly-up-members

(預設情況下啟用),可以在尚未達到聚合時提升新的連接配接節點。這些

Joining

節點将更新為

WeaklyUp

。一旦達到了消息聚合,

leader

就會把

WeaklyUp

的成員狀态設定為

Up

請注意,網絡分裂另一側的成員不知道新成員的存在。例如,在

quorum decisions

時,你不應該把

WeaklyUp

的成員計算在内。

  • State Diagram for the Member States (

    akka.cluster.allow-weakly-up-members=off

    )
Akka 指南 之「叢集規範」叢集規範
  • State Diagram for the Member States (

    akka.cluster.allow-weakly-up-members=on

    )
Akka 指南 之「叢集規範」叢集規範

Member States

  • joining

    :聯接叢集時的瞬态狀态
  • weakly up

    :網絡分裂時的瞬時狀态,僅當

    akka.cluster.allow-weakly-up-members=on

    開啟時,才會出現此狀态
  • up

    :正常工作狀态
  • leaving / exiting

    :優雅删除期間的狀态
  • down

    :當節點不再參與叢集決策時,會标記為

    down

  • removed

    :邏輯删除的狀态,标記該節點不再是叢集的成員

User Actions

  • join

    :将單個節點聯接到叢集,如果在配置中指定了要聯接的節點,則在啟動時可以是顯式的或自動的聯結節點
  • leave

    :告訴節點優雅地離開叢集
  • down

    :将節點标記為

    down

Leader Actions

leader

的職責如下:

  • 将成員移入或移出叢集中
    • joining -> up

    • weakly up -> up

      (執行此操作,不需要消息收斂)
    • exiting -> removed

Failure Detection and Unreachability

  • fd*

    :某個監控節點的故障檢測器被觸發,則将被監控節點被标記為

    unreachable

  • unreachable*

    unreachable

    不是一個真正的成員狀态,而是一個标志,除了表示叢集無法與此節點通信的狀态之外,在

    unreachable

    之後,故障檢測器可能會再次檢測到它是

    reachable

    的,進而删除該标志。

英文原文連結:Cluster Specification.