場景描述
很多企業(yè)會遇到數(shù)據(jù)庫升級、或數(shù)據(jù)庫遷移的情況,尤其是在自建數(shù)據(jù)庫服務向云數(shù)據(jù)庫服務、自建機房向云機房、舊數(shù)據(jù)庫向新數(shù)據(jù)庫遷移等場景。
然而,我們需要在整個移植過程中保證其穩(wěn)定性、避免數(shù)據(jù)遺失、服務宕機等情況,最常見的移植方法之一就是數(shù)據(jù)庫雙寫移植操作。
解決方案
如下圖所示,這個雙寫移植的過程為:
- 原始階段,程序只對一個舊數(shù)據(jù)庫進行讀寫。
- 在現(xiàn)有的讀寫舊數(shù)據(jù)庫的代碼程序基礎上,需要添加讀寫新數(shù)據(jù)庫的代碼。例如,在某個表中插入一條數(shù)據(jù)時,我們需要把這條數(shù)據(jù)同時插入到新舊兩個數(shù)據(jù)庫中。通常情況下,我們會并行執(zhí)行這兩個插入操作,以盡可能保持服務的原有調用處理時間。
- 當一個寫數(shù)據(jù)庫請求進來,我們將其寫入舊數(shù)據(jù)庫的同時,將一個很少的百分比流量寫入新的數(shù)據(jù)庫。
- 將寫入新數(shù)據(jù)庫的流量比緩慢提高,直到 100% 為止。在這個過程中如果出現(xiàn)問題,可以及時回滾,并在不影響生產環(huán)境服務的情況下進行修復。
- 寫移植完成后,開始逐步放量從新的數(shù)據(jù)庫中讀取數(shù)據(jù)返回給服務,如先允許 10% 的流量在新數(shù)據(jù)庫做讀操作。在這個過程中測量性能的同時對比結果,如果在讀操作中遇到問題,可以馬上回滾新數(shù)據(jù)庫的讀流量,并在不影響生產環(huán)境服務的情況下進行修復。
- 直到在新數(shù)據(jù)庫實現(xiàn) 100% 的讀寫操作一段時間沒有問題后,就可以停止與舊數(shù)據(jù)庫相關的代碼服務了。
在實際操作過程中,不止新舊數(shù)據(jù)庫的操作流量要逐漸開放,實際上新的數(shù)據(jù)庫的讀寫代碼也需要逐步的更新到生產環(huán)境服務中,以確保可迭代的穩(wěn)定平滑移植。
實踐方法與工具
整個過程中,除了自身系統(tǒng)架構的設計外,有兩個特別的工具在其中起到重要環(huán)節(jié):
- 負責可靈活、實時、穩(wěn)定放量、回滾的 Feature Flags 服務 (FeatBit)。
- 在整個過程中全方位(支持無侵入和針對性埋點模式)的監(jiān)測服務異常與及時報警的可觀測服務 (觀測云)。
使用 FeatBit 實現(xiàn)實時的數(shù)據(jù)庫移植請求流量控制
如下代碼所示,為某一個服務的數(shù)據(jù)庫讀取操作分流的示例偽代碼:
- 第 6 行代碼,調用?_fbService.BoolVariation("read-sport-olddb")?方法獲得流量控制返回值,如果為?true,則將讀取舊數(shù)據(jù)庫的 Query 函數(shù)添加到并行任務執(zhí)行隊列中。
- 第 9 行代碼,調用?_fbService.BoolVariation("read-sport-newdb")方法獲得流量控制返回值,如果為?true,則將讀取新數(shù)據(jù)庫的 Query 函數(shù)添加到并行任務執(zhí)行隊列中。
- 第 19 行代碼,為使用 FeatBit Feature Flags SDK 同時運行兩個數(shù)據(jù)庫讀取操作,并將結果進行對比驗證,根據(jù)執(zhí)行情況返回正確值,并向觀測云發(fā)送相關異常數(shù)據(jù)。
public async Task<List<Sport>> GetSportsByCityAsync(int cityId, int pageIndex, int pageSize)
{
var tasks = new List<Task<List<Sport>>>();
// 當讀取 Sport 相關業(yè)務的舊數(shù)據(jù)庫開關返回 true 時,則添加讀取任務到執(zhí)行任務隊列
if (_fbService.BoolVariation("read-sport-olddb"))
{
tasks.Add(GetSportsByCityQueryAsync(_oldDbContext, cityId, pageIndex, pageSize));
}
// 當讀取 Sport 相關業(yè)務的新數(shù)據(jù)庫開關返回 true 時,則添加讀取任務到執(zhí)行任務隊列
if (_fbService.BoolVariation("read-sport-newdb"))
{
tasks.Add(GetSportsByCityQueryAsync(_newDbContext, cityId, pageIndex, pageSize));
}
// 同時執(zhí)行兩個讀操作(為了避免新增數(shù)據(jù)讀取增加請求時間),并將結果進行對比并返回
// 如果結果不一致,則返回舊數(shù)據(jù)庫讀取結果,并進行記錄
return await _fbService.RunAndCompareDbTasksAsync(
tasks,
timeoutDelayForNewDB: 3000, // 設定新數(shù)據(jù)庫的最長等待時間,避免不良體感
(timeoutInfo) => { }, // 當新數(shù)據(jù)庫調用超時,發(fā)信息至觀測云
(unMatchInfo) => { }, // 當返回結果不一致時,發(fā)信息至觀測云
(exception) => { } // 當出現(xiàn)異常時,發(fā)信息至觀測云
);
}
在把類似于上述的代碼逐步的集成到我們的項目中之后,就可以通過 FeatBit 提供的 Feature Flags 控制中心來控制每一個對應的數(shù)據(jù)庫移植的雙寫雙讀放量工作了。例如我們先將 feature flag?read-sport-from-newdb?放量調整到 5%,若在一段時間未在觀測云中觀察到異常狀況,增大放量百分比至 10% (如下圖)。
使用觀測云觀測移植全過程,及時發(fā)現(xiàn)潛在問題
在整個的數(shù)據(jù)遷移過程中,自動化的、及時發(fā)現(xiàn)錯誤問題并回滾,是極為重要的。他可以最有效的幫我們避免諸多問題,如:
- 新數(shù)據(jù)庫操作帶來巨大的系統(tǒng)資源消耗時,我們需要第一時間知道并通過 Feature Flags 系統(tǒng)立刻回滾。
- 當某個寫操作或讀操出現(xiàn)時間操作超時數(shù)量超過預估閾值時,我們可以快速定位問題,回滾的同時進行快速的修復,提高移植的速度。
- 當某個寫操作或讀操作出現(xiàn)信息錯誤時(如結果不一致、請求時間過長、程序異常等),我們可以根據(jù)觀測系統(tǒng)具體定位錯誤信息,從而加速 debug 的速度。
- 等等
實現(xiàn)這些,我們只需要:
- 根據(jù)《觀測云文檔:快速入門》,選擇與自己業(yè)務相符的技術棧,進行小白式的在 15 分鐘內完成配置和安裝。
- 運行你已有的服務程序,開始你的數(shù)據(jù)庫系統(tǒng)移植。
- 打開觀測云控制臺的「應用性能檢測」頁面,定位到鏈路,你將看到所有服務的運行情況。
通過「鏈路」與「錯誤追蹤」快速定位移植錯誤
通過「鏈路」頁面,我們發(fā)現(xiàn)在移植過程中,出現(xiàn)了一些紅色項(即 Error),通過資源列可以輕松的看到我們在對新數(shù)據(jù)庫的讀取操作中出現(xiàn)了錯誤異常,如下所示:
點擊對應的 Error,我們可以快速查看其對應的調用鏈路火焰圖。如下圖所示,根據(jù)火焰圖的解釋:
- 如下圖?①位置的 Span 所提示,在這個地方出現(xiàn)了數(shù)據(jù)庫移植的 Timeout 錯誤,即新數(shù)據(jù)庫的讀取時間超出了我們可以接受的請求響應時間閾值。
- 如下圖?②位置中,指出錯誤發(fā)生在 Feature flag?read-sport-newdb?為?true?的情況下面。也就是說我們可以快速定位可能需要回滾或關掉的 Feature Flags,從而避免移植風險。
- 而根據(jù)?③位置 Span 可以快速定位出現(xiàn)超時現(xiàn)象的服務端 API 服務,并且根據(jù)捕捉到的 API 的參數(shù)與 Header,可以幫助我們后面去更好的調試解決問題。
通過 Feature Flags 實時將讀操作回滾至無超時狀態(tài)
根據(jù)上面的「鏈路」查找方式,我們快速定位到了出現(xiàn)異常的數(shù)據(jù)庫讀操作。那么,我們只需要回到 FeatBit 的后臺界面,找到上面發(fā)現(xiàn)的開關?read-sport-newdb,并將其放量為 true 的百分比向后回滾即可。如下圖所示,將 true 的百分比從 10% 回滾到之前未出現(xiàn)讀數(shù)據(jù)異常的 5%的流量分配。
回滾后,下面代碼所示的?_fbService.BoolVariation("read-sport-newdb")?返回值,只會將有 5% 的比率為?true。文章來源:http://www.zghlxwxcb.cn/news/detail-664099.html
// 當讀取Sport相關業(yè)務的新數(shù)據(jù)庫開關返回 true 時,則添加讀取任務到執(zhí)行任務隊列
if (_fbService.BoolVariation("read-sport-newdb"))
{
tasks.Add(GetSportsByCityQueryAsync(_newDbContext, cityId, pageIndex, pageSize));
}
總結與后續(xù)
這篇文章介紹了使用觀測云與 FeatBit 通過雙寫雙讀的操作方式實現(xiàn)了降低數(shù)據(jù)庫移植風險的基礎方法。
在實際運行中,我們可能有大量的業(yè)務需要處理,人為的介入和操作會因為各種原因造成反應不及時的問題。在后續(xù)的文章中,我們將介紹更多的內容,如:文章來源地址http://www.zghlxwxcb.cn/news/detail-664099.html
- 使用觀測云的指標服務與 FeatBit 的?Trigger 服務,實現(xiàn)移植時自動化實時回滾避災與報警方案。
- 使用觀測云的指標服務與 FeatBit 的?Scheduler 服務?,實現(xiàn)自動化的放量與回滾方案。
到了這里,關于使用 Feature Flags 與可觀測工具實現(xiàn)數(shù)據(jù)庫灰度遷移的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!