ESB架構,從支撐幾千到百萬訂單的優化過程
背景說明
2016年左右是SAAS快速發展的階段,公司轉型SAAS業務,變成了風口的豬,業務快速發展,同時也避免不了互聯網公司的發展初期的痛點,技術嚴重拖了業務發展的后腿,幾千的訂單數已經讓系統不堪重負,三天一個小故障,五天一個大故障,系統基本處于不可用的狀態。沒有監控系統,基本都是客戶發現問題電話打過來了,才知道系統出問題了。
公司的技術棧是JAVA,基于一個國外比較流行,國內比較冷門的開源ESB框架"Mule"來開發,當時公司決定做技術轉型,將ESB往微服務轉,同時選擇GRPC作為微服務的開發框架。
當時面臨的問題是該領域的SAAS服務業務邏輯非常復雜,整個老的代碼已經沉淀了一段時間,往新的框架遷移的時間周期比較長,所以老的代碼還需要繼續支撐一段很長的時間,但是業務量又高速發展,所以需要針對老的代碼做性能優化,能夠支撐到新的框架能夠上線
架構介紹
What is Mule ESB?
Mule, the runtime engine of Anypoint Platform, is a lightweight Java-based enterprise service bus (ESB) and integration platform that allows developers to connect Applications together quickly and easily, enabling them to exchange data. It enables easy integration of existing systems, regardless of the different technologies that the applications use, including JMS, Web Services, JDBC, HTTP, and more. The ESB can be deployed anywhere, can integrate and orchestrate events in real time or in batch, and has universal connectivity.
what-mule-esb.png
框架數據流轉
數據流轉.png
- xxx-api是api層的服務;xxx-service是service層的服務,ActiveMQ數據總線
- routeQ:服務注冊topic(service層服務注冊具體的能力-方法),此處實現了一個服務注冊發現的能力
- API接收到請求:1、api從routeQ中獲取請求具體實現的service層對應的隊列名(xxx-service-{host1});2-api將消息(json格式)發送到對應的隊列中;3-service層服務監聽到隊列的消息,進行業務處理;4、service層服務獲取監聽的消息中的target地址(xxx-api-{host}),將結果消息寫會target地址;5、api服務監聽到resp消息然后將結果返回給請求終端
- api的處理是一個同步過程
服務部署架構圖
服務的部署主要是按照粗粒度的系統功能做了集群的劃分:定時任務主要是
mule.png
- 對外服務
主要是面向對外的服務,流量較大,SLA要求比較高,出問題概率也比較高,系統故障的容忍度低
- 內部管理服務內部運營和管理人員使用的,服務的SLA要求不高,系統故障容忍度高,允許一定時間的服務異常
- 定時任務任務類的介于對外和對內的服務之間的SLA要求,由于也是服務于在線業務類的服務,部分服務實時性要求比較高,類似于準實時,比如延時的要求是秒級別的,所以這類的服務也需要有一定的可用性控制,系統故障榮任務略低
優化過程
監控報警
最開始沒有監控報警,服務掛掉全是靠客戶的電話才能知道,那么首先就是構建監控報警系統,基于小米開源的Open-Falcon構建了最早的監控報警系統,然后開始分析整個Mule開發框架的問題,通過分析部署圖和Mule的框架可以得出,出問題最直接的表象,隊列阻塞和隊列的consumer數量異常,那么就是基于這個來實現一個報警。
Mule基于ActiveMQ來作為自己的數據總線,ActiveMQ是一個典型的AMQ,類似于RabbitMQ、RocketMQ,都有自己的admin管理頁面或者api接口,那么就是基于admin-api來操作,由于ActiveMQ產品比較老,很多的協議還是基于XML,那么就是通過接口獲取隊列的stat信息,然后分析隊列的消息數量和consumer數量來觸發報警,Open-Falcon的開放性非常強,只需要寫一個plugin就可以實現自己需要定制化報警
ActiveMQ.png
其中queues/queue/stats/size隊列為消費的堆積消息數;queues/queue/stats/consumerCount是消費者的數量。消費者消息規定的數報警、消息對接數量過多報警;
故障分析
通過流量分析和故障檢測,發現兩個點是主要的瓶頸點
- 業務消息:由于業務需要,終端跟云端通過消息進行業務通信(有些業務場景需要云端主動給消息到終端),但是消息的通信采用了輪訓拉取的方式,通過分析有85%的流量都來自于消息的輪訓,但是由于業務量還不夠大,這85%的消息輪訓里邊又80%以上的都是無效的空查詢,絕大部分都是沒有消息,這個時候就是空輪訓,但是整個業務請求還需要過一遍ActiveMQ。同時消息的查詢后端service直接查詢MySQL,這樣對于MySQL的壓力也非常大
- 業務賬單數據的處理:此業務出故障的次數也比較多,我來公司第一次碰到故障就是賬單的隊列堵了,這個的原因主要是賬單的數據會引發一連串的數據計算,邏輯非常復雜,同步計算,嚴重依賴MySQL,consumer消費能力非常容易遇到瓶頸
- ActiveMQ集群:集群使用的是5.13.0,比較老的一個版本,對于cluster的支持不太友好,只能支持雙主模式,雙主模式經常出故障
處理措施
- 消息的輪訓拉取的方式改造成推的模式,通過websocket實現長連接推送消息
- 賬單數據的處理其實類似于一個離線業務,不算是在線業務,實時性要求不是很高,將賬單處理的部分從在線的集群剝離,獨立一個賬單處理的集群,同時賬單的堵塞經常是因為計算復雜,數據庫瓶頸遇到隊列堵塞,所以做了讀寫分離,對于賬單報表的讀取和計算在同一個Mule集群里邊做了隊列的讀寫分離,避免互相的影響
- 同時將服務再次做了細粒度的劃分:在線/離線、讀/寫的服務的劃分,將集群重新的規劃,盡量保證實時在線業務的高可用
- 在線業務集群同時部署兩個集群,做數據隔離,但是同時承載業務流量,做到服務級別的HA
- 接入層通過Nginx和openresty做了一些熔斷和降級的處理,最大限度保證服務的可用性
- 通過分析可以發現基本服務的瓶頸都會出現在MySQL數據層,那么針對這個瓶頸也做了調整,讀寫分離和分庫,讀寫分離比較好理解,分庫的邏輯主要是針對SAAS的特點,SAAS系統主要是以客戶為核心,每個客戶都有自己的客戶標識,那么可以天然的通過客戶的標識來進行分庫的操作
- ActiveMQ遇到過幾次問題,首先是內存過高觸發流控(AMQ都有類似的自我保護能力)、OOM這種主要是調整JVM的內存設置以及流控的配置
- ActiveMQ的集群問題,雙主的模式經常會出現consumer都落到一個節點,導致另外一個節點產生的消息無法消費堵塞,高版本的ActiveMQ支持多節點的集群模式也解決了類似的BUG,由于所有的RD都集中在GRPC微服務改造,不準備提升版本支持高版本的開發,所以只能通過別的方案繞開,ActiveMQ不采用集群,只是用單點+haproxy來實現HA。
總結
- 通過上邊的優化改造錯誤,Mule運行了一年多的時間,支撐了訂單到百萬的業務量,同時故障率非常的低,保證了SLA
- 一個完整的大型系統,在整個的生命周期內,開發交付以后,運維、優化、保證可用性階段的重要性也非常的大,需要不停的去學習改造
- 監控報警系統需要首先部署好,避免系統的裸奔,只要好的監控報警才能夠幫助我們更快速的定位問題、發現問題、優化和改造系統
- 服務的等級劃分非常重要,需要最大粒度的去劃分,然后根據等級做不同的處理
- 服務的治理、讀寫分離在系統的很多方面都能用到,需要根據實際情況更好的應用到特定的地方
題外話
MuleSoft公司成立于2006年,最初是實現一個ESB的開發框架并開源,框架的名字命名為"Mule",由于單純通過框架和服務支持很難盈利;
2009年在新CEO加入以后,開始轉型,并構建一個名為"Anypoint"的云平臺,平臺打通了數千個SAAS服務平臺,并將服務通過API接口的方式暴露給用戶,用戶可以在Anypoint上邊按照自己的業務場景和依賴的三方SAAS平臺,組裝自己的自定義業務,可以說Anypoint是對于ESB的上層抽象,將SAP、NetSuite、Salesforce等三方SAAS服務當做企業的應用,Anypoint就是連接SAAS服務的數據總線,同時用戶可以基于Anypoint的編排能力用最低的代價實現自己的業務,大量的減少了IT的投入成本。用當前比較流行的概念來說,Anypoint就是一個通用的業務中臺,也是一個有業務編排能力的低代碼平臺。
也正是得益于MuleSoft的轉型和在云服務的優秀表現,2018年被Salesforce用65億美元的價格收購,徹底逆襲。
從MuleSoft的成功我們也能看到,對于計算機和軟件體系,任何概念和理論都是互通的,都是可以借鑒并發展的,同時需要有一個明確的可以落地的方向,沿著方向持續的走下去。