內容來源:2017年4月22日,貝法易集團技術部總監黃亮在“2017年MongoDB中文社群深圳使用者組大會”進行《MongoDB在跨境電商物流供應鏈系統中的實踐》演講分享。IT 大咖說作為獨家視訊合作方,經主辦方和講者審閱授權釋出。
閱讀字數:2896 | 4分鐘閱讀
摘要
本次介紹下出口易跨境電商物流供應鏈系統從單體應用過渡到面向服務的分散式系統架構的過程中,遇到的一些挑戰和實現。其中包括了基於MongoDB建模和資料持久化方面上具體實踐。
關於出口易物流
出口易物流是廣州市貝法易商貿有限公司(簡稱貝法易)旗下,以全球倉儲為核心,整合全球物流網路系統,為跨境電商賣家提供海外倉儲、國際專線、國際小包、國際快遞、FBA頭程等物流服務以及本地化售前售後服務,解決訂單管理、金融融資難題。我們不是物流的供應商,我們是跨境電商全程物流解決方案提供商。
我們公司的重資產是人員,我們瞭解跨境電商物流,包括跨境電商通關的環節、關於物流方面的國際法律以及離境品的相關資訊,這些都是我們公司最寶貴的資源。
我們公司底下有一大群長期合作的供應商,這是我們最大的優勢。我們的難點也是在於這些供應商是不可控的,因為我們是在使用別人家的服務。
所以除了訂單系統還有一個很重要的資產就是我們自營的海外倉儲,這也是我們最核心的價值。
覆蓋歐美澳主要市場的服務網路
上圖是我們全球佈局的物流網路。這些倉儲有大有小,英國倉庫是我們最核心的倉庫。截至2017年,在國內我們一共有八個倉儲中心,重點的是在深圳、廣州和上海。
全球主流電商平臺重點推薦物流服務提供商
我們合作的平臺推薦我們的物流服務提供商有Amazon、ebay、wish、阿里國際、shopee、AliExpress還有LAZADA。
出口易新老架構演變過程
我們之前的系統是上圖左邊的架構,針對商家第三方的ERP和一些商家自己研發的一套系統,還有一些平臺跟我們的系統都是有直接互動。有的是通過出口易提供了一套UI來進行訪問,還有就是大量的線上發貨,我們會採用API來進行接入。我們後臺有admin管理後臺,還有單獨的一塊WMS系統。
我們認為這個系統有些過於龐大,想做一些調整。新的架構大部分還是沒有改動,只是在後端針對admin的系統想要往面向服務架構方向落地。基於業務場景的切分有兩塊,一塊是基於通用服務,比如說使用者的認證和授權,還有就是日誌。
支付有一些支付閘道器,有和paypal、alipay、payoneer還有銀行的介面。
下面是我們業務最主要模組,包括產品報價、客戶關係管理系統,還有訂單、物流網路和運輸,包括WMS、支付、物流軌跡跟蹤、供應商管理系統,還有結算報表等等諸如此類。
出口易老業務系統特點
單體應用:前後端系統共用一套WEB App Solution。
單一資料庫:採用MS SQLServer 資料庫,核心業務功能共用一個資料庫。
業務功能完整:IT系統隨業務的發展不斷擴充套件新功能。滿足開展跨境電商物流業務最基本的功能性需求。
容易測試和部署:單獨一個Solution,系統依賴少,一旦部署,全部功能即可測試。
出口易老業務系統不足
不夠靈活:對應用程式做任何細微的修改都需要將整個應用程式重新構建、重新部署。
妨礙持續交付:系統規模大,構建和部署時間也相應地比較長,不利於頻繁部署,阻礙持續交付。
受技術棧限制:包括開發語言,開發工具,資料庫一旦選定,無法根據實際需要作其他選擇。
技術負債:系統邏輯異常複雜,隨著時間推移,人員更迭,技術負債不斷累積。
出口易新業務系統特點
面向服務:根據業務模組切分不同的系統模組,系統模組採用面向服務架構。服務與服務通過明確的介面定義進行通訊。
領域驅動設計:每個業務模組團隊負責一個領域或業務功能相關的全部開發。核心領域根據DDD中明確定義的規則實現。
獨立部署、升級、擴充套件和替換:每個服務可以單獨部署,透明升級,不影響整個系統。
異構/採用多種語言:每個服務開發團隊,可以選擇自己熟悉開發語言,資料庫,開發工具和開發架構。
新架構落地的切入點
身份認證:每個服務都需要統一的登入認證。
鑑權:不同的使用者使用相同的服務模組都需要鑑權。
由單點登入的頁面包括基於OAuth2 API這樣的方式來接入。內部採用的是DDD這樣的一個邏輯架構,包括應用層、領域層。領域層裡面又包括了領域模型、實體子物件、領域服務、領域事件和查詢的規格。
基於倉儲,要存一個訂單,必須連線實體和子物件一起儲存重新整理到資料庫。
我們做應用的時候更偏向於完成業務,所以選用了mangoDB。我們有一套自己的架構,在封裝的過程中就會把mangoDB做一層封裝。
上圖中面向切面的架構包括了exertion、loading和cache等切面。
上圖是TMS系統調撥單聚合根示意圖,它包括了物流軌跡的集合、預計到貨時間等資訊,還有這些調撥單歷經的節點資訊。
為什麼選擇MongoDB?
1、非事務緊密型。錯誤資料容忍性相對比較高。
2、團隊成員有使用MongoDB開發經驗。對基於MongoDB方面的建模需要考慮的必要冗餘有一定的瞭解。
3、Portal 模組資料庫讀大於寫,基於MongoDB讀寫方面的高效能,解決了高併發下系統卡頓問題。
4、TMS 系統模型之間關係複雜,採用傳統關聯式資料庫,勢必增加一堆表。採用MongoDB,可以把複雜的模型,通過一個Doucment儲存到一起。
基於MongoDB開發需要注意的問題
集合之間不能Join,建模方面要特別注意。建議增加必要的冗餘,減少二次查詢。
僅僅支援單個Document級別事務。資料一致性錯誤時,要考慮增加必要資料監控和資料修復功能。
聚合查詢,需要通過MongoDB 聚合管道方式查詢,MongoDB C# 驅動提供了良好支援,但是相對Linq查詢還是比較繁瑣。
基於MongoDB的持久化實現
一、倉儲Repository
倉儲限定在對整個聚合根的操作上,提供聚合根的持久化和重建或查詢。
二、倉儲上下文Repository Context
負責事務處理。每個聚合根的倉儲都會關聯到同一個倉庫上下文。但是MongoDB 不支援事務,我們提供了虛擬實現。倉儲上下文應用了工作單元模式。
一些關注點
一、領域模型採用POCO(POJO)
簡單的CLR物件(簡單的Java物件),不繼承任何持久化框架中的基類,或實現任何持久化框架中的介面。領域層不引用MongoDB類庫。MongoDB倉庫層使用lambda expression 實現類的Map。
二、ID 生成器
有多種ID生成器可供選擇。GuidGenerator,OjbectIdGenerator,String OjbectIdGenerator,etc。我們ID一律使用String型別。所以直接使用MongoDB的StringObjectIdGenerator。
三、多型類的Map
如果把多型類(繼承)對映到MongoDB,需要指定已知型別。
四、一些需要了解的約定
NamedIdMemberConvention可以指定類的哪些屬性可以作為ID。
IgnoreExtraElementsConvention可以忽略Document中不存在於類中的欄位,否則會丟擲異常。
EnumRepresentationConvention可以指定列舉序列化的方式,我們都指定為BsonType.String。
MongoDB聚合框架(C#)
一、聚合框架
MongoDB2.2版本引入了此功能,是資料聚合的一個新框架。
這個框架一是對文件進行“過濾”,也就是篩選出符合條件的文件;二是對文件進行“變換”,也就是改變文件的輸出形式。其他的也包括按照某個指定欄位分組和排序等。
它其實是MapReduce的替代方案,但比MapReduce簡單。
該框架使用宣告性管道符號來支援類似SQL 中的Group by 操作的功能。不需要自己編寫自定義的JavaScript。
二、管道操作符
$project:資料投影,主要用於重新命名、增加和刪除欄位。
$match:過濾操作,篩選符合條件文件,作為下一階段的輸入。
$limit:限制經過管道的文件數量。
$skip:從待操作集合開始的位置跳過文件的數目。
$unwind:將陣列元素拆分為獨立欄位。
$group:對資料進行分組。
$sort:對文件按照指定欄位排序。
$geoNear:會返回一些座標值,這些值以按照距離指定點距離由近到遠進行排序。這個在地理資訊系統中比較常用。
總結
對於大多數的聚合操作,聚合管道可以提供很好的效能和一致的介面。
使用起來比較簡單,和MapReduce一樣,它也可以作用於分片集合。
輸出的結果只能保留在一個文件中,要遵守BSON Document大小限制(當前是16M)。
管道對資料的型別和結果的大小會有一些限制,對於一些簡單的固定的。
聚集操作可以使用管道,但是對於一些複雜的、大量資料集的聚合任務還是使用MapReduce。
今天的分享就到這裡,謝謝大家!