已提交的交易歷史
程式服務窗口計算,在區塊之外從鏈上即時讀取手續費表
自上次套用以來是否變化?
不寫入
協議交易
鏈上狀態
內核在執行時讀取常數時間
比對的是費率,不是級距位置門檻移動,或某一級被重新定價,都會改變帳戶實際付的錢,卻不改變它的級距序號。
最終費率由鏈來解析每一批都提交成功之後,該週期才記錄為已套用;中途當機會重放整個週期,這是安全的,因為計算是冪等的。
目前在運行的
以成交量為準的費率級距。 這個服務消費節點串流推送的交易歷史,累計各帳戶的成交量,並按排程做快照。一個週期結束,就計算每個帳戶在滾動窗口內的成交量,透過從鏈上即時讀取的手續費配置映射成級距,再分批把有變動的帳戶寫回鏈上。 這句話裡有幾個細節是承重的:- 級距表從鏈上讀取,絕不寫死。 服務若自己留一份副本,網路改了費率表之後,它還會繼續套用昨天那一張。
- 比對的是費率,不是級距序號。 只比級距序號,會漏掉兩種真實情況:門檻移動了,成交量沒變的帳戶卻落進不同級距;某個級距重新定價了,序號卻沒變。兩者都會改變帳戶實際付的錢,卻都不會改變序號。
- 最終費率由鏈來解析。 交易攜帶的是級距序號,執行過程對照鏈上即時的手續費配置把它解析出來。級距序號超出有效範圍,整批交易失敗,不會部分套用。
- 每一批都提交成功之後,該週期才記錄為已套用。 週期中途當機會重放整個週期,這樣做是安全的,因為計算是冪等的:同一個窗口產生同樣的結果。
失效模型
這些服務夾在兩個系統中間,而兩邊都會時不時不可用。設計一開始就假定了這一點,不把它當異常處理。 相依項目失效——資料庫、節點的資料流、節點的 API——會以退避策略重試,不會終止行程;重新啟動修不好一個連不上的相依項目,只會在故障之上再加一次冷啟動。仍然算致命的,是重新啟動修得好、或者必須讓維運人員看到的問題:啟動時配置無效、無法綁定健康檢查端點,以及 panic。 故障期間,行程保持運行、把自己回報為 not-ready,並累計錯誤計數。所以維運訊號是「not-ready 已經多少分鐘了」,不是「行程還活著嗎」;前者才是有用的問題,因為行程活著、卻已經一小時擷取不到資料,那才是真正的事故。 收到編排系統發出的訊號,行程會優雅關閉:停止工作、寫出檢查點、乾淨退出。少了這一步,每一次例行部署都要賠上一個還沒寫出的窗口和一次重放。週期算完了但還沒套用,不等於這個週期丟了。計算是冪等的,而且要等寫入成功才會記錄週期已套用,所以一次運行被中斷,恢復的方式是重做那個窗口,不是跳過去。
這個模式為何可以推廣
寫回路徑是通用的。協議裡本來就有設定帳戶級配置和設定全域配置的交易,而所謂程式服務,就是任何一個從已提交歷史中替這些交易算出一個值的行程。 費率級距是目前唯一在運行的。激勵計畫、推薦歸因和活動資格的形態一樣:對交易歷史做窗口計算,跟當前已套用的值比對差異,再分批寫回。它們該放在這裡而不是內核裡,理由和費率級距一樣——計算是週期性、面向歷史的,而執行需要的答案必須是常數時間的查表。這些都還沒有建構;可以推廣的是這個模式,不是「它們一定會採用這個模式」的承諾。 這些計畫的商業條款在費率與計畫中說明。本頁講的是結果如何上鏈。後續閱讀
索引器
這些服務所消費的資料流。
手續費
商業面:有哪些級距,各自的費率是多少。
IntentionKernel
寫回的配置在執行期間怎麼讀。
狀態模型
配置鍵為何帶版本,以及用戶端為何應當即時解析它們。