# Sagas pattern
###### tags: `design pattern`
用在 microservices 間的 transaction model 如何維持 consistency
參考來源: [Using sagas to maintain data consistency in a microservice architecture by Chris Richardson](https://www.youtube.com/watch?v=YPbGW3Fnmbc)
[TOC]
## ACID is not option
在一個使用者購物情境中要保證, 購買商品的總額要 <= 使用者可用金錢餘額, 並建立新訂單.
### monolithic
在傳統的 monolithic 架構, 直接建立一個 transaction 在database 確認使用者的金錢餘額並建立新訂單. 符合 ACID 準則.
### microservice
在 microservice 架構中就是要把各種服務 loose Coupling. 因為每個 service 都會有自己的 database, 所以無法同時在 distribute database 使用 transaction sql.
### 2PC is not an option
雖然 2PC 可以保證 transaction 的一致性.
但是, 2PC 會遇到
* coordinator 發生問題
* 需要花許多時間去溝通(跟coordinator說這個交易在自己這邊是成功還是失敗, 收到coordinator 說可以commit 才commit)
* 因為 lock 降低 throughput
* 如果有 service 是用 NoSQL, 並不支援 transaction
* 在 CAP 理論裡面, 2PC 會影響 availability
## Overview of sagas
### 使用 sagas 替代 2PC

* sagas 模式下建立 order

### 如何處理 rollback
sagas pattern 無法像 ACID 的 transaction 一樣那麼容易做到 rollback, 需要 developer 自己寫 code 去處理.
* 當 T2 失敗後就要執行 C1 來 rollback T1 成功的 transaction.

### Sagas complicate API Design
當啟用 sagas 的 transaction 時要如何做 response?
* option 1: 當 saga 完成才做 response
* **pros**: 可以知道結果
* **cons**: 降低 availability(因為要等待後面一連串 service 的 response)
* option 2: 當 saga 建立時就先做 response (建議使用)
* **pros**: 增加 availability
* **cons**: client 需要透過 poll 或是被 server 通知來知道結果
### Revised Create Order API
* createOrder()
* return a new orderID
* 不用確認order 的內容正確性
* getOrder(id)
* client 可以定期透過這個知道 order status
### Minimal impact on UI
* 做非同步的處理
* 使用 popup 來告知 user 目前 order 是正在處理中.
* server 使用 push notification 給 UI
## Coordinating sagas
### How to sequence the saga transaction?
在每個 transation(Ti) 做完後都需要考慮下一步:
* Ti **成功**: 執行 T(i+1)
* Ti **失敗**: 執行 C(i-1)
#### Option1: Choreography-> ==distributed== decision making

* 增加 service 的 coupling. order service 需要寫更多 code 去處理 coustomer service 成功或是失敗的處理.
#### Option2: Orchestraction-> ==centralized== decision making

透過一個 CreateOrderSaga component 去告知每個 service 接下來要幹嘛.
* 每個 service 要建立APIs 提供 Saga component 做調用.
saga Orchestractor 可以視為 state machine. 根據每個 service 回傳的 status 去做下一個動作.
* **Implicit Orchestractor**
* Existing domain object, e.g. Order aggregate
* Tradeoffs
+ pros: Simple
- cons: Bloated responsibilites
* **Explicit Orchestractor**
* Dedicated object
* Tradeoffs
* pros: Improved separation of concern
* cons: Additional class
#### Event-based, implicit Orchestractor
用 event sourcing 來實作雖然容易, 但是協調者(Event Handler)需要負責很多事

#### Explicit Orchestractor
用一個 CreateOrderSaga 專門處理訂單的建立

**saga framework**:
stateless singleton.
CreateOrderSagaState: enum
CreateOrderSagaData: persistent data




## Transactional messaging
### Saga orchestrator <=> participant communication
* Saga orchestrator 會調用 saga participant
* CreateOrderSaga 會調用 saga participant 的reserveCredit(), create()/approve()
* Saga participant 會丟 reply
* Saga 必須要被完成, 不論成功或失敗
### Use asynchronous messaging
### Messaging channels
* Saga participant
* Subscribes to its command channel
* Sends to its reply channel
* Saga orchestrator
* Sends commands to the participant's command channel
* Subscribes to the participants reply channels
* (ensures ordering of all messages from that participant)

### Messaging must be transactional
下面這些動作 在更新 database 和傳送 messages 都要是 atomic.
* Saga coordinator
* Changes state
* Sends commands
* Processes replies
* Saga participant
* Process command
* Updates state
* Sends reply
### Use database table as a message queuue
透過建立一個 message table 來紀錄訂單的狀態, 但是會有一個問題是要如何通知 order service?

* Publishing message using **polling**
* Message publisher periodically polls the table
* Benefits:
* Simple
* Works well at low-scale
* Drawbacks:
* Latency and performance
* 很難去知道這個 message 是否已經被處理過
* Transaction **log tailing**
使用 database 的 log 系統來知道是否有產生 transaction

* 使用 database 的特定機制去讀取 transaction log
* MySQL binlog using master/slave replication protocol
* DynamoDB table streams
* ..
* Benefits
* Good performance/latency
* Easy to track position
* Drawbacks
* Database specific
* Obscure