網際網路賬戶系統的具體實現
在上一篇文章中我們通過場景舉例的方式,討論了一套相對通用的網際網路業務賬戶系統,從業務模型上應該如何定義。那麼除了從業務模型上進行定義外,在具體系統實現上又該如何設計?又有哪些需要注意的地方呢?在本篇內容中小碼農就和大家一起討論下賬戶系統的實現細節,希望可以和大家一起交流進步。
事實上賬戶系統的業務邏輯是比較複雜的,對 資料的一致性要求很高 ,特別是記賬動作涉及強事務特性;另外,效能問題也是常常制約賬戶系統穩定性的一個比較突出的方面。在這種情況下,我們還需要考慮 系 統的業務通用性設計 問題,而這必然也會涉及很多配置項的設計,增加系統的邏輯複雜度。但是,也只有處理好了這些問題,賬戶系統才能保證業務的持續擴張,否則再好的理念也只是空中樓閣。然而,處理好這些複雜的問題,事實上並不只是某一點的設計就可以達成的,既需要邏輯流程設計上的優化,也需要採用合適的技術方案,更需要一個合理的系統結構。
下面我們就從 系統結構、整體流程、資料模型、記賬規則,以及日終對賬 這幾個方面與大家探討從系統層面應該如何設計。另外對於賬戶系統中制約效能最常見的 熱點賬戶 問題,也會和大家一起探討。
系統結構
在之前的內容中,我們提到要設計一套可以滿足網際網路業務擴充套件的賬戶系統,所以賬戶是這套系統的基礎,為了更好地支援不同業務、或同一業務不同賬戶的開戶,我們需要將開戶邏輯設計成獨立的子系統,獨立地提供包括開戶、賬戶資訊查詢、餘額查詢在內的服務,以便邏輯複雜到一定階段後可以更容易的擴充套件。在完成開賬戶動作後,就需要根據業務規則,設計好邏輯體系下不同交易型別的記賬規則了,而這種 規則 配置是否智慧,則是賬戶系統是否通用的關鍵 ;配置完規則後賬戶系統就可以接收業務發起的交易請求,並根據規則的配置完成業務資金流的處理了,所以,從系統結構層面也需要將記賬核心服務設計成獨立的子系統;此外,為了適配業務層不同的交易型別,主要是隔離記賬邏輯與交易邏輯,還需要前置賬戶交易系統。
最後,為了確保賬戶餘額與流水之間的平衡,我們還需要在日終時對主要資金賬戶進行對賬核算,確保賬戶流水發生額與賬戶餘額的一致性。所以從系統結構層面,整個系統主要可以分為四個部分:
之所以在賬戶系統、核心記賬系統之上設定一層賬戶層交易系統,是為了將多變的業務交易邏輯與相對通用的記賬邏輯進行隔離,避免在核心記賬系統中冗餘過多的業務邏輯導致後續出現臃腫的情況。例如業務層的交易型別可能是複雜多變的,如車費充值、押金支付之類,而這樣的邏輯是沒有必要讓記賬系統感知的,記賬系統只需要根據交易系統傳遞的記賬規則,根據會計分錄完成資金流處理即可。
整體流程
為了確保系統能夠正常Run起來,需要對系統整體的流程進行規劃,這部分流程即包括線下流程,也包括線上流程,它是確保整個系統閉環的基礎。例如,以賬戶系統需要支撐A公司打車業務為例,假設賬戶系統已經存在的情況下,那麼它需要支撐這個業務應該經歷以下兩個階段的流程:
(一)、線下規劃配置流程
按照正常的流程設計,在業務開展之前,需要根據實際的業務資金流設計好具體的賬戶及交易資金邏輯,這部分邏輯一般是由PM與資金部門線下確認後形成正式的產品規格文件。之後,由具有許可權的運營人員通過後臺,或者前期在沒有完善配置系統的情況下,由技術人員初始化到系統中,由於這部分配置關係到交易核心流程,所以 在流程及操作規範的制定上要嚴格把控 ,避免配置錯誤導致的嚴重系統邏輯錯亂問題。
在這部分流程中我們首先需要配置業務主體,這裡需要為A公司配置客戶開戶資訊,之後需要按照之前業務模型定義的結構,在客戶下為其開通表示打車業務線網約車使用者,至此在系統中就完成了 “誰?要幹什麼? ”的定義。而具體 “怎麼幹?”, 則是在後面我們要重點配置的內容。
那麼具體需要配置什麼內容呢?
因為,賬戶系統本身是為交易邏輯服務的,所以我們需要明確業務中涉及賬戶邏輯的交易有哪些型別,例如在約車業務中主要涉及到 司機端開戶 、 乘客開戶、現金支付車費、餘額充值、餘額支付車費、司機提現 等這些交易型別,所以我們需要為這些交易型別定義交易編碼(tradeCode),並將其與之前開通的網約車業務使用者進行關聯,這樣在後續的系統交易流程中,就可以進行交易許可權控制,各業務線邏輯各自關聯自身的交易型別,以免互相干擾了。
而定義了這些交易型別以後,賬戶層交易系統具體接收到這樣的交易請求後應該怎樣執行邏輯呢?在網際網路公司早期業務發展的過程中,很多都是將賬戶邏輯與交易邏輯耦合在一起的,這樣會導致各個業務賬戶邏輯陷入要麼繼續耦合,要麼各自定製、重複開發的怪圈。
而要讓這種邏輯變得通用,就需要將其 規則化 ,即賬戶層交易系統接收到指定的交易請求型別後,會根據系統使用者交易規則配置,獲取開戶、記賬交易規則資訊,然後記賬系統和開戶系統就會按照規則指定的邏輯執行了,這種執行邏輯識別規則,不感知具體業務邏輯。在上述流程中,我們將“平臺層開戶”也設計成了規則,只是這種開戶動作介面並不對實時交易介面開放,一般是通過後臺設定,即通過後臺呼叫開戶系統機構(平臺)開戶介面,開戶邏輯根據網約車平臺層開戶規則,自動開立 “服務費賬戶”、“代收付平臺賬戶”、“結算賬戶”、“市場營銷賬戶” 這類開展網約車業務所需的平臺層賬戶體系。
其他開戶交易型別,如司機端開戶、乘客開戶由於需要在具體使用者註冊、司機入駐時通過實時交易介面自動呼叫Api開通,所以這裡需要配置好開戶規則即可;至於,各個涉及資金變動的交易型別,如車費支付、餘額充值之類,涉及到具體的記賬規則的邏輯,也需要通過配置相應的交易記賬規則,關於記賬規則的配置設計涉及一點會計知識的細節,會在後面的內容中介紹到。
(二)、線上系統交易流程
完成系統級的資料定義及規則配置後,整個賬戶系統就會通過開放Api,為各個業務交易系統提供線上賬戶交易介面服務了。
業務層交易系統向賬戶層交易系統發起交易請求後,系統會首先根據傳遞的客戶、使用者ID對請求許可權進行識別,只有在(一)流程中設定了客戶、使用者主體資訊的交易請求才被允許,之後賬戶層交易系統會根據傳遞的交易編碼(tradeCode)識別交易資料開戶交易型別,還是交易記賬型別。開戶交易型別則被轉發至開戶子系統進行開戶處理,開戶子系統根據tradeCode設定的開戶規則,完成註冊使用者賬戶體系的開通,如:乘客張三,會依次為其開通客戶身份、打車使用者身份、以及打車使用者涉及的餘額賬戶,餘額返現賬戶,押金賬戶的開通。
而如果為交易記賬型別,假設這裡為乘客使用現金支付車費,則請求被轉發至記賬子系統,記賬子系統根據業務線客戶、使用者ID、乘客業務使用者ID以及tradeCode獲取記賬規則,完成資金邏輯記賬處理。
規則涉及的賬戶邏輯如下:
記賬規則
在賬戶系統中,記賬規則邏輯的設計是最為複雜的一項設計,需要在兼顧會計邏輯的情況下,還需要將其設計成較為通用的規則,以上面使用者支付車費的賬戶資金邏輯為例,如何將其設計成規則配置呢?
在以上記賬規則表中,定義了業務線使用者ID(merchUserId),表示該業務模式在系統中的唯一編碼;記賬交易型別(tradeCode)由具體的業務線交易模式定義,例如打車業務使用者現金支付車費。這兩個欄位由定義客戶使用者資訊、使用者交易型別,可根據實際業務定義。
後面的欄位主要定義了賬戶交易邏輯的情況,例如changeType中定義的記賬,表示按照規則正常的借貸方向進行餘額更新,而凍結、解凍則是對賬戶餘額進行凍結、解凍操作,增加、減少是根據規則直接對賬戶進行增加及減少操作,之所以定義上述不同型別,主要是為了適應不同賬戶操作邏輯,具體定義及含義,大家也可以根據自身公司的實際業務情況進行定義。
可能這麼解釋大家會有比較大的疑問,我們以線上交易流程中涉及的網約車使用者現金支付車費的資金邏輯為例:
根據規則表的設計,以上規則描述了各賬戶資金流的變動邏輯,其中涉及賬戶型別、借貸方向、資金型別、記賬科目以及記賬步驟。當業務層交易發起至賬戶層交易系統後,賬戶層交易系統會獲取以上記賬規則,並根據規則描述的賬戶型別,找到普通消費使用者、平臺層使用者、普通服務使用者對應的賬戶資訊,並按照規則逐條進行記賬邏輯執行。
通用資料模型
在上面的流程及規則涉及中,以網約車業務為例,通過兩個流程說明了賬戶系統應該如何支撐著項業務,雖然,看著並不是特別複雜,但是從系統設計上看卻是涉及了很多實體資訊,接下來我們從資料建模的角度,看看如何設計系統的資料模型。
在模型中我們根據邏輯,抽象了客戶、使用者、賬戶相關實體,同時也抽象了賬戶流水、科目資訊、記賬規則、開戶規則,交易型別等資訊。系統通過這些實體設計相關表結構,系統就初步具備了運轉能力了,大家可以根據實際情況增加其他實體資訊。
會計科目
會計科目是賬戶系統中比較基礎的概念,它的定義決定了賬戶的一些屬性特徵,例如是否可透支,屬於資產類or負債類,可以根據不同公司財務的需求進行設計。
記賬策略
大家知道記賬動作是強事務的,按照正常記賬邏輯以上規則執行過程中涉及的4個賬戶更新需要具有原子性,要麼都執行成功,要麼全部回滾,而對於普通消費賬戶、普通服務賬戶,這些賬戶都屬於個人賬戶,在線上實時交易中的併發度是有限的。而對於平臺層賬戶,包括代收付賬戶、服務費賬戶等,平臺所有的交易都涉及這些賬戶的資金變動,所以如果在某一個交易過程中對其加鎖,會導致該賬戶記錄的加鎖-更新動作非常頻繁,成為熱點賬戶,影響系統性能。
所以在規則中我們加入了是否緩衝記賬的配置,一旦配置為緩衝記賬,則在執行該規則時,只是把該記賬邏輯放入緩衝佇列的邏輯與其他規則在一個事務中,而具體賬戶更新邏輯則是由緩衝記賬系統完成,該邏輯可設定為日間完成,或日終完成。
從而緩解熱點賬戶問題導致系統性能瓶頸,但是需要注意,這種方案也對緩衝記賬邏輯提出了比較高的要求,需要緩衝記賬系統儘量保證記賬動作執行成功,一旦執行失敗前面同步執行成功的記賬邏輯回滾起來會比較麻煩;另外,如果之前的同步記賬邏輯在傳送緩衝佇列成功後,自身邏輯又失敗了,則需要及時傳送衝正機制,取消該緩衝記賬動作。
日終對賬
為了確保賬戶餘額始終處於相對正確地狀態,需要對日終賬戶流水進行各種試算核對,確保所有流水發生額累加後的餘額+期初餘額能夠與當前餘額匹配,這裡會涉及到比較複雜的對賬邏輯,需要大家在實際系統研發實踐中加以考慮。
技術點拓展
在賬戶系統的研發設計過程中,還會涉及很多其他問題,例如賬戶流水資料量非常大,同時資料的留存時間又要求比較長,所以需要考慮資料的分散式儲存,目前小碼農所在公司,採用了TIDB這種分散式資料庫,大家可在實踐中根據自身情況進行選擇。
另外,賬戶的頻繁更新,在系統併發量非常高的情況下,還會遇到效能瓶頸,如何在保證使用者體驗及資料正確性的情況下,採取更多的技術手段,如採用Redis/Codis進行快取記賬,也需要在實踐應用場景中進行探索。
後記
由於賬戶系統邏輯相對比較複雜,涉及很多會計知識及細節邏輯,本文只是描述了一種理念與思路,真正做好這套賬戶系統還需要大家根據自身場景進行取捨與裁剪。由於作者水平有限,不足之處,還請多多包涵!
原文釋出時間為:2018-09-11
本文作者:無敵碼農
本文來自雲棲社群合作伙伴“ ofollow,noindex">程式員小灰 ”,瞭解相關資訊可以關注“ 程式設計師小灰 ”。