背景
隨著財(cái)經(jīng)支付業(yè)務(wù)的快速發(fā)展,考慮到未來訂單量持續(xù)增長,在線存儲(chǔ)遇到更大的挑戰(zhàn),需提前做好規(guī)劃。目前財(cái)經(jīng)支付主要業(yè)務(wù)都是使用 mysql(InnoDB)作為數(shù)據(jù)存儲(chǔ),因歷史訂單信息訪問頻率低并占用了大量數(shù)據(jù)庫存儲(chǔ)空間,期望將歷史數(shù)據(jù)跟生產(chǎn)最新交易數(shù)據(jù)進(jìn)行分離,當(dāng)前數(shù)據(jù)庫保留最近一段時(shí)間的數(shù)據(jù)作為熱庫,歷史交易存入另一個(gè)數(shù)據(jù)庫壓縮存儲(chǔ)作為冷庫(rocksdb),即數(shù)據(jù)庫冷熱分離。此舉將會(huì)極大的節(jié)省數(shù)據(jù)庫設(shè)備成本,減少因在線存儲(chǔ)空間不足擴(kuò)容導(dǎo)致停服不可用的時(shí)長,以下基于財(cái)經(jīng)支付的統(tǒng)一交易系統(tǒng)現(xiàn)狀做的相關(guān)案例分析僅供大家參考。
方案
技術(shù)選型
架構(gòu)圖
方案分析
因業(yè)務(wù)場景比較復(fù)雜,如果按照業(yè)務(wù)場景梳理工作量將幾何倍的增長,換種維度,數(shù)據(jù)庫相關(guān)的操作無非就是查詢、插入、更新,只要能在數(shù)據(jù)庫交互層實(shí)現(xiàn)保證查詢、插入、更新這些數(shù)據(jù)庫基本操作在增加冷熱分離后功能不受影響即可。財(cái)經(jīng)支付代碼有統(tǒng)一的分層規(guī)范,對數(shù)據(jù)庫操作全部收斂封裝至數(shù)據(jù)庫交互層,因此比較好改造,不擴(kuò)容的情況下,熱庫預(yù)計(jì)保留最近 X 天(時(shí)間可調(diào))數(shù)據(jù), X 天前的數(shù)據(jù)歸檔到冷庫。
方案對比
方案一:能夠徹底數(shù)據(jù)庫存儲(chǔ)壓力的解決方案,但是對冷庫性能要求太高,如果涉及的插入、更新、查詢能夠根據(jù)單號過濾時(shí)間,降低對冷庫的依賴。
方案二:適用于冷庫性能較低,涉及的插入、更新、查詢大部分無法根據(jù)單號過濾時(shí)間時(shí),需要熱庫歸檔表中轉(zhuǎn)過濾。
方案三:如果系統(tǒng)涉及的場景比較簡單,歷史訂單后續(xù)也無變更,可以按場景進(jìn)行歸檔。
方案選擇
交易:交易表負(fù)責(zé)記錄商戶訂單與財(cái)經(jīng)支付內(nèi)部訂單的映射、交易金額、買方和賣方等重要信息,最重要的功能是防止重復(fù)交易。但是冷庫相比熱庫性能較低,商戶訂單號無固定規(guī)則,無法根據(jù)單號判斷時(shí)間過濾減少冷庫壓力,而熱庫 cpu 使用率很低,熱庫數(shù)據(jù)庫計(jì)算不是瓶頸,因此交易選用方案二。交易歸檔表主要意義在于減少在線交易對冷庫的依賴。
支付:支付表負(fù)責(zé)保存交易單用了什么支付方式、該支付方式需要扣多少錢、從哪里扣、扣到哪里去等信息,涉及的訂單查詢、更新、插入都可以根據(jù)交易單號或者支付單號進(jìn)行判斷時(shí)間減少對冷庫的查詢,因此支付選擇方案一。
基本原則
為了充分的保證 0 事故,0 資損,方案設(shè)計(jì)時(shí),提出了以下基本原則,在研發(fā)、測試、代碼評審時(shí)均參考以下基本原則進(jìn)行層層把控,可以有效的避免生產(chǎn)事故的發(fā)生。
數(shù)據(jù)插入唯一性:
- 熱庫歸檔表的所有唯一鍵必須跟要?dú)w檔的熱庫表保持一致。
- 熱庫歸檔記錄已存在的訂單,冷庫必須有相應(yīng)數(shù)據(jù),
- 冷庫插入: 先 insert 冷庫成功后 再 insert 熱庫歸檔表
- 冷庫更新:更新冷庫數(shù)據(jù),使用同一個(gè)事務(wù) 先 delete 再 insert 冷庫數(shù)據(jù)
- 熱庫刪除:刪除熱庫數(shù)據(jù)時(shí)使用冷庫數(shù)據(jù)當(dāng) where 條件,所有熱庫字段(包含 ID)條件都滿足后才能刪除成功。
數(shù)據(jù)更新一致性:
- 冷庫無 update 操作,所有的更新操作必須在熱庫進(jìn)行,如果數(shù)據(jù)需要更新并且僅在冷庫存在,需同步到熱庫后,再在熱庫完成更新。
- 冷庫熱庫數(shù)據(jù)同時(shí)存在時(shí),以熱庫數(shù)據(jù)為準(zhǔn)。冷庫的數(shù)據(jù)來源只有熱庫數(shù)據(jù)同步到冷庫。
- 數(shù)據(jù)從冷庫同步到熱庫時(shí),操作歸檔表和交易表需保證在同一個(gè)是事務(wù)內(nèi)完成,涉及到的查詢必須使用寫庫。
數(shù)據(jù)查詢準(zhǔn)確性:
- 單筆查詢:查詢熱庫數(shù)據(jù)不存在時(shí),不存在再次查詢冷庫(如果單號中可以判斷訂單日期,可再增加一層日期過濾,減少冷庫查詢)
- 批量查詢:冷庫熱庫數(shù)據(jù)都存在時(shí)優(yōu)先返回?zé)釒鞌?shù)據(jù)。
- 批量查詢:合并冷熱庫數(shù)據(jù)后,需看原先查詢的接口順序是否有要求,如果對順序有要求合并后還需排序。
- 減少冷庫壓力:冷庫性能較低,線上實(shí)時(shí)交易盡可能減少對冷庫的查詢和依賴(可通過交易單號中的日期或者歸檔表進(jìn)行過濾)。
- 限制天數(shù)控制:數(shù)據(jù)庫交互 層天數(shù)控制 為 n,歸檔任務(wù)控制的天數(shù)為 m,要求 m>n。例如,mode 層 有些判斷訂單超過 n 天的才會(huì)查詢冷庫,歸檔任務(wù)只歸檔 m 天前的歷史數(shù)據(jù),分開控制可以防止因調(diào)整歸檔天數(shù)導(dǎo)致數(shù)據(jù)查不到情況。
具體細(xì)節(jié)
歸檔表結(jié)構(gòu)
歸檔表狀態(tài)流轉(zhuǎn)
一致性刪除
使用冷庫記錄的所有字段當(dāng)作刪除熱庫的 where 條件(包含自增 id),刪除熱庫和更新熱庫歸檔狀態(tài)為冷庫需在一個(gè)事物,任一失敗則回滾。
交易及支付任務(wù)(數(shù)據(jù)歸檔、刪除、兜底)
歸檔任務(wù)
查詢熱庫訂單表 X (時(shí)間可調(diào))天前的訂單,同步熱庫訂單到冷庫,插入熱庫歸檔表,歸檔狀態(tài)為處理中,放入延遲刪除 mq 消息。
歸檔刪除 TASK
常駐服務(wù) TASK 消費(fèi)刪除 mq 消息,rpc 調(diào)用交易支付提供的刪除接口,支持本地限流能力。
兜底任務(wù):
主要功能:查詢熱庫歸檔表中處理中修改時(shí)間超過規(guī)定時(shí)間的訂單強(qiáng)制執(zhí)行刪除操作。主要用來防止 mq 異常或者日常丟失消息時(shí),使用兜底任務(wù)可以補(bǔ)償消化處理中的歸檔記錄。
執(zhí)行邏輯
數(shù)據(jù)歸檔任務(wù)(每天啟動(dòng)一次)
for {
初始化查詢時(shí)間范圍和分頁
for{
查詢 X 天前交易單 limit 1000(索引排序,滾動(dòng)時(shí)間查詢)
if 記錄存在 并且 條數(shù)=1000 {
for 對于每條記錄 {
// 啟用x個(gè)協(xié)程處理
交易單冪等寫入冷庫(不保證最新,只保證冷庫數(shù)據(jù)存在性)
冪等寫歸檔記錄表(type: PROCESSING,熱庫數(shù)據(jù)刪除時(shí)再更新為COLD,歸檔記錄已存在HOT狀態(tài)更新為PROCESSING )
發(fā)MQ延遲消息,X min(可配置)后刪除熱庫數(shù)據(jù)
}
}
if 條數(shù)=1000 {
continue
}
時(shí)間范圍往下推進(jìn)
//記錄不存在
if 結(jié)束時(shí)間超過規(guī)定時(shí)間{
break (跳出循環(huán),任務(wù)結(jié)束)
}
redis記錄當(dāng)前查詢條件,方便后續(xù)任務(wù)重跑恢復(fù)繼續(xù)
}
}
刪除熱庫數(shù)據(jù),消費(fèi)MQ
消費(fèi)MQ記錄 {
查詢冷庫
數(shù)據(jù)一致性刪除(開啟事務(wù) 條件刪除熱庫數(shù)據(jù),更新歸檔記錄表狀態(tài)為COLD 結(jié)束事務(wù))
一致性刪除熱庫失敗,同步熱庫數(shù)據(jù)到冷庫,數(shù)據(jù)一致性刪除
}
兜底補(bǔ)償任務(wù)(每30分鐘啟動(dòng)一次)
{
查詢歸檔記錄表中狀態(tài)為PROCESSING,修改時(shí)間為X +Y min前的記錄 limit 1000
if 不存在 {
break
}
for 對于每條記錄
查詢冷庫
數(shù)據(jù)一致性刪除(開啟事務(wù) 條件刪除熱庫數(shù)據(jù),更新歸檔記錄表狀態(tài)為COLD 結(jié)束事務(wù))
一致性刪除熱庫失敗,同步熱庫數(shù)據(jù)到冷庫,數(shù)據(jù)一致性刪除
}
}
歸檔任務(wù)查詢時(shí)間滾動(dòng)機(jī)制:時(shí)間范圍第一次起始時(shí)間為固定日期(財(cái)經(jīng)支付訂單最早點(diǎn)日期),結(jié)束時(shí)間為指定日期,下次開始時(shí)間等于上次結(jié)束時(shí)間,結(jié)束時(shí)間為上次結(jié)束時(shí)間加上指定時(shí)間范圍)。每次查詢下一個(gè)時(shí)間窗口時(shí) redis 保存信息,指定日期,當(dāng)天任務(wù)的時(shí)間范圍,分頁數(shù)。
歸檔任務(wù)并發(fā)處理:需支持多任務(wù)分片并發(fā)處理
提升全天歸檔訂單量:為了不影響在線交易,全天 24 小時(shí) 區(qū)分 交易高峰、低峰、日常 三個(gè)不同時(shí)間段,歸檔速度不同。
交易-有歸檔表(查詢、新增、更新)
特點(diǎn): 唯一鍵有外部單號,訂單規(guī)則隨機(jī)無法根據(jù)單號判斷時(shí)間,因此必須有歸檔表。
查詢
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處理
存在以下部分情況可做特殊處理減少數(shù)據(jù)庫冷庫依賴。
- 單筆查詢:
- 根據(jù)外部單號查詢,如果查詢的 qps 較高,可以查詢冷庫前使用歸檔表進(jìn)行過濾判斷。
- 根據(jù)交易單號查詢,如果可以根據(jù)單號判斷時(shí)間,查詢冷庫前使用單號進(jìn)行時(shí)間范圍過濾。
- 批量查詢:部分功能管理后臺(tái)功能分頁查詢,對數(shù)據(jù)查詢范圍要求較高的增加冷庫查詢邏輯時(shí),可以增加傳入的查詢時(shí)間范圍的開始時(shí)間過濾是否需要查詢冷庫,針對冷庫熱庫都存在情況時(shí)優(yōu)先保留熱庫數(shù)據(jù)(只過濾同一分頁內(nèi)的相同單號數(shù)據(jù)),如果對結(jié)果有異議可使用單號單獨(dú)再次查詢返回最新再次確認(rèn)。跟產(chǎn)品和運(yùn)營確認(rèn)能不支持的就僅查詢熱庫。
更新
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處理
插入
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處
支付-無歸檔表(查詢、新增、更新)
特點(diǎn): 唯一鍵都為內(nèi)部單號,現(xiàn)有主要查詢可以根據(jù)單號判斷時(shí)間,不需要?dú)w檔表,可以徹底解決熱庫數(shù)據(jù)庫存儲(chǔ)問題。
查詢
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處理
存在以下部分情況可做特殊處理減少數(shù)據(jù)庫冷庫依賴。
單筆查詢:
- 根據(jù)支付單號查詢,如果可以根據(jù)單號判斷時(shí)間,查詢冷庫前使用單號進(jìn)行時(shí)間范圍過濾。
批量查詢:
- 根據(jù)交易單號查詢,如果可以根據(jù)單號判斷時(shí)間,查詢冷庫前使用單號進(jìn)行時(shí)間范圍過濾。
- 部分功能管理后臺(tái)功能分頁查詢,對數(shù)據(jù)查詢范圍要求較高的增加冷庫查詢邏輯時(shí),可以增加傳入的查詢時(shí)間范圍的開始時(shí)間過濾是否需要查詢冷庫,針對冷庫熱庫都存在情況時(shí)優(yōu)先保留熱庫數(shù)據(jù)(只過濾同一分頁內(nèi)的相同單號數(shù)據(jù)),如果對結(jié)果有異議可使用單號單獨(dú)再次查詢返回最新再次確認(rèn)。跟產(chǎn)品和運(yùn)營確認(rèn)能不支持的就僅查詢熱庫。
更新
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處理
插入
邏輯在數(shù)據(jù)庫交互層統(tǒng)一實(shí)現(xiàn)處
總結(jié)
- 支付因沒有歸檔表徹底解決了數(shù)據(jù)庫存儲(chǔ)壓力問題,大大的節(jié)省了數(shù)據(jù)庫存儲(chǔ)資源。
- 交易因新增了歸檔表,大大延緩了熱庫數(shù)據(jù)庫存儲(chǔ)壓力,為交易數(shù)據(jù)庫又額外提供了緩沖擴(kuò)容時(shí)間,為后續(xù)再次優(yōu)化徹底交易解決數(shù)據(jù)庫存儲(chǔ)問題提供了充足的時(shí)間。
成果
- 徹底解決了支付數(shù)據(jù)庫存儲(chǔ)壓力問題,有效的緩解了交易數(shù)據(jù)庫熱庫的存儲(chǔ)壓力。
- 數(shù)據(jù)庫熱庫保留天數(shù)可靈活調(diào)控,可以根據(jù)后續(xù)訂單量進(jìn)行合理調(diào)整存儲(chǔ)可用天數(shù)。
缺點(diǎn)
- 交易采用方案二新增了歸檔表,并且歸檔表里的存儲(chǔ)的全量數(shù)據(jù),僅能減緩交易和支付數(shù)據(jù)庫的存儲(chǔ)空間緊張情況,無法徹底解決數(shù)據(jù)庫存儲(chǔ)問題。
- 交易表釋放的 datafree 存儲(chǔ)空間無法提供給歸檔表使用,僅能交易表使用,需要不定期釋放交易表的 datafree 空間。