公司重用我獨立負責一個核心系統(tǒng),我該怎么設計系統(tǒng)的高可用架構(gòu)
背景
今天給大家分享一個話題,就是對于線上跟錢有關(guān)的計費類的系統(tǒng),在線上可能出現(xiàn)的一些把錢算錯的問題,以及我們?nèi)绾蝸碓O計架構(gòu)解決這些問題。
但凡是跟算錢相關(guān)的系統(tǒng),都是每個公司的重中之重,比如說價格系統(tǒng)、運費系統(tǒng)、計費系統(tǒng)、支付系統(tǒng)、基金系統(tǒng)、財務系統(tǒng)、結(jié)算系統(tǒng)等等,因為這些系統(tǒng)運行過程中,隨時可能因為技術(shù)問題或者運營的人為誤操作問題,把錢給算錯了。
所以今天來給大家講講這一類跟算錢有關(guān)的系統(tǒng),我們應該如何來保證他不會把錢給算錯呢?
計費業(yè)務系統(tǒng)架構(gòu)設計
業(yè)務場景引入
首先,我們先來引入一個業(yè)務場景,假設我們現(xiàn)在有 B 端、M 端和 C 端三個系統(tǒng)。
其中 B 端可以由商家/入駐客戶/供應商/合作伙伴這一類 B 端角色對自己的一些計費規(guī)則進行設置和調(diào)整,M 端是是公司的運營可以進行統(tǒng)一的基礎性計費規(guī)則調(diào)整,C 端是面向用戶的,在處理一些請求的時候,會根據(jù) B 端和 M 端的計費規(guī)則進行計算,算出當前的支付金額。
如下圖:
這個時候可能你說了,這看起來沒啥問題啊,不就在平臺層和商家層允許修改計費規(guī)則,然后c端系統(tǒng)實時根據(jù)兩個系統(tǒng)的計費規(guī)則計算費用么。
真的是這樣嗎?上面那套計費模型里,看著簡單,其實蘊藏著大量的問題,下面來給大家一一說明。
業(yè)務系統(tǒng)消息同步丟失
首先,因為歷史原因,上述計費模型會非常的復雜,不是我們看起來那么的簡單。
實際上,B 端系統(tǒng)每次修改完了計費規(guī)則以后,是要把計費規(guī)則通過 MQ 同步給 M 端系統(tǒng)的,然后 M 端系統(tǒng)會匯總 B 端系統(tǒng)的所有商家的計費規(guī)則,接著后續(xù) C 端系統(tǒng)在計費的時候,是調(diào)用 M 端系統(tǒng)的接口拉取所有需要的計費規(guī)則來進行計算的。
如下圖所示:
單單就上圖這一個架構(gòu),就可能會讓我們在計費的時候可能因為一些技術(shù)原因出現(xiàn)問題。
比如說最典型的就是,不管因為什么,B 端系統(tǒng)那里修改了計費規(guī)則以后,可能因為網(wǎng)絡原因、MQ 故障、代碼 bug 等各種原因,并沒有同步到 M 端系統(tǒng)那里去,這就會導致 C 端系統(tǒng)一直用老的計費規(guī)則在計費。
嚴格來說,這就已經(jīng)導致計費錯誤了,如下圖所示:
這還僅僅只是同步問題導致的計費錯誤而已,其實還有更加麻煩的一個問題,那就是當 M 端系統(tǒng)收到了 B 端系統(tǒng)同步過來的計費規(guī)則了以后,他可能會陸續(xù)把復雜的計費規(guī)則寫入多個數(shù)據(jù)存儲中。
沒錯,你沒看錯,有可能 M 端系統(tǒng)會用異構(gòu)數(shù)據(jù)存儲架構(gòu),來存放不同的計費規(guī)則,比如 MySQL、MongoDB,等等。
如下圖:
| 計費業(yè)務系統(tǒng)計費問題
這個時候可能會出現(xiàn)一個問題,那就是 C 端系統(tǒng)可能會在你的一次計費規(guī)則同步的過程中,就從你 M 端系統(tǒng)這里來查詢各種計費規(guī)則來進行計費。
但是這個時候有可能會出現(xiàn)一個問題,那就是 MongoDB 里可能已經(jīng)是最新的計費規(guī)則,而從 MySQL 里查出來的還是老的計費規(guī)則,也就是說,完全可能會出現(xiàn),用了不一致的計費規(guī)則來進行計費。
比如下圖:
這是第二個可能出現(xiàn)計費錯誤的場景,第一個計費規(guī)則同步失敗和第二個計費規(guī)則并發(fā)讀寫,都是技術(shù)類的問題。
第三個計費錯誤的場景,就是我們的商家或者自己的運營,手欠甚至手抽,把計費規(guī)則改成了非常離譜的錯誤。
比如說,某一個計費規(guī)則正?;鶞式痤~是百元級別的,但是他給改成了幾塊錢,這可能會導致公司出現(xiàn)嚴重的損失。
如下圖:
所有這一切問題,都可能會導致計費的錯誤,那么說到這里,大家是不是想說,那還不簡單,case by case 的優(yōu)化和處理不就完了。
比如說對 B 端和 M 端系統(tǒng)進行大范圍的加固,實現(xiàn) MQ 消息不丟失保障機制,對 M 端系統(tǒng)異構(gòu)存儲寫入和讀取,加個分布式鎖,寫入的時候不能讀取,讀取的時候不能寫入,對運營修改計費規(guī)則的時候進行校驗,加入各種校驗規(guī)則,亂改就不讓你通過。
沒錯,大家說的這些其實都可以,但是不知道大家想過一個問題沒有,對于真正復雜的公司級系統(tǒng),比如上述的 B 端系統(tǒng),看起來在圖里僅僅是一個框而已。
其實一家公司里可能是幾十個人維護的大平臺,M 端系統(tǒng)也是同理,所以如果要推動各方實現(xiàn)各種技術(shù)方案來做保障,首先在跨部門推動方面成本就是很高的。
這僅僅是其一,其二,就是你現(xiàn)在做了一些措施做了加強,但是不代表以后就不會有新的問題了。
比如說,你對 MQ 同步實現(xiàn)了消息不丟失方案,可是哪一天如果 MQ 掛了呢?
比如說,你如果在 M 端系統(tǒng)實現(xiàn)寫入和讀取加分布式鎖做互斥,那可能會導致并發(fā)性能大幅度的降低。
比如說,你給計費規(guī)則修改加入校驗規(guī)則,可是隨著計費規(guī)則不停的變化,很可能會導致你的校驗規(guī)則失效,或者要持續(xù)不斷的加入更多新的校驗規(guī)則。
如下圖:
計費業(yè)務數(shù)據(jù)補償系統(tǒng)設計
所有這一切其實都是治標不治本,對于這一類線上跟錢相關(guān)的,固然應該在技術(shù)和業(yè)務上嚴防死守,但是這都依賴技術(shù)團隊的技術(shù)素養(yǎng),以及對業(yè)務校驗規(guī)則的持續(xù)維護,如果想要一勞永逸,那么通常我們會引入一套計費數(shù)據(jù)補償系統(tǒng)。
這個計費數(shù)據(jù)補償系統(tǒng),是額外獨立開發(fā)的,我們來看看,用這個系統(tǒng)我們會實現(xiàn)哪些功能來解決剛才看到的那些問題。
首先,從本質(zhì)上來說,我們不管具體的 B 端和 M 端的代碼邏輯是如何寫的,第一個有一點是可以肯定的,那就是 B 端和 M 端是需要實現(xiàn)數(shù)據(jù)同步和最終一致的。
所以說,我們不管他們之間是通過 MQ 來同步或者是什么,我們可以直接監(jiān)聽 B 端和 M 端系統(tǒng)的數(shù)據(jù)存儲,通過定時拉取數(shù)據(jù)來實現(xiàn)比對,如果一旦發(fā)現(xiàn)兩邊數(shù)據(jù)不一致,則自動實現(xiàn)補償。
如下圖:
接著我們再來看第二個問題,不管你的 M 端計費規(guī)則的寫入和查詢邏輯如何,最大的問題就是你的某一次計費結(jié)果可能并沒有按照一致和正確的計費規(guī)則來進行。
所以說,我們的計費數(shù)據(jù)補償系統(tǒng)可以直接讓 C 端系統(tǒng)的計費接口把每次計費請求的日志上報給我們。
接著我們可以同時把 M 端系統(tǒng)的每一次計費規(guī)則的查詢和修改日志也上報給我們,我們可以把相關(guān)日志數(shù)據(jù)存儲到大數(shù)據(jù)系統(tǒng)中。
接著我們就可以基于大數(shù)據(jù)技術(shù)來進行相關(guān)系統(tǒng)的日志運算,檢查一下每一次計費運算查詢多個規(guī)則的時候,是否出現(xiàn)了多個規(guī)則在短時間內(nèi)先后修改,然后導致使用了不一致的規(guī)則來計算的問題。
如下圖所示:
最后就是對于運營可能誤操作改錯計費規(guī)則的問題,我們可以拉取 C 端系統(tǒng)的每一次計費結(jié)果,然后對計費結(jié)果我們可以進行環(huán)比比對校驗。
就是說,你每一次計費結(jié)果都可以更過去的類似的計費結(jié)果進行比對,如果說差距過大,超過了 50% 的話,那么就會自動發(fā)送告警給運營,提醒他可能出現(xiàn)了計費額規(guī)則誤操作的問題。
如下圖所示:
總結(jié)
通過上述的計費數(shù)據(jù)補償系統(tǒng),就可以直接繞開所有的具體計費規(guī)則和計費邏輯,跟 C 端系統(tǒng)、B 端系統(tǒng)、M 端系統(tǒng)完全解耦。
采用自行拉取數(shù)據(jù)、拉取日志、拉取計費結(jié)果等手段,用大數(shù)據(jù)一類的技術(shù)進行各種檢測,從根本上解決問題,以此來實現(xiàn)線上計費系統(tǒng)因為技術(shù)問題或者誤操作問題導致的計費錯誤。
-?