在電商業務高速增長的今天,傳統單體商城系統越來越力不從心 —— 代碼堆成一團、改一點牽一片、想加功能得大動干戈,根本扛不住高并發、多場景的業務需求。微服務架構卻能破這個局:把系統拆成一個個能獨立部署的小服務,每個服務專心管一塊業務,開發、測試、上線各干各的,靈活得很。
ZKmall 開源商城就基于 Java 技術棧搭了套完善的微服務體系,靠著合理的模塊拆分和高效的服務通信,實現了系統高可用、易擴展還能快速迭代。今天就來好好說說 ZKmall 是怎么拆分模塊、怎么讓服務之間順暢通信的,給 Java 商城系統的微服務改造當個參考。
一、為啥微服務成了電商系統的香餑餑?
電商業務越做越大,商品多了、用戶多了、營銷花樣也多了,傳統單體架構的毛病就全暴露出來了。微服務架構靠著 “化整為零” 的思路,把復雜系統拆成一堆小服務,每個服務各管一攤,給電商系統規模化發展鋪好了路。
業務拆解開,迭代才叫快。傳統單體商城里,商品、訂單、支付的代碼攪在一起,改個商品搜索功能,說不定訂單流程就出 bug,真是牽一發而動全身。微服務把不同業務拆成獨立服務,服務間靠標準化接口說話,邊界清清楚楚。開發團隊各管一塊,商品團隊優化搜索時,訂單團隊該升級下單流程升級,互不耽誤。有家綜合電商換了微服務架構后,新功能上線從 2 周縮到 3 天,開發效率提了 70%,業務線之間吵架都少了 90%。
想擴就擴,不用瞎浪費資源。電商流量波動大,平時訂單不多,大促一來訂單量能翻好幾倍。單體架構得按峰值配服務器,平時就空著浪費。微服務就靈活多了,哪個服務壓力大就單獨擴哪個。大促時訂單服務擴到 10 個服務器實例,商品服務 3 個就夠;平時再縮回去,省不少錢。有家服飾電商 618 大促,就靠這招,訂單服務單獨擴容,穩穩扛住 3 倍流量,服務器成本降了 30%。
一個服務掛了,其他還能跑。單體系統最怕一個模塊出問題,整個系統都癱了。微服務里服務都是獨立的,支付服務出點小問題,訂單服務還能先記著訂單,等支付好了再處理;商品服務某個實例崩了,其他實例接著干活,用戶根本感覺不到。有家生鮮平臺用了微服務,單個服務出故障時,影響范圍縮到 5% 以內,系統全年能用的時間從 99.5% 提到 99.95%,因為故障丟的訂單少了 80%。
技術棧能靈活選,不用一棵樹上吊死。不同業務對技術要求不一樣,商品搜索要快,訂單處理要準,支付安全最重要。微服務里每個服務能選最合適的技術:ZKmall 的搜索服務用 Elasticsearch,查得快;訂單服務用 MySQL,保證數據準;用戶服務加個 Redis,登錄快。開發團隊不用被一種技術捆死,想試試新技術也容易,試錯成本低。
二、模塊咋拆分?按業務邊界來,不瞎拆
模塊拆分是微服務的核心,拆得好,服務邊界清,改起來方便;拆不好,還不如單體架構。ZKmall 照著領域驅動設計(DDD)的思路,按業務領域劃邊界,每個服務專心管自己的事,內聚性高,相互不添亂,為后面服務通信和維護打下好基礎。
核心業務拆成六大塊,各管一攤。ZKmall 把電商核心業務拆成六個核心服務,每個服務專注一塊業務,從開發到存儲都獨立:
- 商品服務:管商品從生到死的全流程,商品叫啥、賣多少錢、有啥規格、庫存多少,從上架到下架都歸它管。
- 訂單服務:處理下單、訂單狀態變來變去、訂單拆成幾個包裹、對接物流這些事,保證訂單數據沒錯。
- 用戶服務:管用戶注冊、登錄、改信息、會員等級、積分這些,是所有業務的基礎。
- 支付服務:對接微信、支付寶、銀聯這些,處理付錢、退款、查賬單,保證錢的事不出錯。
- 營銷服務:搞各種促銷,發優惠券、滿減、秒殺、拼團、分銷,怎么能讓用戶多買東西就怎么來。
- 搜索服務:讓用戶能搜到商品,還能篩選、排序,查得快、準,幫用戶快點買到東西。
還得有幫襯的服務,核心服務才能跑起來。光有核心業務服務不夠,還得有幫忙的服務搭架子:
- 網關服務:系統的大門,所有外面來的請求都從這進,負責把請求送到對應服務,還能擋擋壞人、控制流量。
- 注冊中心服務:記著所有服務在哪,服務一啟動就來登記,其他服務要找它就來這查地址。
- 配置中心服務:所有服務的配置都放這,數據庫密碼、緩存參數啥的,改配置不用重啟服務。
- 消息服務:靠消息隊列讓服務間異步通信,一個服務干完活發個消息,其他服務收到再接著干,不用等著。
- 日志服務:收集所有服務的日志,出問題了能查到哪錯了。
- 監控服務:盯著各服務的狀態,響應快不快、錯得多不多,不對勁就報警。
服務邊界劃清楚,別你中有我我中有你。ZKmall 拆服務時守著 “高內聚、低耦合” 的規矩:
- 每個服務只管好自己領域的事,商品服務就管商品,別去碰訂單的數據。
- 服務間靠接口說話,接口定好了,里面咋改不影響外面。
- 別共享數據庫,各用各的庫,不然一個服務改表結構,其他服務全完蛋。
- 業務流程要跨服務時,靠發事件協調,別直接調用一堆接口。
服務大小不是一成不變的,能大能小。剛開始業務簡單,用戶服務和會員服務可以放一起;后來會員等級、積分規則越來越復雜,就單獨拆出個會員服務。商品服務一開始管庫存,后來庫存要搞預售、分倉,就拆出個庫存服務專門管。拆的時候慢慢來,先在原來的服務里留好接口,新服務跑順了再把流量切過去,業務不受影響
三、服務間咋通信?該實時實時,該異步異步
服務拆成一個個的,肯定要相互通信。ZKmall 根據不同業務場景,該實時就實時,該異步就異步,兩種方式配合著來,既保證用戶操作有反應,又能讓系統處理更多請求。
實時通信用 REST API,說句話馬上等回應。有些場景得馬上有結果,比如下單時得查商品還有沒有庫存、用戶能不能買。ZKmall 就用 REST API,服務間發 HTTP 請求,等著對方回應。訂單服務創建訂單時,調用商品服務的接口查商品信息,調用庫存服務的接口鎖庫存,調用用戶服務的接口看看用戶狀態。接口都按標準來,用 JSON 傳數據,格式統一,包含狀態碼、消息、數據三部分,好調試。為了防止重復調用出問題,接口都設計成冪等的,比如下單接口用訂單號當標識,調多少次都只創建一個訂單。有家服飾電商這么干,服務間實時調用成功率 99.9%,接口響應時間都在 200ms 以內。
異步通信靠消息隊列,發完消息不用等。有些場景不用馬上處理,比如下單成功后要減庫存、發優惠券、通知物流,這些可以慢慢弄。ZKmall 就用消息隊列,一個服務干完活發個消息,其他服務收到消息再處理,不用等著。訂單服務創建訂單后發個 “訂單創建成功” 的消息,庫存服務收到就減庫存,營銷服務收到就改優惠券狀態,物流服務收到就安排發貨。這樣訂單服務不用等其他服務處理完,馬上告訴用戶下單成功,系統能處理更多請求。消息還能存起來,萬一哪個服務當時沒接住,后面還能再讀,保證不丟。有家綜合商城用這招,訂單創建流程響應時間從 500ms 縮到 200ms,系統能處理的訂單量翻了 3 倍。
服務在哪不用記,注冊中心幫你找。服務地址可能會變,服務器擴容、重啟,地址都可能變。ZKmall 用注冊中心,服務一啟動就去注冊中心登記自己的地址;其他服務要調用它,就去注冊中心查最新地址。注冊中心還盯著服務活沒活,服務崩了就把它從列表里去掉,別再發請求過去了。調用的時候還能挑挑揀揀,輪著來、按權重來,別讓某個服務太累。有家生鮮平臺這么弄,服務擴縮容不用改配置,新服務起來 30 秒就能接到請求,用戶根本感覺不到服務在變。
服務出問題了能熔斷降級,別把整個系統拖垮。服務調用可能超時、出錯,比如支付服務卡了,訂單服務一直等著就會卡死。ZKmall 用熔斷降級,就像家里的保險絲,電流太大就斷開。用個 “熔斷器” 盯著調用情況,失敗太多就 “熔斷”,后面的請求直接返回個默認結果,比如 “支付有點慢,先幫您記下訂單”。過一會兒再試試,服務好了就恢復調用。不重要的功能可以降級,比如商品詳情頁的推薦商品加載不出來,就顯示默認的,別影響用戶看商品。有家跨境電商這么一弄,支付服務偶爾出問題時,訂單還能接著下,少丟了 90% 的訂單。
跨服務操作要保證數據一致,別這邊變了那邊沒變。一個業務可能跨好幾個服務,比如下單要減庫存,庫存減了訂單沒創建成,就出問題了。ZKmall 用 “最終一致性” 的辦法:訂單服務先創建個 “待確認” 的訂單,發個消息給庫存服務;庫存服務減庫存,減完了發個消息;訂單服務收到消息,把訂單改成 “已確認”;要是庫存不夠,訂單服務就把訂單取消。要求特別嚴的場景,比如支付和訂單狀態同步,就用 TCC 模式,先試試能不能鎖資源,能就確認,不能就回滾。有家家居平臺這么做,跨服務數據不一致的問題少了 95%,用戶投訴訂單和支付狀態對不上的幾乎沒有了。
四、通信得管好,別亂套
服務多了,通信關系越來越復雜,得好好管著,保證通信可靠、安全,出問題能查到。ZKmall 靠控制流量、防壞人、追蹤鏈路、監控報警,把服務通信管得明明白白,系統更穩定,運維也方便。
流量控制,別讓一個服務累死。有的服務突然來了一堆請求,自己扛不住,還可能把依賴的服務拖垮。ZKmall 就限流,網關那控制總的請求量,每個服務也設個上限,比如訂單服務每秒最多處理 1000 個請求,多了就告訴用戶稍等。不同服務的調用用不同的線程池,商品服務的線程池滿了,不影響支付服務的調用。大促時還能調限流閾值,讓核心服務多處理點請求。有家數碼商城這么一弄,扛住好幾次流量高峰,服務資源用得正好,不閑也不累。
安全防護,別讓壞人鉆空子。服務間通信要保證是自己人調用的、數據沒被改、敏感信息沒泄露。ZKmall 里服務調用都帶令牌,令牌不對就不讓進;傳輸數據用 HTTPS 加密,特別是支付信息;誰能調用哪個接口也有限制,訂單服務的支付狀態接口,只有支付服務能調;接口參數要驗簽名,防止被改。有家做金融電商的這么干,沒出過服務被惡意調用、數據泄露的事,用戶的支付信息妥妥的。
鏈路追蹤,出問題能順著線找到哪錯了。一個請求要經過好幾個服務,出了問題不知道在哪壞的。ZKmall 給每個請求發個唯一的 Trace ID,每個服務都記著這個 ID,日志里也帶上。用個系統把這些 ID 串起來,就能看到請求走了哪些服務,每個服務用了多長時間。比如用戶說下單慢,順著 Trace ID 一看,原來是商品服務查圖片太慢了。有家綜合電商這么一弄,查問題從幾小時縮到幾分鐘,線上故障修得快了 60%。
監控報警,服務不對勁馬上知道。得盯著服務通信的情況,響應快不快、錯得多不多。ZKmall 用監控系統收集數據:調用了多少次、成功多少次、失敗多少次、用了多長時間。設個閾值,訂單服務調用支付服務錯太多、商品服務響應太慢,就報警給運維。儀表盤上能看到服務之間的調用關系、響應時間變化,運維一眼就知道哪不對勁。有家生鮮平臺這么做,服務通信出問題平均 10 分鐘就發現了,處理得快多了。
五、微服務真能幫業務增長
ZKmall 的微服務實踐說明,拆好模塊、管好通信,不光解決了技術問題,還能幫業務長得更快,技術和業務一起進步。
新功能上線快,能抓住商機。微服務能單獨改、單獨上線,新功能不用等整個系統更新。有家美妝電商,新品上線從 1 個月縮到 1 周,搞個營銷活動 3 天就能上,抓住好幾個熱點,新品賣得挺好,占了 40% 的銷售額。
系統穩,用戶體驗好。服務獨立擴容、出問題不擴散,用戶用著順。有家服飾平臺雙 11,靠微服務扛住 5 倍流量,頁面加載快,支付也順利,用戶滿意,口碑越來越好。
運維省勁兒,團隊效率高。服務能單獨部署,自動化運維,不用老加班。有家家居電商,服務部署從幾小時縮到幾分鐘,業務漲了,運維的人沒多,大家能專心搞創新,不天天救火。
能試試新業務,拓展新市場。微服務靈活,想搞個跨境電商、社區團購,復用現有的商品、用戶、支付服務,很快就能搭起來。有家綜合商城,新業務從想法到上線就 1 個月,省了 70% 的錢,新業務一年賣了一個億,成了新的增長點。
微服務得跟著業務走
ZKmall 的微服務實踐告訴我們,搞微服務不是為了炫技,是為了業務。模塊拆分要按業務領域來,通信機制要適合業務場景。離開業務瞎搞微服務,只會更復雜。跟著業務需求走,微服務才能真正幫電商系統長得更大、跑得更穩。