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