將協調降至最低以達到延展性
大部分的雲端應用程式是由多個應用程式服務所組成,包括 Web 前端、資料庫、商務程式、報告和分析等等。 為了達到延展性和可靠性,每個服務都應該在多個實例上執行。
未協調的系統,可以獨立處理工作,而不需要在機器之間傳遞訊息,通常比較容易調整。 協調通常不是二進位狀態,而是一種頻譜。 協調會在不同的層級發生,例如數據或計算。
當兩個實例嘗試執行影響某些共享狀態的並行作業時,會發生什麼事? 在某些情況下,必須跨節點協調,例如保留 ACID 保證。 在這裡圖表中, Node2
正在等候 Node1
釋放資料庫鎖定:
協調會限制水準規模的優點,並造成瓶頸。 在此範例中,當您相應放大應用程式並新增更多實例時,您會看到鎖定競爭增加。 在最壞的情況下,前端實例會花大部分時間等候鎖定。
「正好一次」語意是另一個經常協調的來源。 例如,訂單必須只處理一次。 兩名工人正在接聽新訂單。 Worker1
會挑選處理訂單。 應用程式必須確定 Worker2
不會複製工作,但如果 Worker1
當機,則不會卸除訂單。
您可以使用排程器代理程序監督員等模式來協調背景工作,但在此情況下,更好的方法是分割工作。 每個背景工作角色都會獲派特定範圍的訂單(例如,依計費區域)。 如果背景工作角色當機,新的實例會從先前的實例離開的地方挑選,但多個實例沒有競爭。
建議
使用以異步方式通訊的分離元件。 元件最好使用事件彼此通訊。
接受最終一致性。 當數據散發時,需要協調才能強制執行強式一致性保證。 例如,假設作業會更新兩個資料庫。 如果系統可以容納最終一致性,或許使用 補償交易模式在失敗后以邏輯方式復原,而不是將其放入單一交易 範圍,則最好是。
使用網域事件來同步處理狀態。 網域 事件是一個事件 ,會在發生具有定義域內重要性的事件時記錄。 感興趣的服務可以接聽事件,而不是使用全域交易來協調多個服務。 如果使用此方法,系統必須容許最終一致性(請參閱上一個專案)。
請考慮 CQRS 和事件來源等模式。 這兩種模式有助於減少讀取工作負載與寫入工作負載之間的爭用。
CQRS 模式會分隔讀取作業與寫入作業。 在某些實作中,讀取數據會實際與寫入數據分開。
在事件來源模式中,狀態變更會記錄為僅附加數據存放區的一系列事件。 將事件附加至數據流是不可部分完成的作業,需要最少的鎖定。
這兩種模式彼此互補。 如果 CQRS 中的唯寫存放區使用事件來源,只讀存放區可以接聽相同的事件,以建立目前狀態的可讀取快照集,並針對查詢優化。 不過,在採用 CQRS 或事件來源之前,請注意此方法的挑戰。
數據分割數據和狀態。 避免將所有數據放入一個跨許多應用程式服務共用的數據架構。 微服務架構會藉由讓每個服務負責自己的數據存放區,來強制執行此原則。 在單一資料庫中,將數據分割成分區可以改善並行,因為寫入某個分區的服務不會影響寫入至不同分區的服務。 雖然數據分割會增加某種程度的協調,但您可以使用數據分割來增加平行處理原則,以提升延展性。 將整合型狀態分割成較小的區塊,以便獨立管理數據。
設計等冪作業。 可能的話,設計作業為等冪。 如此一來,就可以使用至少一次語意來處理它們。 例如,您可以將工作專案放在佇列中。 如果背景工作角色在作業中間當機,另一個背景工作角色只會挑選工作專案。 如果背景工作角色需要更新數據,併發出其他訊息做為其邏輯的一部分, 則應該使用等冪訊息處理模式 。
盡可能使用開放式並行存取。 悲觀並行控制會使用資料庫鎖定來防止衝突。 這可能會導致效能不佳並降低可用性。 透過開放式並行控制,每個交易都會修改數據的複本或快照集。 認可交易時,資料庫引擎會驗證交易,並拒絕任何會影響資料庫一致性的交易。
Azure SQL 資料庫 和 SQL Server 支援透過快照集隔離的開放式並行存取。 某些 Azure 記憶體服務透過使用 Etag 支援開放式並行存取,包括 Azure Cosmos DB 和 Azure 儲存體。
請考慮 MapReduce 或其他平行分散式演算法。 根據要執行的工作數據和類型,您可以將工作分割成可由多個節點平行執行的獨立工作。 請參閱 大型計算架構樣式。
使用領導者選舉進行協調。 如果您需要協調作業,請確定協調器不會成為應用程式中的單一失敗點。 使用領導者選舉模式時,一個實例隨時都是領導者,並擔任協調器。 如果領導者失敗,則會將新的實例選取為領導者。