基於區塊鏈錢包的賬務體系

背景

隨着公司業務逐漸增長,用戶跨越百萬級,向千萬級進發,原有的支付體系,已經很難在滿足如此巨大的支付體量,用戶賬戶的支付體系,需要進行升級改造。
就像每個程序猿都有一個烏托邦的夢,希望地府需要開發一套生死簿管理系統,希望天堂有一臺mac,對! I99+1 DB內存+1 CB硬盤夠不夠?

舊賬戶體系的弊端

1:系統龐大,舊體系屬於完整的清結算體系,系統過於龐大,包括交易、支付、銀行渠道、賬戶、清分、openapi等,但是實際上只需要支付功能即可
2:流程過長,支付流程經過漫長的調用鏈路,交易->賬戶->支付->清分,響應時間達到了600ms,客戶體驗非常差
3:穩定性差,舊系統屬於外包開發,一旦出現問題,難以排查問題和維護
4:體量過大,舊系統的表未進行分庫分表,某些表體量已經超過10億
5:併發性差,舊系統是基於悲觀鎖模式進行轉賬支付,無法支持過大的併發
6:跟蹤性差,無法進行消費跟蹤,反洗錢監控等等

新賬戶體系特性

針對舊體系的缺點,以及目前公司的使用情況,對賬戶體系進行重構,並且增加會計學賬務平衡法,方便財務使用
1:構建新的賬戶體系,並且封裝出針對各種場景的支付功能,方便使用和快速定位問題
2:簡化核心支付流程,採用異步+MQ解耦,將支付分爲核心+異步兩個部分,提高響應速度和穩定性
3:引入分庫分表機制,採用sharding/mycat,針對賬戶表採用一致性hash算法,減少後期增刪節點搬運數據的痛苦,針對流水錶,採用按月分表機制,可以有效的減少單表的數據體量
4:引入區塊鏈錢包思想,拆分賬戶爲多筆資金,可以有效的減少熱點賬戶,同時爲大數據集採打好基礎,可以方便的跟蹤資金流轉情況,監控反洗錢等違法亂象問題
5:引入財務會計學算法,進行賬務平衡,可以更加有效的滿足財務各種變態的需求

基於區塊鏈錢包思想的賬戶體系

應該沒有同學想看我在這裏表演分庫分表,所以直接進入正題之一:區塊鏈錢包,沒錯這玩意其實在區塊鏈裏面已經被玩壞了,但是它的思想並不落後,基於‘拆分’的思想,可以將單個賬戶拆分成更小的資金,粒度更加細小,好處也顯而易見,話不多說,直接上圖:
在這裏插入圖片描述
以上是賬戶和資金的關係,單個賬戶不再作爲最細粒度,而是包含了多筆資金,而資金則作爲單筆支付產生的最小粒度
那麼單筆資金的結構是怎樣的了,單筆資金採用了單向鏈表,記錄上一筆資金信息,組成一個巨大的單向鏈表網
在這裏插入圖片描述
這樣做的好處包括:
一:熱點賬戶變少,比如供應商S端,如果是基於賬戶粒度進行轉賬,需要對S端的賬戶也同樣進行加鎖(無論是數據庫鎖亦或是分佈式鎖),但如果是資金粒度,那麼就成了供應商S端的賬戶增加一筆資金,對!沒錯!只需要事務+插入即可完成(有的童鞋可能採用的是裸奔+重試+冪等,這不是討論的重點)
二:跟蹤資金流轉情況,還在爲了查看某個月註冊用戶在未來十幾個月的消費情況頭疼嗎?還在爲商戶M端備付金使用情況而頭疼嗎?還在爲了財務提的變態需求,需要查看某個時間點所有用戶剩餘餘額而頭疼嗎?((⊙﹏⊙)額,資金思想也解決不了這個問題,建議殺了這個財務->祭天,如果有哪位大大有解決方案,請共享一下!跪謝!),資金跟蹤基於單向鏈表,記錄上一筆資金來源,可以很方便的解決以上問題。
三:如微信發紅包,則可以看成某個用戶下的特殊賬戶,資金則可以作爲預分配好的單個紅包,從而解決併發問題(微信的紅包方案當然不是這樣,這個是根據錢包思想衍生出來的想法,作者未進行嘗試,不對結果負責!)
四:不需要轉賬流水,是的,資金錶即可滿足流水的跟蹤需求,可以幹掉流水錶這個妖豔的小婊砸啦!

這樣做的壞處包括:
一:資金變成最小單位,那麼表的體量將會變得更加巨大,因爲一個賬戶可能存在成百上千條資金,那麼資金錶的體量豈不是賬戶表*1000,好像搞出更大的事情了!
二:一次支付可能會使用到多條資金,比如用戶付200塊,但是用戶的資金卻包含了1個1塊的,2個2塊的一直到n個n塊的,如果是熱點賬戶需要加鎖怎麼辦?喔靠,感覺豈不是藥丸!

壞處的解決方案:
一:賬戶的資金存在有餘額和無餘額的資金,針對無餘額的資金,可以增加歷史資金錶,來減少當前具有餘額的資金錶的體量,分庫分表不就是幹這個的嗎,基於賬戶ID的一致性hash,資金信息可以準確的落到單表上,什麼這個表中不一定有對方賬戶,如果朋友之間相互轉賬怎麼辦?加個隱藏的中間系統賬戶不就行了嗎。
二:賬戶存在成百上千條資金概率非常低,在作者所接觸到的業務場景中,基本上不存在(假如是支付寶、微信這種大的BAT,另當別論,不過他們有更好的解決方案),而有可能存在如此多的資金的,大部分是供應商S端或者商戶M端,前面已經討論過,這個設計不會對供應商S端產生影響,那麼只需要針對商戶M端進行熱點設計即可

基於區塊鏈錢包思想的熱點賬戶

通過前面的討論,我們發現,熱點賬戶不可能在C端賬戶和供應商S端賬戶中形成,C端用戶手速不可能比系統的處理速度更快,供應商S端是收錢方,只需要插入資金即可,也不會產生熱點賬戶
那麼商戶M端熱點賬戶該如何解決了,或者說,如果真的出現了變態的熱點賬戶,該如何解決了?
‘拆分‘,沒錯,還是拆分,因爲基於錢包思想,已經不存在熱點的賬戶了,只會存在熱點資金,比如商戶M端賬戶現在有5000w,需要通過接口給他的客戶發錢(不要問我爲什麼會有這樣的場景,也不要問我這樣是不是有洗錢的嫌疑,作者所在的公司,現在就真的有這樣的業務場景,並且確實是合規的!),好嘛商戶所在公司的技術很牛逼,調用接口做到了併發1000次/s,如何破了?
在這裏插入圖片描述
答案是:將熱點賬戶裏面的資金也進行拆分,比如將第一筆5000w,在給供應商S端調賬加錢的時候,就可以進行拆分(是否熱點賬戶可以由前端界面進行控制,這樣更加靈活),將一筆拆分成了100筆,這樣單筆資金的併發就可以大幅度下降變成10筆/s,至於如何協調單筆資金的併發粒度,這裏就不再敘述了,各位都是編程小能手,我就不獻醜了。

會計學轉賬平衡算法

會計學首先要理解這幾個字:有借必有貸,借貸必相等
借記賬戶:借記業務是收款行或者收款人主動向付款行或者付款人發起的扣款業務。「借」字是指資產方的增加或者負債的減少,最常見的就是借記卡,也就是儲蓄卡。平時我們用儲蓄卡時,不能透支,只有有錢,就是資產,所以叫做借記卡。比如你在銀行儲蓄,收到工資到賬,對於個人來說銀行的資產多了,都是借記業務。會計科目裏面,對於個人來說, 借:銀行存款 貸:現金。
貸記賬戶:貸記業務是付款行或者付款人主動向收款行或者收款人發起的付款業務。「貸」字是指資產方的減少或者負債的增加,最常見的就是貸記卡,也就是信用卡。平時我們用信用卡時,額度減少,負債增加了,所以叫做貸記卡。比如你從銀行轉賬到別的銀行,或者從企業賬戶代付工資到各個員工賬戶,對於付款行來說銀行的資產都減少了,都是貸記業務。
可能大家看得一頭霧水,那麼還是上圖吧
在這裏插入圖片描述
會計學平衡賬務的方式,作者最開始的時候一直無法理解,不過最後作者大徹大悟,終於遁入空門,咳咳!頓悟其中,明白了原理,大家請看上圖,這是一個用戶充值並且消費的流程,具有通用性,
第一步:銀行賬戶加錢,C端賬戶加錢
第二步:C端賬戶減錢,供應商S端賬戶減錢
madede!怎麼回這樣?這不科學,
第一步裏面的銀行賬戶加錢,C端賬戶加錢,可看流程錢是流動的啊,明明是從銀行賬戶流動到了C端賬戶,按理不應該是銀行賬戶減錢,C端賬戶加錢嗎。
第二步裏面也是這樣,C端賬戶減錢買東西,我可以理解,爲什麼供應商S端賬戶也跟着減錢了,難道是出現了經濟危機,C端賬戶減錢買東西,供應商S端賬戶還要倒貼出錢?那中間的渠道商豈不是要上天了?
但作者要告訴你,這就是科學
在這裏插入圖片描述
沒錯,不過要配合前面的借記、貸記才能明白
第一步:銀行賬戶是資產類賬戶,屬於貸記賬戶,在這次轉賬中,貸記類賬戶應該記爲加錢,而C端賬戶屬於借記賬戶,它的錢增加了,也應該記錄爲加錢;
第二步:供應商S端賬戶屬於借記賬戶賬戶,所以當C端賬戶轉賬給它的時候,它們都應該記錄爲減錢;
是不是還沒有明白?
手動摸頭,那麼作者在解釋一下吧,

銀行賬戶你可以理解爲你們公司方在銀行裏面的賬戶,(這裏的銀行具有通用性,泛指銀行而已,支付寶,微信也是同理),當客戶充值的時候,客戶在銀行裏面的賬戶在減錢,轉賬倒你們公司的賬戶裏面,那麼你們公司的賬戶是不是應該加錢,那麼客戶充值100塊,你們公司的賬戶是不是該加100塊,客戶的賬戶是不是也該加100塊?是不是沒毛病?
供應商S端賬戶,屬於你們公司跟供應商達成的協議,類似備付金,屬於你們公司存放在供應商哪裏的錢,比如你們跟某個供應商達成協議,存放資金50萬在供應商哪裏,然後就可以通過接口發100萬的貨,那麼當C端賬戶轉賬給供應商S端賬戶的時候,你們在供應商哪裏的資金是不是也該相應減少了?比如用戶支付100元,買了一套碗筷,那麼你們公司在供應商哪裏的餘額是不是應該變成49900,減去100塊,是不是沒毛病?

淡定,如果一時半會理解不了,也可以看看其他的文章,網上這樣的文章太多了,我就不掛鏈接了,嗯~ o( ̄▽ ̄)o

結語

開源代碼? 這個就必要掛了吧 關於資金和會計學轉賬流程問題? 可以以資金轉賬爲主,異步進行會計學轉賬。 關於冪等問題? 資金信息中即可包含外部訂單號,實現冪等處理, 賬戶信息表是否還有存在的必要? 根據具體業務需求而定,作者設計的系統是包含了賬戶信息的,並且還保留了餘額字段,異步實現的餘額更新,不過這個餘額是有有效期的