蘑菇街電商交易平臺服務架構及改造優化歷程(含PPT)

蘑菇街電商交易平臺服務架構及改造優化歷程(含PPT)

導讀:高可用架構 7 月 30 日在上海舉辦了『互聯網架構的基石』專題沙龍,進行了閉門私董會研討及對外開放的四個專題的演講,期望能促進業界對互聯網基礎架構的建設及發展,本文是潘福江分享蘑菇街電商交易系統架構。

潘福江,蘑菇街高級研發工程師,2014 年之前在阿里,搞過電商垂直業務平臺建設,也搞過中間件相關的研發工作,2015 年加入蘑菇街(現美麗聯合集團),負責蘑菇街交易資金,購物車等電商基礎平臺的服務化建設工作。

我來自蘑菇街,蘑菇街是一個主要面向女性用戶的電商平臺,男同胞們可能用的比較少。不過蘑菇街里有大量的模特妹子, ?而且顏值都比較高,建議大家可以下來用用,寫代碼累的時候,可以偷偷打開蘑菇街看看妹子,感覺還是很不錯的。

今天我的主題是蘑菇街交易平臺的服務架構,以及在服務化建設過程中,我們做的一些改造歷程分享。

蘑菇街導購時期 業務結構

蘑菇街是做導購起家的,當時所有的業務都是基于用戶和內容這兩大核心展開。那個時候前臺業務主要做的是社交導購,后臺業務主要做的是內容管理。一句話總結就是小而美的狀態,業務相對來也不是很復雜。

當時的技術架構是典型的創業型公司技術架構。網站整體是用 PHP 搭建的,系統做了簡單的分層,基礎設施以現成的開源產品為主。2013 年時蘑菇街做了轉型,主要原因那段時間很大一批導購網站遭到了封殺,于是就轉型做社會化電商平臺。

社會化電商平臺分兩部分,一部分社會化,我們之前做導購時積累了一些經驗。電商是我們之前沒有接觸過的,這塊基本上是從零開始一手建立起來。要做電商平臺,首先就要搭建一個交易平臺。起初比較簡單,我們重寫了一套系統,系統結構和之前相比并沒有本質上的變化,所有業務都寫在一個巨大的工程里面, 中間通過一套代理層和我們的基礎設施進行交互。

電商轉型面臨的問題

業務高速發展,每年保持 3 倍以上的增長(2015 年用戶過億,PV 超過 10億)

用戶購買鏈路大促峰值是日常的百倍(2015 年初最高只支持 400 單/秒)

業務異常復雜,業務形態快速膨脹

歷史包袱沉重,系統耦合非常嚴

蘑菇街轉型到電商平臺以后,業務基本上每年以三倍以上的速度增長,這個時候問題開始暴露了。電商平臺在發展過程中尤其在發展中期遇到的一些的問題,不僅僅是蘑菇街的,其它平臺可能也會遇到。如系統代碼臃腫、模塊耦合程度高,依賴復雜,業務擴展能力差等。

蘑菇街那個時候主要面臨了幾個問題:

一個是我們業務在高速增長,系統容量跟不上,當時交易系統只能支持到每秒四百單的容量(大促的時候流量是平時的百倍以上)。

另一個是電商業務形態變的特別快,業務支撐不夠靈活,不夠快

此外還有歷史包袱,系統耦合非常嚴重

解決這一系列問題的關鍵就一個字:“拆”。

系統拆分歷程

DB 垂直拆分

業務系統垂直拆分(購物車,下單,資金…)

數據 & 業務模型統一,服務接口設計邏輯清晰,粒度合適

基礎業務邏輯下沉到服務,Web 層專注表示邏輯和編排

服務治理

系統拆分——交易購物車為例

以交易購物車的例子來說明下我們的改造過程,以前我們就一個工程,所有的代碼都寫在這,不同的終端或業務都有一個不同的模塊代碼在維護。訪問數據也比較隨意,各自維護一套數據訪問的代碼。因此就有兩個非常頭疼的問題:

一方面由于交易就一個庫,所有內容都是放在里面,因此這些隨意散亂的 SQL 可能會冷不丁的給你來個慢查詢,別的業務代碼帶來的不穩定會相互影響,還很難定位這種“野 SQL”是哪里查過來的,導致我們的 DB 很不穩定,對后續改造非常不利。

另外一個是業務支撐方面,產品提一個需求過來,在各種端都要實現一遍,復用性很差,業務支撐非常不靈活,系統毫無擴展性,開發同學也是苦不堪言,經常加班加點搞,還經常搞出一堆 bug。

于是我們就去拆系統,到底怎么拆?其實也是有些講究的。

系統拆分的優先順序

如果把 DB 比如成一個木桶,各類業務就可以比喻為往里面倒的水,一開始往木桶里面倒的水可能并不多,木桶裝的下沒問題。但是隨著業務增長,木桶總有一天是會裝不下的。

首先木桶需要足夠大,并且能很方便擴容,這樣才不會有后顧之憂。業務量有時候并不好預測,指不定什么時候量就起來了,如果不把這個底層的木桶做得足夠強大,而優先去搞業務上的拆分優化,那量一旦起來整個系統就歇菜了。

因此DB 是系統拆分的基礎,需要優先拆分

DB 拆出來的同時還要關注穩定性,前面也提到,當時 SQL 是比較散亂,極易造成 DB 不穩定,所以數據訪問/模型統一也很關鍵,我們建了統一的數據訪問層。有了這一層之后,后面對 DB 的改造擴容都能夠比較有效的掌控。

基礎的東西都建好了,再來解決業務支撐困難這個問題。業務模型上需要統一抽象,能夠支持定制擴展。流程改造過程同時也孵化出了SPI 業務框架、流程引擎、規則引擎等這些基礎業務框架。在業務支撐上做到了靈活可擴展。系統也做了比較合理的分層,每層只需要關心本層所需關注的能力即可。

系統拆分成果

交易系統在整體拆分完成以后,公司 SOA 化雛形也基本已經形成了,包括基礎服務化框架、消息中間件、數據中間件、配置中心也都落地實施了,此外還孵化了一系列基礎設施工具,包括監控系統,調度系統,日志搜集,鏈路跟蹤系統等。

還有一個背景拆分過程中,公司戰略整體往 Java 語言轉,這個是公司綜合層面考慮,Java的人才尤其是杭州相對比較多,技術體系也比較成熟,有大牛在能 hold 住問題,當時確實 PHP 資源比較少。

容量提升

做了系統拆分改造以后,接下來更多的會去關注應用本身的容量、性能以及穩定性方面的事情。我們也在這些方面分別作了一些改造和嘗試。

按業務對 DB 進行垂直拆分

讀寫分離,保證讀可以任意擴展

分庫分表,提升中心服務寫入容量

系統拆分時,已經按業務把 DB 垂直拆分出來了,并且 DB 也做了讀寫分離(基于 MySQL)。

下面重點介紹一下分庫分表上的改造,當時目的主要是為了提升中心服務的寫入容量,因為當時 DB 讀寫分離是單 Master 結構,會有一個寫入瓶頸。

以交易創建為例來說明我們分庫分表的歷程,交易創建應該算是交易里面最為復雜的業務場景之一。創建一筆訂單的時,會同同時寫入其他很多的數據,當時系統容量大約是每秒能夠處理一千單,DB 單點存在寫入瓶頸,并且寫入過多會造成主從延遲嚴重。另外 DB 磁盤空間也已經突破了 80%,不穩定性非常高,有可能隨時會崩掉。

所以我們就決定去做拆分,當時的背景是中間件還沒建立起來,沒有分庫分表相關的組件,于是就決定內部先搞起來。

當時對比了業內比較流行的一些方案,比如阿里的 TDDL,Cobar,谷歌的 Vitess 等,比較下來發現這些組件都比較重,接入和使用成本都相對比較高。我們的原則是符合我們業務場景下,選一種接入和使用成本都相對簡單的組件。于是我們采取的是最后一種方式,通過 MyBatis Plugin 字節碼增強的方式實現分庫分表功能,該組件目前已開源:https://github.com/baihui212/tsharding

分庫分表業界方案對比如下圖:

自研分庫分表組件 TSharding,完成分庫分表

足夠簡單,投入較少資源

支持分庫分表

支持數據源路由

支持事務

支持結果集合并

支持讀寫分離

這個組件叫 TSharding,它的特點是足夠簡單,是符合我們預期的,支持分庫且分表,支持數據源路由,支持事務,支持結果集合并,支持讀寫分離,滿足我們所有的要求。

性能優化

我們在性能優化上也做了一些嘗試,主要舉下面三個場景:

分布式事務處理

單機異步并行

預處理 & 緩存

分布式事務處理----交易創建為例

優化思路:異步消息解耦

交易創建流程中,訂單、券和庫存的狀態必須要保證一致性

營銷優惠券服務和庫存中心庫存服務,與下單服務是分開部署的

調用券/庫存服務超時/失敗,異步發消息通知回滾;復雜性可控

MQ 產生端發送失敗重試 + 消費接受 ACK 機制保證做種一致

消除了二階段提交等分布式事務框架的侵入性影響

首先講分布式事務處理,這里還是以交易創建為例,交易創建過程會跟多個服務進行交互,并且有些服務是強依賴,比如扣減庫存,鎖券服務,必須保持一致性。二階段/多階段協議這種方式很重,當時并沒有采納

我們當時想了一個方法是,通過異步消息解耦的方式來解決,具體流程:

下單時先不要急著讓這個訂單暴露出來,我們先創建一筆不可見的訂單(或者可以認為是先預創建了一筆訂單),然后再去做減庫存,鎖券操作,當這些操作異常或者失敗時,下單系統就會發出一條廢單消息,它的下游系統(如促銷,庫存系統)收到這個廢單消息以后,就會幫我們做回滾的操作,用這樣的方式來解決我們分布式事務的問題。

分布式事務處理——支付回調為例

支付回調流程中,資金系統回調交易后會促發訂單狀態更新,減庫存,發券等操作

資金作為發起方保證重試,消息可達,交易以及下游做好等

失敗業務進任務重試表,做異步補償重試

消除了二階段提交等分布式事務框架的侵入性影響

還有一個場景就是支付回調,支付系統在訂單完成付款之后會通知交易系統,交易系統會進行一些列的操作如定單狀態更新,減庫存,發券等,也是一個分布式事務問題。

我們的策略是,當業務失敗的時候這個請求會進入我們的一個失敗補償表,通過不斷的做異步補償重試(階梯式),保證最終一致性。

單機異步并行——購物車為例

分析思路

購物車是典型 IO 密集型應用

代碼串行執行,同步等待時間較長

CPU利用率低

分析一下,購物車其實本身是一個典型的 IO 密集型的應用,有很多類似的應用都是這樣的,會存在大量的網絡 IO 請求。還有一點是我們習慣上代碼是串行寫的,所以存在很多同步等待時間。

既然每次購物車的查詢都會經過這么多的節點,那如果兩個節點之間沒有依賴關系,我是不是就可以并行的去搞,分析一下其實每一次查詢都會對應一顆查詢依賴樹,同一層節點之間是沒有依賴關系的,在這一層我們其實是可以去做并行操作的,所以基于這個思路我們當時做了優化,并且效果還挺不錯。

具體的優化就是加入這個概念,去查的時候我們先等一下別的查詢,我們一塊兒去查,最終做一個匯總,查詢結果就出來了,就是這么一個流程。然后做的效果也不錯,整個 RT 基本上能夠降到一半以上。

預處理 & 緩存——營銷計價服務為例

使用緩存降低 DB 讀壓力

盡可能地緩存需要的數據

DB 數據有變化主動失效緩存(異步,低延遲),減少不一致問題

大促高峰前開啟本地緩存;做緩存預熱,有助于提高緩存命中率

預處理達到計價接口部分耦合:報名大促活動商品的折扣同步到商品表

預處理跟緩存化,其實也是一種比較通用的優化手段。我們采用了多級緩存的策略,本地緩存+分布式緩存。優先讀取本地緩存,本地緩存沒有就去分布式緩存取。分布式緩存取不到才去 DB 里面取。當數據發生變化的時候我們會有一套異步刷新緩存的系統來及時更新緩存里面的數據。

服務 SLA 保障

SLA: Service Level Agreement,是對服務提供者的要求。SLA 體現在對容器(QPS)、性能(RT)、程度(分布情況;可用性;出錯率)的約束。提高 SLA 的一些手段如下

基礎監控先行,把關鍵指標監控起來

依賴治理、邏輯優化:減少不必要的依賴

負載均衡;服務分組;限流

降級預案、容災、壓測、在線演練

這個是我們內部的一個監控系統,我們會監控每個應用的一些關鍵指標,觀察整個鏈路上的情況。

總結及下一步規劃

總結

服務化構架不是一成不變的,是隨著業務不斷發展而演化

沒有最佳的方案,在合適場景下采用合適的方案

目前在做

服務治理、SLA 保障系統化

下一步

同城/異地雙活

Q&A

提問:如果消費者收到一條消息,這時候我就告訴系統可以把這個消息刪除了,那我后端在執行這條消息的過程當中,比如我做一些入庫操作或者其他的操作,但是這個服務死掉了,那么你們有沒有遇到類似這樣的情況,你們是怎么來處理的?

潘福江:目前沒有,因為其實這是一個需要合作的過程,我們需要下游系統去配合保證,保證業務 OK 之后才去 ACK 消息,主要是幾個系統之間的協作問題。

提問:電商大部分分布式事務解決方案用消息隊列的機制,有沒有一種更通用的解決方式?我們開發一套分布式組件,比如兩階段協議,更高效解決這種分布式事務。

潘福江:分布式事務問題其實還是看場景的,支付寶(以前在支付寶)有類似的框架,但是比較重,也需要一定的接入成本,需要一定的配合。Case by Case 的分析問題會更好一些,比如有些場景他的一致性要求并沒有那么高,沒有必要采用兩階段協議這種來處理,主要還是看業務場景。

提問:數據庫遷移的時候,能做到平滑遷移嗎?因為我看到你之前用的中間件的時候切換過兩次,這個時候肯定遇到一些數據庫在線平滑遷移,你是怎么弄的?

潘福江:這個我們內部會有一套數據同步工具,另外有套開關系統來完成灰度切換,你可以動態去推送一些值,到你的應用里面,然后動態的可以把這個值改掉。此外我們這個數據同步工具是支持回溯的,遇到緊急情況可以迅速切回,并且把數據回溯回來。

提問:你做了一個分庫之后你要把老的庫保留到新的庫里面,因為上去之后你要分步發布,但你的老庫還在跑,這個時候有人在用你的老庫,但是因為你又在發布,一半流量已經切到新的庫上去了,如果這個時候有人正在修改數據怎么辦?

潘福江:上文也提到,老庫和新庫是有建立一個通道的(數據同步通道),并且數據同步工具一直在工作。老庫的數據會實時的同步到新庫,并且我們的灰度是通過開關系統動態推送的,實時生效。

提問:在分庫分表的拆分之后,假如有表的關聯查詢你們怎么處理的?

潘福江:我們貌似沒有關聯查詢,也不推薦,關聯查詢對后續水平拆分十分不利,不利于 DB 的擴展。可以分開查,然后在應用層把關聯的事情做掉。

提問:如果分開去查的話,性能上會不會受影響呢?

潘福江:性能上可能是會受到一定的影響,會多訪問幾次數據庫,但是 DB 擴展性能大大的提升,互聯網玩的是大數據,比起這點,DB 擴展性更重要,應用層可以有很多的方式去優化(比如緩存),如果你用了 JOIN 再去做水平拆分是非常困難的。

提問:你們在拆庫之前,有沒有考慮什么好的方案回退?

潘福江:我們的數據同步工具是支持回溯的,出了問題通過開關系統可以立馬切回,并且能回溯數據,把影響面降到可控范圍。

相關閱讀

(點擊標題可直接閱讀)

Mercury:唯品會全鏈路應用監控系統解決方案詳解

同程旅游緩存系統設計:如何打造Redis時代的完美體系

保證分布式系統數據一致性的6種方案(含蘑菇街方案)

對話:一個工程師在蘑菇街4年的架構感悟

10個互聯網團隊應對高壓的容量評估與高可用體系:私董會1期

本文及本次沙龍相關 PPT 鏈接如下,也可點擊閱讀原文直接下載

http://pan.baidu.com/s/1nvnOEBf

想更多了解高可用架構沙龍內容,請關注「ArchNotes」微信公眾號以閱讀后續文章。關注公眾號并回復城市圈可以更及時了解后續活動信息。轉載請注明來自高可用架構及包含以下二維碼。

高可用架構

改變互聯網的構建方式

長按二維碼 關注「高可用架構」公眾號

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容