熱點賬戶,7個解決思路
本文主要講述了熱點賬戶的概念及其解決思路,其中包括限制并發、匯總明細記賬、排隊辦理、緩存記賬、子賬戶拆分等多種方式,并舉例進行了詳細解釋。
我們經常聽到一個概念“熱點賬戶”,可能很多人不陌生什么是熱點賬戶,但是對如何解決熱點賬戶問題并沒有系統性的完整的思路;事物總是發展的,事物所處的場景也是在不斷變化的,基于有限的經驗去解決無限的可能性是很好的技能,我們試圖從認識熱點賬戶開始,再了解幾個常見的解決思路和案例,打開對熱點賬戶的世界。
對于賬戶我們要重點理解這幾知識點。
了解賬戶的結構是“入賬請求、賬戶流水、賬戶余額”;入賬請求產生了賬戶流水,賬戶流水更新賬戶余額;所以其中我們要關注賬戶流水的創建以及賬戶余額的更新,這里賬戶余額的更新要重點關注,這是后續造成熱點賬戶發生的主要的環節。
賬戶的賬務處理主要分三類:收錢,付錢,賬戶間轉賬;收錢針對一個賬戶的余額增加,付款是一個賬戶的余額減少,轉賬是兩個賬戶之間一個增加一個減少。
賬戶處理的存在最大并發量,超過這個并發量賬務處理就會出問題;賬戶賬務處理過程的線程控制,無論是收錢、付錢還是轉賬,為了保證賬務的準確性,每次賬務處理都是一個單獨的事務,就算是多個請求同時發生,對賬戶的操作也是一個一個的來;當一筆入賬請求開始處理時賬戶資源會被加鎖,等該筆請求處理完以后會釋放鎖;這樣的話就意味著每一筆賬務處理都會獲得一個時間占用,這個時間內其他入賬是不能操作的,這樣就出現了資源的瓶頸,也就是賬戶的入賬必然存在一個并發的最大閾值,一旦超過這個閾值,就會出現賬戶的性能問題。
熱點字段和熱點事件;在交易并發過程中,有些字段的使用頻率很高,比如流水號、余額、發生額等字段,這些使用頻率很高的字段稱為熱點字段;導致熱點字段的事件稱為熱點事件,比如商家結算日,需要給商家結算付款,這時候造成付款專戶的付款并發,這個就是一個熱點事件。
一、什么是熱點賬戶
業務發生以后會產生業務事件,比如下單支付,業務事件需要申請入賬;當在短時間內產生了大量的業務事件,或者狹義的看有大量的交易產生時,造成高并發的入賬請求,高并發引起了賬戶系統的性能瓶頸而產生了性能問題,進而造成入賬延遲、失敗、賬務準確性等各種賬務問題;而這個過程中涉及到的賬戶我們就稱為熱點賬戶。
所以說熱點賬戶是由于高并發交易時頻繁更新賬戶產生性能問題而造成的,所以這里一個關鍵的前提是“高并發”,那么熱點賬戶的標準是什么呢,在一些文獻里提到以下標準:
- 賬戶每秒有10次以上更新需求
- 串行化時賬戶處理延遲高于1秒以上
我想熱點賬戶產生的根本機理跟城市交通高峰時段的擁堵地段是一個機理,怎么解決高峰問題,錯峰出行,限號限流,分流等等;同樣熱點賬戶也是,既然是高并發造成的擁堵,我們就可以以降低賬戶上的并發為目的,也就是降低熱點賬戶的操作并發以降低賬戶熱度;像可以緩存記賬,可以批量匯總記賬,可以將賬戶拆分分攤并發,可以進行記賬排隊等等手段都可以降低對賬戶的高并發操作,從而降低賬戶熱度。
二、熱點賬戶常見發生場景
既然產生熱點賬戶的原因是高并發造成的賬戶被頻繁更新,所以我們探索熱點賬戶的發生場景就轉換成了探索交易高并發的場景,這些高并發場景都有可能造成熱點賬戶,比如很容易想到“雙11購物節”“微信發紅包”“某自營電商平臺的秒殺搶購”“小米官網新品的預售”等。
這里的場景有的是因為高并發收款造成的,有些是高并發付款造成的;而且收款和付款的熱點賬戶解決方案往往會存在差異,不同場景的收款和付款解決方案也會有差異;就像淘寶雙11收款,淘寶中間賬戶其實因為不外漏給用戶,后續商家履約周期也長,所以時效性要求并不高,可以考慮批量定時入賬、異步入賬、緩存入賬等,不采用實時入賬;所以我們可以將業務場景分為高頻入賬場景和高頻扣款場景;像淘寶雙11的中間擔保賬戶就是高頻入賬造成的熱點賬戶。
我們來分析一下淘寶雙11產生熱點賬戶的場景。
我們在淘寶購物時都清楚,錢是不會直接給到商家的,而是先收到中間擔保賬戶,等履約完成以后才會由擔保賬戶結算給商家,所以這里對于擔保賬戶來說有兩個過程,一個是用戶購買商品時的收款,另一個是服務履約以后的結算付款,而其中雙11期間的用戶付款就成了熱點事件,從而中間擔保賬戶的收款造成了擔保賬戶成為熱點賬戶。
上面我們介紹了,淘寶擔保賬戶是內部賬戶,并不外漏給用戶或者商家,這樣的話,只需要實時告訴用戶和商家已經付款成功即可,至于擔保賬戶的入賬可以慢慢的處理;這里我們也得到了一個思路,解決熱點賬戶要關注兩個問題。
一個是給用戶的反饋:對交易參與者的反饋策略,參與者需不需要實時知道賬戶的處理情況,是只需要知道結果即可還是需要實時看到賬戶余額的變化,顯然對于淘寶中間賬戶來說,賬戶參與者是不需要知道賬戶余額更新情況的,只需要知道支付成功的反饋結果即可,而這個結果可以依賴渠道的反饋通知,而內部記賬可以不反饋給用戶,這樣的話擔保賬戶就有了足夠的時間和選擇來規避并發問題。
另一個是賬務要求:賬務更新時效性要求高不高,賬務的準確性要求高不高,這里中間擔保戶對時效性要求不高,準確性肯定是所有賬戶要求都是很高的。
這樣我們可以使用批量的延遲更新中間擔保賬戶的方式來規避雙11高并發交易的入賬請求,以規避熱點賬戶的發生。
這里我們要知道個事實,數據庫插入數據的并發支持是非常大的,一般不會造成數據庫性能問題,批量插入即可,只是更新賬戶余額需要進行鎖處理,會造成性能問題,所以解決淘寶中間賬戶的關鍵是解決賬戶余額更新問題。
首先我們先將高并發的交易的入賬請求插入到入賬流水表,這時并不著急去更新中間擔保賬戶余額,此時這些流水我們標記一個入賬狀態“未入賬”;定時的去掃描這個流水表,將掃描到的數據進行加鎖,確保不會被后續入賬或其他處理影響,然后匯總求和,用這個求和的總值去更新中間擔保賬戶的余額,然后將這一批“未入賬”流水更新為已入賬,然后釋放鎖,這樣就以很小的并發完成了對中間賬戶的更新。
下面我們介紹幾種常見的解決熱點賬戶的方案,并且針對每個方案我們列舉一個實際的案例為補充;對于熱點賬戶的方案設計過程中,我們需要重點關注幾個問題:
- 收支:賬戶是收入熱點賬戶還是支出熱點賬戶
- 內外:賬戶是用戶熱點賬戶還是內部熱點賬戶
- 時效:賬戶是高時效性實時入賬還是不需要高時效性
- 結果:用戶是否需要實時知道入賬結果還是不需要
- 余額:用戶是否需要實時知道賬戶余額更新還是不需要
對于方案的設計和選擇可以先做以上幾個方面的分析,然后選擇合適的解決方案;比如上面淘寶中間擔保賬戶對時效性要求不高,用戶不需要感知余額的場景我們就可以選擇延遲批量匯總入賬。
對于方案的設計,我們就可以基于以上幾個問題從解決“賬戶的單位并發”為核心突破點,因為并發造成的頻繁更新是熱點賬戶產生的根本原因,所以解決的熱點賬戶并發的問題也就可以解決熱點賬戶的問題。
1. 限號限流-直接控制并發
第一性原理,不想太多,直接解決產生問題的問題本身;并發不是造成熱點賬戶么,那么反向思考,這個并發閾值是多少,在賬戶之前設到屏障控制這個閾值,開閘放水,門就這么大,只能進來這么多水,就像很多城市的限號限流一樣,最終的結果肯定是損害一部分車主的體驗;雖然是立竿見影的效果,但是這也是自損800的方案;這里我們不妨稱之為“熱點閥”。
所以給賬戶安裝“熱點閥”可以解決熱點賬戶問題;但是問題還是比較明顯的,除非你很強勢,比如交通控制,否則以服務為第一客戶優先的企業這種方式一般不會采用。
2. 變少為多-明細匯總記賬
數據庫插入數據是可以支持非常高并發,可能達到3.2w/s,所以插入流水不是熱點賬戶瓶頸所在,而是余額更新;所以我們就將“降低賬戶的單位并發”設計思路縮小到了“降低余額更新并發”的范圍;對于余額更新就是基于流水去增加或者減少余額,了解C語言的應該知道,無非就是下面的這個函數(不一定準確,但是這么個意思)。
balance=balance+發生額
就像新余額等于當前余額加上或減去該流水的發生額,降低余額的更新頻率我們自然就可以想到,可以降低發生額的更新頻率,也就是你們這個多人來更新我,我實在是忙不過來,都堵在門口,不如你們派一個代表10分鐘進來一次,匯總大家的要求我一次性解決;這樣就是我們說的“匯總明細記賬”的方法,這樣的話這個函數從意義上就變成了
balance=balance+sum(一段時間內全部明細的發生額)
這個方案的適用場景就是不需要實時更新余額,且主要是增加賬戶余額的場景如果是扣款類場景,可能匯總入賬會造成賬戶余額透支,不過如果允許賬戶透支,出款類場景也是可以考慮,只不過對資金管理的時效就會變差,你無法從賬戶余額直接看到剩余可用頭寸。
3. 排隊辦理-緩沖記賬
現在大家經常做核酸,因為并發較大,檢測人員有限不能實時采集樣本,所以大家需要排一個很長的隊伍;同時因為一個人一個人檢測成本也高,效率也低,所以10個人一組進行混采;混采就像我們上面說的指派代表的匯總記賬一樣;所以說我們可以為賬戶設置一個排隊機制,出現高并發賬戶更新不過來時大家進行排隊辦理。
就算排隊可以解決賬戶的并發問題,但是肯定是有天花板的,就像10個人采樣,100萬人排隊,那要做到什么時候,也可能發生抱怨和投訴;所以怎么辦呢?增加檢測點是一個很好的辦法,1000個人采樣,就可以分攤這么多的要檢測的排隊的人;這就是我們下面要講的“子賬戶拆分”分攤壓力。
4. 臨時存放點-緩存記賬
高并發請求可以先進行緩存,然后定時將緩存更新到數據庫;這個看起來跟緩沖記賬異曲同工,但這里有個區別,緩沖記賬時賬務請求還在排隊入賬,而緩存記賬實際上賬務請求已經實時在緩存中完成了記賬;緩存記賬具備緩沖記賬和匯總明細記賬的雙重優點。
這里要注意因為緩存需要具備賬戶余額部分的管理,所以賬戶系統的余額要賦予緩存模塊,緩存模塊在此余額基礎上進行出金和入金的記賬操作;定期將緩存同步到賬戶系統完成最終的記賬,記賬完成的緩存部分可以進行清空,然后獲得最新的賬戶余額,以此循環。
5. 增加點位-子賬戶拆分
當即要解決高并發的熱點賬戶問題又要保證實時性要求時,上面的會影響賬戶更新時效的方案自然就不是首選了,那么就需要一個能夠支持實時余額更新的方案了;既然一個賬戶的更新出現了瓶頸,那是不是可以考慮為他找更多的幫手分攤壓力呢?答案是肯定的;我們可以將賬戶進行按需拆分,拆分成多個子賬戶,將高并發請求分配給各個子賬戶,從而每個子賬戶的并發就降下來了;這里要明確一個問題,這個子賬戶更多是不能讓用戶感知的,只是內部的處理方案,對用戶來說還是一個賬戶,所以流水和賬戶余額反映給用戶的都是一個;這就意味著:
賬戶作為一個整體被用戶感知。
這樣的話勢必要增加很多賬戶設計的復雜程度,比如入賬的時候入哪個子賬戶,是平均入賬還是按序入賬,出賬的時候怎么出,有個別子賬戶余額不足但是總賬戶余額充足時怎么處理;所以說這里會有一個復雜的賬務處理模型;不管這個模型怎么設計,要保證金業務上順利完成賬務記錄要求以及用戶的使用體驗,從而確保業務的正常進行。
我之前設計的賬戶系統,每個商家可能會有七八個子賬戶,出款的時候是按照順序出款,就是先扣完一個賬戶扣下一個賬戶。
想起在某支付機構做了斷直連接入網聯的改造項目,其實網聯的項目方案里提到了其要作為人行支付系統的前置系統做人行熱點賬戶系統的前置緩沖,我想這個設計方法是不是可以借鑒到工作當中。
6. 小弟線上-前置緩沖
為解決備付金集中存管所形成的熱點賬戶問題,實現對已映射額度管理,網聯構建了“備付金熱點賬戶前置系統”即“RCMP”,用于支付機構通過網聯平臺(EPCC)的業務辦理。
前置系統分為額度管理模塊及賬戶管理模塊,網聯將為各支付機構在前置系統中建立賬戶,用于可用額度的監控、已映射額度的管理。
因為網聯是“實時清算,定時結算”,在一個清算周期內凈額軋差了支付機構的支付指令,最后提交給人行的結算請求筆數一個周期從每個機構的上千萬筆到一筆,這個看起來有點像匯總明細記賬,而這個匯總處理的操作是網聯代人行支付系統完成的。
那這么看,是不是我們工作當中也需求這樣一個前置系統,來幫助賬戶系統完成壓力的分擔,比如要求業務方建設前置模塊,按照要求進行處理加工后請求入賬;特別是賬戶中臺,面對眾多業務線時,是不是可以考慮每個業務線在某些場景下都做賬戶前置,完成初步加工后再請求中臺賬戶系統,這樣就可以分擔中臺的壓力,又不損害賬戶的中臺核心能力,業務線也不用完整建設賬戶系統;這里的思路就是中臺不能一攬子大包,一些能力要分攤給業務線,比如業務線的個性化部分,需要業務線做前置層。
7. 打鐵還需自身硬-技術性能升級
技術層面就不過多討論了,作為非專業人士,或者說產品視角提些建議“能多增加幾臺服務器么,可以擴充下硬盤么,你這個cpu可不可以換成頂尖的……”
事物總是變化的,場景也是不斷地更新,面對新的場景,新的問題,歷史的經驗只能作為解決新問題的參考;不妨在遇到虛擬問題時多思考一下真實的世界,也許會有意料之外的答案!
本文由人人都是產品經理作者【陳天宇宙】,微信公眾號:【陳天宇宙】,原創/授權 發布于人人都是產品經理,未經許可,禁止轉載。
題圖來自Unsplash,基于 CC0 協議。
- 目前還沒評論,等你發揮!