微服务编排引擎Cadence简介
原文來源:https://cadenceworkflow.io/
?
1、概述(Overview)
大量的用例跨越了單一的請求-應答,需要跟蹤復雜的狀態,響應異步事件,并與外部不可靠的依賴項通信。構建此類應用程序的通常方法是將無狀態服務、數據庫、cron作業和隊列系統等大雜燴在一起。這對開發人員的開發效率產生了負面影響,因為大多數代碼都是專門用于管道的,在大量低級細節后面隱藏了實際的業務邏輯。這樣的系統經常存在可用性問題,因為很難保持所有組件的健康。
Cadence解決方案是一種不考慮故障的有狀態編程模型,它掩蓋了構建可伸縮分布式應用程序的大部分復雜性。本質上,Cadence提供了一個持久的虛擬內存,它不鏈接到特定的進程,并在各種主機和軟件故障中使用局部變量保存完整的應用程序狀態,包括函數堆棧。這允許您使用編程語言的全部功能編寫代碼,而Cadence則負責應用程序的持久性、可用性和可伸縮性。
Cadence由編程框架(或客戶端庫)和托管服務(或后端)組成。該框架使開發人員能夠用熟悉的語言編寫和協調任務。
該框架使開發人員能夠用熟悉的語言編寫忽略錯誤的代碼。
后端服務是無狀態的,依賴于持久存儲。目前支持Cassandra和MySQL存儲。可以添加到提供多行單碎片事務的任何其他數據庫的適配器。有不同的服務部署模型。在Uber,的團隊運營著由數百個應用程序共享的多租戶集群。
2、使用案例(Use cases)
作為Cadence開發人員,我們面臨一個非技術性的難題:如何定位和描述Cadence平臺。
我們稱之為工作流。但是當大多數人聽到“工作流”這個詞時,他們會想到低代碼和ui。雖然這些可能對非技術用戶有用,但它們給軟件工程師帶來的痛苦往往大于價值。對于“hello world”演示應用程序來說,大多數ui和低代碼DSL非常棒,但是任何包含100多個元素或幾千行JSON DSL的圖表都是完全不實際的。因此,將Cadence定位為一個工作流并不理想,因為它會讓那些喜歡只使用代碼的開發人員望而卻步。
我們稱之為協調器。但這一術語相當狹隘,并拒絕了希望實現業務流程自動化解決方案的客戶。
我們稱之為耐用功能平臺。從技術上講,這是一個正確的術語。但微軟生態系統之外的大多數開發人員從未聽說過持久功能。
我們相信命名的問題來自這樣一個事實:Cadence確實是一種編寫分布式應用程序的新方法。它足夠通用,可以應用于任何超出單個請求-回復的用例。它可以用于構建工作流或編排平臺的傳統領域中的應用程序。但對于傳統上依賴于數據庫和/或任務隊列的多個用例來說,這也是開發人員生產力的巨大提升。
2.1、定時輪詢(aka Distributed Cron)
定時輪詢,通常稱為分布式cron,是指定期執行業務邏輯。對于這些場景,Cadence的優勢在于它可以保證執行、復雜的錯誤處理、重試策略和對執行歷史的可見性。
另一個重要的維度是規模。有些用例需要對大量的實體定期執行。在Uber,有些應用程序可以為每個客戶創建定期工作流。假設有1億多個并行cron作業不需要單獨的批處理框架。
定時輪詢通常是其他用例的一部分。例如,每月生成一次報告是定期的服務編排。或者是一個事件驅動的工作流,它為客戶累積忠誠度積分,并每月應用一次這些積分。
有許多Cadence周期性執行的例子。例如:
-
Uber后端服務,每分鐘為每個城市的每個十六進制重新計算各種統計數據。
-
每月優步業務報告生成。
2.2、微服務編排和事務(Microservice Orchestration and Saga)
一些業務流程通常是以多個微服務調用的形式實現的。并且實現必須保證所有調用最終都必須成功,即使出現長期的下游服務故障。在某些情況下,應該執行補償回滾邏輯,而不是試圖通過長時間重試來完成過程。Saga模式是補償API標準化的一種方法。
Cadence非常適合這種情況。它保證工作流代碼最終完成,內置了對無限指數活動重試的支持,并簡化了補償邏輯的編碼。它還提供了對每個工作流狀態的完全可見性,與基于隊列的編排不同,在隊列中幾乎不可能獲得每個單獨請求的當前狀態。
以下是一些基于Cadence的服務編排場景的真實示例:
-
使用Cadence工作流通過Banzai Cloud啟動Kubernetes;
-
使用Uber的客戶困擾票務流程和編排引擎改善用戶體驗
2.3、投票(Polling)
輪詢正在執行定期操作,以檢查狀態更改。例如ping主機、調用restapi或為新上傳的文件列出amazons3存儲桶。
Cadence支持長時間運行的活動和無限制的重試,使它非常適合。
一些實際的用例:
-
網絡、主機和服務監控;
-
正在處理上載到FTP或S3的文件;
-
輪詢外部API以使特定資源可用。
2.4、應用事件驅動( Event driven application)
許多應用程序監聽多個事件源,更新相應業務實體的狀態,并且在達到某種狀態時必須執行操作。節奏是一個很好的適合其中許多。它直接支持異步事件(aka signals),有一個簡單的編程模型,可以掩蓋狀態持久性的許多復雜性,并通過內置的重試確保外部操作的執行。
一些實際的用例:
-
由消費者行為檢測生成的對欺詐事件作出反應的工作流;
-
客戶忠誠度計劃,其中工作流累積獎勵點并在請求時應用。
2.5、存儲掃描(Storage scan)
在大量主機或數據庫之間劃分大型數據集,或者在amazons3存儲桶中包含數十億個文件,這是很常見的。Cadence是一個理想的解決方案,可以以可伸縮和彈性的方式實現此類數據的完整掃描。標準模式是運行一個活動(或多個并行活動,用于分區數據集)來執行掃描并將其進度返回到Cadence。在主機發生故障的情況下,將在其他主機上重試該活動,并從上次報告的進度繼續執行。
一些實際的用例:
-
對所有工作流執行記錄執行定期掃描的Cadence內部系統工作流。
2.6、批量任務(Batch job)
許多批處理作業不是純粹的數據操作程序。對于這些,現有的大數據框架是最合適的。但是,如果處理一個記錄需要外部API調用,而這些調用可能會失敗并且可能需要很長時間,那么Cadence可能會更好。
內部Uber客戶使用Cadence生成月末報表。每個語句都需要調用多個微服務,有些語句可能非常大。之所以選擇Cadence,是因為它為財務數據的持久性提供了嚴格的保證,并且能夠無縫地處理長時間運行的操作、重試和間歇性故障。
2.7、基礎架構資源調配(Infrastructure provisioning)
在公共云中提供一個新的數據中心或一個機器池是一個潛在的長時間運行的操作,有很多可能出現間歇性故障。當需要調配和配置幾十萬甚至幾十萬的資源時,規模也是一個問題。對于資源調配場景,一個有用的特性是Cadence支持將活動執行路由到特定的進程或主機。
許多操作都需要某種類型的鎖定,以確保一次對一個資源執行的變異不超過一個。Cadence通過業務ID提供了強大的唯一性保證。這可用于以容錯和可伸縮的方式實現此類鎖定行為。
一些實際的用例:
-
使用Cadence工作流啟動Kubernetes,由Banzai Cloud提供;
-
在HashiCorp consur中使用Cadence編排集群生命周期。
2.8、部署(CI/CD and Deployment)
實現CI/CD管道并將應用程序部署到容器、虛擬機或物理機是一個非常重要的過程。它的業務邏輯必須處理圍繞滾動升級、金絲雀部署和回滾的復雜需求。Cadence是構建部署解決方案的完美平臺,因為它提供了所有必要的保證和抽象,允許開發人員專注于業務邏輯。
一些實際的用例:
-
Uber內部部署基礎設施;
-
更新推送至物聯網設備。
2.9、操作管理(Operational management)
假設您必須創建一個類似于amazonrds的自操作數據庫。Cadence用于多個項目,這些項目自動管理和自動恢復各種產品,如MySQL、Elasticsearch和apache Cassandra。
這種系統通常是不同用例的混合體。他們需要使用輪詢來監視資源的狀態。它們必須對數據庫的管理接口執行編排API調用。如果需要,他們必須提供新的硬件或Docker實例。他們需要推送配置更新,并定期執行備份等其他操作。
2.10、交互式應用程序(Interactive application)
Cadence的性能和可伸縮性足以支持交互式應用程序。它可以用來跟蹤UI會話狀態,同時執行后臺操作。例如,在下訂單時,當后臺任務評估客戶是否存在欺詐行為時,客戶可能需要經過幾個屏幕。
2.11、DSL工作流(DSL workflows)
Cadence支持直接用Java和Go等編程語言實現業務邏輯。但有些情況下,使用特定領域的語言更合適。或者可能有一個遺留系統使用某種形式的DSL來定義流程,但它在操作上不穩定且不可伸縮。這也適用于較新的系統,如apacheflow、各種BPMN引擎和AWS Step函數。
可以使用Cadence SDK編寫解釋DSL定義的應用程序。當在Cadence上運行時,它會自動變得高度容錯、可伸縮和持久。Cadence已經被用來抨擊一些Uber內部的DSL引擎。客戶繼續使用現有的流程定義,但Cadence被用作執行引擎。
在Cadence之上統一所有公司的工作流引擎有很多好處。最明顯的一點是支持單個產品比支持多個產品更有效。它也很難擊敗Cadence的可伸縮性和穩定性,這是它帶來的每一個集成。在某些情況下,共享引擎的能力可能會帶來巨大的好處。
2.12、大數據與ML(Big data and ML)
許多公司都構建了定制的ETL和ML培訓和部署解決方案。Cadence非常適合用于此類應用的控制平面。
Cadence的一個重要特性是它能夠將任務執行路由到特定的進程或主機。控制如何將ML模型和其他大文件分配給主機是很有用的。例如,如果一個ML模型是按城市劃分的,那么請求應該被路由到包含相應城市模型的主機上。
3、術語(Concepts)
Cadence是一種新的開發人員友好的分布式應用程序開發方法。它借用了工作流自動化領域的核心術語。所以它的概念包括工作流和活動。工作流可以對事件作出反應并通過查詢返回內部狀態。
部署拓撲解釋了如何將所有這些概念映射到可部署的軟件組件。
3.1、工作流(WorkFlows)
Cadence核心抽象是一個忽略故障的有狀態工作流。工作流代碼的狀態(包括它創建的本地變量和線程)不受進程和Cadence服務失敗的影響。這是一個非常強大的概念,因為它封裝了狀態、處理線程、持久計時器和事件處理程序。
3.1.1、概述
Cadence核心抽象是一個忽略故障的有狀態工作流。工作流代碼的狀態(包括它創建的本地變量和線程)不受進程和Cadence服務失敗的影響。這是一個非常強大的概念,因為它封裝了狀態、處理線程、持久計時器和事件處理程序。
3.1.2、樣例
讓我們看一個用例。客戶注冊了一個試用期的應用程序。期滿后,如果客戶沒有取消,應每月收取一次續費。必須通過電子郵件通知客戶有關費用,并應能夠隨時取消訂閱。
這個用例的業務邏輯不是很復雜,可以用幾十行代碼來表達。但任何實際的實現都必須確保業務流程具有容錯性和可伸縮性。設計這樣一個系統有多種方法。
一種方法是以數據庫為中心。應用程序進程將定期掃描數據庫表以查找處于特定狀態的客戶,執行必要的操作,并更新狀態以反映這一點。雖然可行,但這種方法有各種缺點。最明顯的是客戶狀態的狀態機很快變得極其復雜。例如,向信用卡充值或發送電子郵件可能會由于下游系統不可用而失敗。失敗的調用可能需要長時間重試,最好使用指數重試策略。應該對這些調用進行限制,以避免外部系統過載。如果單個客戶記錄因任何原因無法處理,則應支持毒丸,以避免阻塞整個流程。基于數據庫的方法通常也存在性能問題。對于需要對處于特定狀態的記錄進行持續輪詢的情況,數據庫效率不高。
另一種常用的方法是使用計時器服務和隊列。任何更新都被推送到隊列中,然后從隊列中使用的工作線程更新數據庫,并可能在下游隊列中推送更多消息。對于需要調度的操作,可以使用外部計時器服務。這種方法通常可以擴展得更好,因為數據庫不會經常被輪詢以獲取更改。但是它使得編程模型更加復雜和容易出錯,因為在隊列系統和數據庫之間通常沒有事務更新。
使用Cadence,可以將整個邏輯封裝在一個簡單的持久函數中,該函數直接實現業務邏輯。因為函數是有狀態的,所以實現者不需要使用任何額外的系統來確保持久性和容錯性。
下面是實現訂閱管理用例的示例工作流。它是在Java中的,但也支持Go。Python和.NET庫正在進行活動開發。
public interface SubscriptionWorkflow {@WorkflowMethodvoid execute(String customerId); }public class SubscriptionWorkflowImpl implements SubscriptionWorkflow {private final SubscriptionActivities activities =Workflow.newActivityStub(SubscriptionActivities.class);@Overridepublic void execute(String customerId) {activities.sendWelcomeEmail(customerId);try {boolean trialPeriod = true;while (true) {Workflow.sleep(Duration.ofDays(30));activities.chargeMonthlyFee(customerId);if (trialPeriod) {activities.sendEndOfTrialEmail(customerId);trialPeriod = false;} else {activities.sendMonthlyChargeEmail(customerId);}}} catch (CancellationException e) {activities.processSubscriptionCancellation(customerId);activities.sendSorryToSeeYouGoEmail(customerId);}} }再次注意,這段代碼直接實現了業務邏輯。如果任何被調用的操作(aka活動)花費了很長時間,那么代碼不會改變。如果下游處理服務停機那么長時間,可以在chargeMonthlyFee上阻塞一天。與阻止睡眠30天是工作流代碼中的正常操作相同的方法。
Cadence對開放工作流實例的數量幾乎沒有可伸縮性限制。因此,即使你的網站擁有數億消費者,上述代碼也不會改變。
學習Cadence的開發人員經常問的問題是“如何處理工作流中的工作流工作進程失敗/重新啟動”?答案是你不要這樣。工作流代碼完全不受任何工人或甚至Cadence服務本身的故障和停機的影響。一旦它們被恢復,并且工作流需要處理某些事件(如計時器或活動完成),工作流的當前狀態將完全恢復并繼續執行。工作流失敗的唯一原因是工作流業務代碼引發異常,而不是基礎架構中斷。
另一個常見的問題是一個worker是否可以處理比其緩存大小或它可以支持的線程數更多的工作流實例。答案是,當工作流處于阻塞狀態時,可以安全地從工作線程中刪除。后來,當需要(以外部事件的形式)出現時,它可以在不同或相同的工人身上復活。因此,假設一個worker可以處理數百萬個開放的工作流執行,假設它可以處理更新率。
3.1.3、狀態恢復和決策(State Recovery and Determinism)
工作流狀態恢復利用了事件源,它對代碼的編寫方式施加了一些限制。主要的限制是工作流代碼必須是確定性的,這意味著如果執行多次,它必須產生完全相同的結果。這就排除了來自工作流代碼的任何外部API調用,因為外部調用可以間歇性地失敗或隨時更改其輸出。這就是為什么所有與外部世界的交流都應該通過活動進行。出于同樣的原因,工作流代碼必須使用Cadence api來獲取當前時間、睡眠和創建新線程。
3.1.4、ID唯一性(ID Uniqueness)
工作流ID由客戶端在啟動工作流時分配。它通常是一個業務級別的ID,如客戶ID或order ID。
Cadence保證在任何時候每個域都只能有一個具有給定ID的工作流(跨所有工作流類型)。嘗試啟動具有相同ID的工作流將失敗,并出現WorkflowExecutionAlreadyStarted錯誤。
如果存在具有相同ID的已完成工作流,則嘗試啟動工作流取決于WorkflowIdReusePolicy選項:
-
AllowDuplicateFailedOnly意味著只有在以前執行的具有相同ID的工作流失敗時,才允許啟動工作流。
-
AllowDuplicate意味著它可以獨立于以前的工作流完成狀態啟動。
-
RejectDuplicate表示根本不允許使用相同的工作流ID啟動工作流執行。
-
默認值為AllowDuplicateFailedOnly。
為了區分具有相同工作流ID的多個工作流運行,Cadence使用兩個ID標識工作流:工作流ID和運行ID。運行ID是服務分配的UUID。準確地說,任何工作流都是由三元組唯一標識的:域名、工作流ID和運行ID
3.1.5、子工作流( Child Workflow)
工作流可以作為子工作流執行其他工作流:工作流:工作流:. 子工作流完成或失敗將報告給其父工作流。
使用子工作流的一些原因是:
-
子工作流可以由不包含父工作流代碼的一組單獨的工作線程托管。因此,它將充當一個獨立的服務,可以從多個其他工作流中調用。
-
單個工作流的大小有限。例如,它不能執行100k活動。子工作流可以用于將問題劃分為更小的塊。一個父母有1000個孩子,每個執行1000個活動是100萬個已執行的活動。
-
子工作流可用于使用其ID管理某些資源,以確保唯一性。例如,管理主機升級的工作流可以為每個主機有一個子工作流(主機名是工作流ID),并使用它們來確保主機上的所有操作都已序列化。
-
子工作流可用于執行某些周期性邏輯,而不必放大父歷史記錄的大小。當父級啟動子級時,它執行周期性的邏輯調用,該調用根據需要繼續多次,然后完成。從父點if視圖來看,它只是一個子工作流調用。
與在單個工作流中并置所有應用程序邏輯相比,子工作流的主要限制是缺少共享狀態。父級和子級只能通過異步信號進行通信。但如果它們之間存在緊密耦合,那么使用單個工作流并僅依賴于共享對象狀態可能會更簡單。
我們建議從單個工作流實現開始,如果您的問題在已執行活動和已處理信號的數量方面有限制。它比多個異步通信工作流更直接
3.1.6、工作流重試(Workflow Retries)
工作流代碼不受基礎結構級停機和故障的影響。但它仍然可能由于業務邏輯級別的故障而失敗。例如,活動可能會由于超出重試間隔而失敗,并且應用程序代碼或工作流代碼有錯誤而無法處理該錯誤。
有些工作流需要保證即使在出現此類故障的情況下也能保持運行。為了支持此類用例,可以在啟動工作流時指定可選的指數重試策略。如果指定了它,則工作流失敗將在計算的重試間隔之后從頭重新啟動工作流。以下是重試策略參數:
-
InitialInterval是第一次重試之前的延遲。
-
BackoffCoefficient。重試策略是指數型的。該系數指定重試間隔的增長速度。系數1表示重試間隔始終等于InitialInterval。
-
MaximumInterval指定重試之間的最大間隔。適用于系數大于1。
-
MaximumAttempts指定出現故障時嘗試執行工作流的次數。如果超過此限制,則工作流將失敗而不重試。如果指定了ExpirationInterval,則不需要。
-
ExpirationInterval指定在出現故障時嘗試執行工作流的時間。如果超過此間隔,則工作流將失敗而不重試。如果指定了MaximumAttempts,則不需要。
-
NonRetryableErrorReasons允許指定不應重試的錯誤。例如,在某些情況下,重試無效參數錯誤是沒有意義的。
3.2、活動(Activities)
無故障無狀態工作流代碼是Cadence的核心抽象。但是,由于確定性的執行要求,它們不允許直接調用任何外部API。相反,它們協調活動的執行。在最簡單的形式中,Cadence活動是受支持語言之一的函數或對象方法。Cadence無法在失敗的情況下恢復活動狀態。因此,活動函數可以不受限制地包含任何代碼。
活動通過任務列表異步調用。任務列表本質上是一個隊列,用于存儲活動任務,直到它被可用的工作線程拾取為止。工作線程通過調用活動的實現函數來處理活動。當函數返回時,worker將結果報告給Cadence服務,后者反過來通知工作流完成情況。通過從不同的流程完成活動,可以完全異步地實現該活動。
3.2.1、超時(Timeouts)
Cadence不會對活動持續時間施加任何系統限制。由應用程序選擇執行的超時。這些是可配置的活動超時:
-
ScheduleToStart是從工作流請求活動執行到工作人員開始執行的最長時間。觸發此超時的通常原因是所有工作線程都已關閉或無法跟上請求速率。我們建議將此超時設置為工作流愿意在所有可能的工作進程中斷的情況下等待活動執行的最長時間。
-
StartClose是活動被工作線程選中后可以執行的最長時間。
-
ScheduleToClose是從工作流請求執行活動到完成活動的最長時間。
-
Heartbeat是Heartbeat請求之間的最長時間。請參閱長時間運行的活動。
需要ScheduleToClose或ScheduleToStart和StartClose超時。
3.2.2、重試(Retries)
由于Cadence無法恢復活動的狀態,而且它們可以與任何外部系統通信,因此會出現故障。因此,Cadence支持自動活動重試。當任何關聯的策略都可以被調用時。以下是重試策略參數:
-
InitialInterval是第一次重試之前的延遲。
-
BackoffCoefficient。重試策略是指數型的。該系數指定重試間隔的增長速度。系數1表示重試間隔始終等于InitialInterval。
-
MaximumInterval指定重試之間的最大間隔。適用于系數大于1。
-
MaximumAttempts指定出現故障時嘗試執行工作流的次數。如果超過此限制,則工作流將失敗而不重試。如果指定了ExpirationInterval,則不需要。
-
ExpirationInterval指定在出現故障時嘗試執行工作流的時間。如果超過此間隔,則工作流將失敗而不重試。如果指定了MaximumAttempts,則不需要。
-
NonRetryableErrorReasons允許指定不應重試的錯誤。例如,在某些情況下,重試無效參數錯誤是沒有意義的。
有些情況下,失敗時不應重試單個活動,而是應重試整個工作流部分。例如,媒體編碼工作流將文件下載到主機,對其進行處理,然后將結果上載回存儲。在此工作流中,如果承載輔助進程的主機死亡,則應在其他主機上重試所有這三個活動。這樣的重試應該由工作流代碼處理,因為它們非常特定于用例。
3.2.3、長期運行的活動(Long Running Activities)
對于長時間運行的活動,我們建議您指定相對較短的心跳超時和持續的心跳。這樣,即使是運行很長時間的活動,也可以及時處理工作人員的故障。指定心跳超時的活動應定期從其實現中調用heartbeat方法。
心跳信號請求可以包括特定于應用程序的有效負載。這對于保存活動執行進度非常有用。如果某個活動由于錯過心跳而超時,下一次嘗試執行該活動時可以訪問該進度并從該點繼續執行。
作為特長競選活動的領導者可以使用。節奏超時使用第二分辨率。因此,它不是實時應用程序的解決方案。但是如果在幾秒鐘內對流程失敗做出反應是可以的,那么Cadence心跳活動就是一個很好的選擇。
這種領導人選舉的一個常見用例是監控。活動執行一個內部循環,該循環定期輪詢某些API并檢查某些條件。它也在每次迭代中心跳。如果條件滿足,則活動將完成,這將允許其工作流處理它。如果活動工作線程死亡,則該活動在超過檢測信號間隔后超時,并在其他工作線程上重試。同樣的模式也適用于在amazons3存儲桶中輪詢新文件或REST或其他同步api中的響應。
3.2.4、取消(Cancellation)
工作流可以請求取消活動。目前,一項活動被取消的唯一途徑是通過心跳。心跳信號請求失敗,并出現一個特殊錯誤,指示活動已取消。然后由活動實現執行所有必要的清理并報告已完成。由工作流實現決定是要等待活動取消確認,還是不等待就繼續。
活動心跳信號失敗的另一個常見情況是,調用它的工作流處于已完成狀態。在這種情況下,活動也將執行清理。
3.2.5、任務路由(Activity Task Routing through Task Lists)
活動通過任務列表發送給工人。任務列表是工作人員監聽的隊列。任務列表是高度動態和輕量級的。它們不需要顯式注冊。每個工作進程有一個任務列表是可以的。通過單個任務列表調用多個活動類型是正常的。在某些情況下(如主機路由),在多個任務列表上調用相同的活動類型是正常的。
以下是在單個工作流中使用多個活動任務列表的一些用例:
-
流量控制。從任務列表中使用的工作線程僅在活動任務具有可用容量時才請求該活動任務。因此,請求峰值不會使工作人員過載。如果請求活動執行的速度比工作人員處理它們的速度快,則它們將被積壓在任務列表中。
-
節流。每個活動工作線程都可以指定允許其處理任務列表中活動的最大速率。即使它有備用容量,也不會超過這個限制。還支持全局任務列表速率限制。此限制適用于給定任務列表的所有工作線程。它經常用于限制活動調用的下游服務的負載。
-
獨立地部署一組活動。考慮一個承載活動的服務,它可以獨立于其他活動和工作流進行部署。要將活動任務發送到此服務,需要一個單獨的任務列表。
-
具有不同能力的工人。例如,GPU盒上的工人與非GPU盒上的工人。在這種情況下,有兩個單獨的任務列表允許工作流選擇將執行請求發送到哪個活動。
-
將活動路由到特定主機。例如,在媒體編碼的情況下,轉換和上載活動必須與下載活動在同一主機上運行。
-
將活動路由到特定進程。例如,一些活動加載大型數據集并在過程中緩存它。依賴于此數據集的活動應路由到同一進程。
-
多重優先權。每個優先級一個任務列表,每個優先級有一個工作池。
-
版本控制。活動的新的向后不兼容實現可能使用不同的任務列表。
3.2.6、異步活動完成(Asynchronous Activity Completion)
默認情況下,活動是函數或方法,具體取決于客戶端庫語言。函數一返回,活動就完成。但在某些情況下,活動實現是異步的。例如,它通過消息隊列轉發到外部系統。而回復來自另一個隊列。
為了支持這樣的用例,Cadence允許在活動函數完成時不完成的活動實現。在這種情況下,應該使用單獨的API來完成活動。這個API可以從原始活動工作人員使用的任何進程調用,即使是在不同的編程語言中也是如此。
3.2.7、本地活動(Local Activities)
有些活動的生命周期很短,不需要查詢語義、流量控制、速率限制和路由功能。對于這些節奏支持所謂的局部活動特征。本地活動與調用它們的工作流在同一工作進程中執行。考慮將本地活動用于以下功能:
-
不超過幾秒鐘。
-
不需要全局速率限制。
-
不需要路由到特定的工作線程或工作線程池。
-
可以在與調用它們的工作流相同的二進制文件中實現。
本地活動的主要好處是,與通常的活動調用相比,本地活動在利用Cadence服務資源方面效率更高,延遲開銷也更低。
3.3、事件處理(Event handling)
忽略故障的有狀態工作流可以在外部事件時發出信號。信號始終是指向特定工作流實例的點對點。信號總是按照接收的順序進行處理。
有多種情況下信號是有用的。
3.3.1、事件聚合和關聯(Event Aggregation and Correlation)
Cadence并不是ApacheFlink或ApacheSpark這樣的通用流處理引擎的替代品。但在某些情況下,它更適合。例如,當所有應該聚合和關聯的事件總是應用于具有清晰ID的某個業務實體時,然后當滿足某個條件時,應該執行操作。
主要的限制是單個Cadence工作流的吞吐量非常有限,而工作流的數量實際上是無限的。因此,如果您需要聚合每個客戶的事件,并且您的應用程序有1億個客戶,并且每個客戶每秒生成的事件不超過20個,那么Cadence就可以正常工作了。但是,如果您想為美國客戶聚合所有事件,那么這些事件的發生率將超出單個工作流的容量。
例如,物聯網設備生成事件,某個事件序列指示應重新配置該設備。將為每個設備創建一個工作流實例,每個實例將管理設備的狀態機,并在必要時執行重新配置活動。
另一個用例是客戶忠誠度計劃。每次客戶進行購買時,都會在apachekafka中生成一個事件供下游系統處理。忠誠度服務Kafka消費者接收事件并使用Cadence signalWorkflowExecution API向客戶發送有關購買的工作流。工作流將累積購買的計數。如果達到指定的閾值,工作流將執行一個活動,通知某些外部服務客戶已達到下一級忠誠度計劃。工作流還執行活動,定期向客戶發送有關其當前狀態的消息。
3.3.2、人工任務(Human Tasks)
許多業務流程都涉及到人工參與者。實現外部交互的標準節奏模式是執行在外部系統中創建人工任務的活動。它可以是帶有表單的電子郵件,或者外部數據庫中的記錄,或者移動應用程序通知。當用戶更改任務的狀態時,會向相應的工作流發送一個信號。例如,在提交表單或確認移動應用程序通知時。有些任務有多個可能的操作,如索賠、退貨、完成、拒絕。因此可以發送與之相關的多個信號。
3.3.3、過程執行變更(Process Execution Alteration)
如果發生了一些外部事件,一些業務流程應該改變它們的行為。例如,在執行訂單裝運工作流時,項目數量的任何更改都可以以信號的形式傳遞。
另一個例子是服務部署工作流。當向Kubernetes集群推出新的軟件版本時,發現了一些問題。在調查問題時,可以使用一個信號來請求工作流暫停。然后,可以使用continue或rollback信號來執行適當的操作。
3.3.4、異步處理(Synchronization)
Cadence工作流非常一致,因此可以將它們用作執行操作的同步點。例如,需要按順序處理單個用戶的所有消息,但底層消息傳遞基礎結構可以并行地傳遞它們。Cadence的解決方案是為每個用戶提供一個工作流,并在收到事件時向其發出信號。然后,工作流將緩沖內部數據結構中的所有信號,然后為接收到的每個信號調用一個活動。
3.4、異常查詢(Synchronous query)
工作流代碼是有狀態的,Cadence框架在各種軟件和硬件故障時保持它。在工作流執行期間,狀態會不斷變化。為了向外部世界公開這種內部狀態,Cadence提供了一個同步查詢特性。從工作流實現者的角度來看,查詢公開為外部實體調用的同步回調。每個工作流類型可以提供多個這樣的回調,向不同的外部系統公開不同的信息。
要執行查詢,外部客戶機調用同步Cadence API,提供域、工作流ID、查詢名稱和可選的查詢參數。
查詢回調必須是只讀的,不能以任何方式更改工作流狀態。另一個限制是查詢回調不能包含任何阻塞代碼。以上兩個限制都排除了從查詢處理程序調用活動的能力。
Cadence團隊目前正致力于實現更新特性,該特性在調用方式上類似于查詢,但將支持工作流狀態變異和本地活動調用。
3.4.1、堆棧跟蹤查詢(Stack Trace Query)
Cadence客戶機庫公開了一些現成的預定義查詢。目前唯一支持的內置查詢是stack_trace。此查詢返回所有工作流擁有的線程的堆棧。這是解決生產中任何工作流問題的好方法。
3.5、任務列表(Task Lists)
當工作流調用活動時,它將ScheduleActivityTask決策發送到Cadence服務。因此,服務更新工作流狀態并將活動任務分派給實現該活動的工作人員。使用中間隊列而不是直接調用工作進程。因此,服務將向該隊列添加一個活動任務,工作線程將使用長輪詢請求接收該任務。Cadence將用于分派活動任務的隊列稱為活動任務列表。
類似地,當工作流需要處理外部事件時,將創建一個決策任務。決策任務列表用于將其傳遞給工作流工作人員(也稱為決策者)。
雖然Cadence任務列表是隊列,但它們與常用的隊列技術有一些不同。主要的一點是,它們不需要顯式注冊,而是按需創建的。任務列表的數量不受限制。一個常見的用例是為每個工作進程提供一個任務列表,并使用它向流程交付活動任務。另一個用例是每個工人池都有一個任務列表。
使用任務列表傳遞任務而不是通過同步RPC調用活動工作線程有多種優勢:
-
工人不需要有任何開放的端口,這是更安全的。
-
Worker不需要通過DNS或任何其他網絡發現機制來公布自己。
-
當所有工作線程都關閉時,消息將保存在任務列表中,等待工作進程恢復。
-
只有當消息有空閑容量時,工作線程才會輪詢消息,因此消息不會過載。
-
跨大量工作人員進行自動負載平衡。
-
任務列表支持服務器端限制。這允許您將任務分派率限制為工作人員池,并且在峰值發生時仍然支持以更高的速率添加任務。
-
任務列表可用于將請求路由到特定的工作人員池,甚至是特定的進程。
3.6、跨DC復制(Cross-DC replication)
Cadence全局域功能為客戶端提供了在發生數據中心故障轉移時從另一個群集繼續執行工作流的能力。盡管可以將全局域配置為復制到任意數量的群集,但它僅在單個群集中被視為活動域。
3.6.1、全局域體系結構(Global Domains Architecture)
Cadence引入了一個新的頂級實體Global Domains,它支持跨集群復制工作流執行。客戶機應用程序需要運行工人輪詢所有集群上的活動/決策任務。Cadence將只在當前活動集群上分派任務;備用集群上的工作線程將處于空閑狀態,直到全局域發生故障轉移。
因為Cadence是一個提供高度一致語義的服務,所以我們只允許在活動集群上發生StartWorkflowExecution、SignalWorkflowExecution等外部事件。全局域依賴于本地群集(local_Quorum)上的輕量級事務(paxos)來更新工作流執行狀態,并創建異步應用的復制任務,以跨群集復制狀態。如果應用程序在全局域處于待機模式的群集上進行這些API調用,Cadence將使用包含當前活動群集名稱的DomainNotActivieError拒絕這些調用。應用程序負責將外部事件轉發到當前處于活動狀態的群集。
3.6.2、全局域的新配置(New config for Global Domains)
3.6.2.1、全局(IsGlobal)
此配置用于區分集群本地域和全局域。它控制在更新時創建復制任務,允許在集群之間復制狀態。只有當域設置為只讀時才可設置。
3.6.2.2、集群(Clusters)
域可以故障轉移到的群集列表,包括當前活動群集。這也是一個只讀設置,只能在設置域時設置。路線圖上的重新復制特性將允許在將來更新此配置以添加/刪除群集。
3.6.2.3、活動集群名稱(Active Cluster Name)
全局域的當前活動群集的名稱。每次全局域故障轉移到另一個群集時,都會更新此配置。
3.6.2.4、文件版本(Failover Version)
唯一的故障轉移版本,也表示全局域的當前活動群集。Cadence允許從任何集群觸發故障轉移,所以故障轉移版本的設計方式是在兩個集群上錯誤地同時觸發故障轉移時不允許發生沖突。
3.6.3、沖突解決(Conflict Resolution)
與只為活動執行提供一次語義的局部域不同,全局域只能支持至少一次語義。Cadence XDC依賴于跨集群的異步事件復制,因此在發生故障轉移時,由于復制任務延遲,活動可能會在新的活動集群上再次被調度。這也意味著,無論何時在新群集進行故障轉移后更新工作流執行,都無法應用該執行之前的任何復制任務。這會導致上一個活動集群中工作流執行所取得的某些進展丟失。在這種沖突解決過程中,Cadence在放棄復制任務之前,會將任何外部事件(如信號)重新注入到新的歷史中。即使在故障轉移期間某些進度可能會回滾,但Cadence可以保證工作流不會卡住,并將繼續向前推進。
3.6.4、可視化API(Visibility API)
在主集群和備用集群上都允許所有可見性api。這使得Cadence Web能夠無縫地為全局域工作,因為可以從域復制到的任何集群中查詢工作流執行的所有可見性記錄。即使全局域處于待機狀態,直接調用Cadence可見性API的應用程序也將繼續工作。但是,在從備用集群查詢工作流執行狀態時,由于復制延遲,它們可能會看到延遲。
3.6.5、CLI
Cadence CLI還可用于查詢域配置或執行故障轉移。
總結
以上是生活随笔為你收集整理的微服务编排引擎Cadence简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 固态硬盘测试
- 下一篇: 量子物理 詹班 计算机,西南交大 大学物