需求變更是信息化過程中的家常便飯,而在變更過程中如何儘可能小的影響線上業務是比較頭疼的事情。舉個車聯網監控的例子:原終端設備上傳車輛的經緯度數據,新的終端設備支持同時上傳速度數據,而舊的車輛狀態表數據量超過億級,此時如果Alter table add column將會造成數據 ...
需求變更是信息化過程中的家常便飯,而在變更過程中如何儘可能小的影響線上業務是比較頭疼的事情。舉個車聯網監控的例子:原終端設備上傳車輛的經緯度數據,新的終端設備支持同時上傳速度數據,而舊的車輛狀態表數據量超過億級,此時如果Alter table add column將會造成數據表上鎖,導致上傳或查詢車輛狀態數據等待。AppBoxFuture的存儲引擎在設計之初也是採用鎖表的方案,後來考慮到上述應用場景決定支持online schema change,但帶來了另一個難題是如何保證分散式環境下的一致性。
在權衡了利弊後,作者決定採用如下草圖所示的變更方案,主要是考慮工程實現上的便利性。實現的關鍵點是實體模型內有SchemaVersion標記,在添加刪除列、索引、EntityRef引用外鍵時,SchemaVersion+1, 同時所有表分區的狀態機內也有SchemaVersion標記當前的版本,如果變更過程中有舊版本的Insert\Update\Delete命令,則拋出SchemaChanged錯誤,由上層邏輯載入新的模型後重試。該方案的優點是實現簡單,且變更過程對線上業務的影響較小,缺點是變更任務不支持回滾,如遇到網路或磁碟錯誤則任務會稍候重試(冪等),添加惟一索引例外,遇到主鍵衝突任務不會重試,改為通知上層刪除該索引。
作者在虛擬機(I74C8G)內做了個單分區80萬行記錄添加列變更性能測試,如下動圖所示:
測試結果如下約0.8秒就處理完一個分區80萬行記錄:
#01/17/2019 11:17:07 [Debug] [StoreService.UpdateModelAsync]: Entity[VehicleState] schema changed, 2 -> 3
MetaAlterTable::TryRunAsTask: 開始提議分區變更任務至68719476742
MetaAlterTable::TryRunAsTask: 分區提議成功68719476742
KVAlterPartion::TryRunAsTask: 分區批次處理完成
MetaAlterTable::TryRunAsTask: all partition done, elapsed time:0.847791s
MetaAlterTableDone::Apply: 移除變更任務, 剩餘任務:0
KVAlterPartionDone::Apply: 移除分區變更任務, 剩餘任務:0
如果您有問題或Bug報告,請留言或在Github提交Issue。