如果你是跟著文章一天接著一天實作的讀者,那麼你需要確保你的 :
Anser-Tutorial-Service
使用的是最新的v1.1.0
以上的版本
在本章,我們將基於第二十章所實作的「包含補償邏輯的協作器」進行延伸,啟用 Anser 的高可用性元件。
打開專案中的 docker-compose.yml
,你應該能看到一個這樣子的區塊:
anser_redis:
image: redis:latest
networks:
- anser_project_network
ports:
- 6379:6379
在本章中,我們將透過 Redis 作為我們的外部儲存媒介,而目前 Anser 僅有提供 Redis 驅動程式作為儲存的選擇。接著,打開 {Anser-Tutorial-Service}/init.php
移至底部應該可以看到這些內容:
use SDPMlab\Anser\Orchestration\Saga\Cache\CacheFactory;
use SDPMlab\Anser\Orchestration\Saga\Cache\Redis\Config;
//定義 Orch 備援機制 Cache 連線資訊
CacheFactory::initCacheDriver(CacheFactory::CACHE_DRIVER_PREDIS, new Config(
host: "anser_redis",
port: 6379,
db: 1,
serverName: 'AnserTutorialService'
));
透過 CacheFactory::initCacheDriver()
我們可以指定一種由 Anser 所提供的驅動程式作為高可用性保障的儲存媒介,我們選用 CacheFactory::CACHE_DRIVER_PREDIS
作為我們的驅動程式,再實體化 Config
類別傳遞到 Factory 中進行初始化。
如果你沒有修改 docker-compose.yml
的內容,你就不用修改 host
與 port
參數的內容。唯獨以下兩個參數可能是需要注意的:
db
:於 Redis 伺服器內的儲存資料庫。serverName
:提供協作器服務的伺服器名稱,這個名稱可以源自於作業系統的固定名稱,或是一個不重複的伺服器名稱。此名稱用於部署多台協作器伺服器時,分辨快照是源自於哪些協作器而來。啟用快照功能很簡單,你只需需要在協作器中打開參數即可,請移至 {project_root}/Orchestrators/CreateOrderOrchestrator.php
之中,並加入以下成員變數:
class CreateOrderOrchestrator extends Orchestrator
{
protected bool $useBackup = true;
/** hide **/
}
我們只需要將父類別 Orchestrator
的 protected bool $useBackup
覆寫為 true
,協作器就會在每個步驟時自動進行快照。此時快照的目標即是上一個小節我們於 CacheFactory::initCacheDriver()
初始化的儲存媒介。
我們可以在協作器內搞一些破壞,比如在最後一個步驟中幹些一些壞事:
//Step4 使用者錢包扣款
$this->setStep()->setCompensationMethod('rollbackUserWalletCharge')
->addAction(
alias: 'walletCharge',
action: static function (CreateOrderOrchestrator $runtimeOrch) {
exit;
$userKey = $runtimeOrch->getStepAction('userInfo')->getMeaningData()['data']['u_key'];
$total = $runtimeOrch->getStepAction('createOrder')->getMeaningData()['total'];
return $runtimeOrch->userService->walletChargeAction($userKey, $runtimeOrch->orderId, $total);
}
);
關注位於匿名函式中的 exit
,這個意外的結束符號會在協作器執行時期直接關閉整個 PHP 程式。在正常的流程中,我們將沒辦法再追蹤整個協作器,當然也無從進行補償。你可以想像,若是在複雜的業務邏輯中有一些沒被發現的錯誤程式混入了正式環境,造成了一些協作器的執行終止,分散式系統中的資料一致性將不復存在。
若是我們打開了快照功能,那麼一切都還是可以挽救。
打開 Postman ,讓我們直接對被放入 exit
的協作器進行請求:
因為 exit
的生效, PHP 沒有任何的輸出,就像沒有發生任何錯誤一樣。此時,你可以透過 Redis 連線程式連入 Redis 內(筆者使用 Another Redis Desktop Manager)。
若是你沒有改變 docker-compose.yml 的內容,那麼你的連線資訊將是:
打開 db1
你將能看到以下畫面:
上述的資料列就是快照的內容,就算協作器在執行時期內遇到邏輯損壞而導致停用,後續我們也有機會對這個協作器進行其他動作,以保障分散式的資料一致性。
在這章節中,我們透過啟用 Anser 的高可用性元件和快照功能,為協作器架構增添了一層保護膜。透過外部的儲存媒介 Redis,我們能夠在協作器的執行過程中,即時捕捉每一個重要的執行狀態,並在必要時能夠有機會存取這個備份。