網易考拉在服務化改造方面的實踐

導讀:前端

網易考拉(如下簡稱考拉)是網易旗下以跨境業務爲主的綜合型電商,自2015年1月9日上線公測後,業務保持了高速增加,這背後離不開其技術團隊的支撐。微服務化是電商IT架構演化的必然趨勢,網易考拉的服務架構演進也經歷了從單體應用走向微服務化的整個過程,如下整理自網易考拉陶楊在近期Apache Dubbo Meetup上的分享,經過該文,您將瞭解到:算法

  • 考拉架構的演進過程
  • 考拉在服務化改造方面的實踐
  • 考拉在解決註冊中心性能瓶頸方面的實踐
  • 考拉將來的規劃

考拉架構的演進過程

考拉在2015年初上線的時候,線上只有七個工程,商品詳情頁、購物車下單頁等都耦合在中間這個online的工程裏面。數據庫

在上線之初的時候,這種架構仍是比較有優點的,由於當時考拉的開發人員也不是不少,把全部的功能都耦合在一個進程裏面,利於集中開發、測試和上線,是一種比較高效和節省成本的方式。json

可是隨着業務的不斷髮展,包括需求的逐步增多,開發團隊的不斷擴容,這時候,單體架構的一些劣勢就逐漸的暴露出來了,例如開發效率低:功能之間的相互耦合,不一樣需求的不一樣分支也常常會修改同一塊代碼,致使合代碼的過程很是痛苦,並且常常會出問題。後端

再例如上線成本高:幾乎全部的發佈需求都會涉及到這些應用的上線,同時不斷增加的業務需求,也會使得咱們的代碼愈來愈臃腫,形成維護困難、可用性差,功能之間相互耦合,都耦合在一個進程裏面,致使一旦某一個業務需求涉及的代碼或者資源出現問題,那麼就會影響其餘的業務。好比說咱們曾經在online工程裏面,由於優惠券兌換熱點的問題,影響了核心的下單服務。性能優化

這個架構在考拉運行的4到5個月的時間裏,從開發到測試再到上線,你們都特別痛苦。因此咱們就開始進行了服務化拆分的工做。網絡

這個是考拉如今的分佈式服務架構。伴隨着服務化的拆分,咱們的組織架構也進行了不少調整,出現了商品中心、用戶中心和訂單中心等等。拆分實際上是由業務驅動的,經過業務來進行一些橫向拆分或者縱向拆分,同時,拆分也會面對一個拆分粒度的問題,好比怎麼纔算一個服務,或者說服務拆的過細,是否是會致使咱們管理成本太高,又或者說是否會帶來架構上的新問題。架構

考拉的拆分由粗到細是一個逐步演進的過程。隨着服務化的拆分,使得服務架構愈來愈複雜,隨之而來產生了各類各樣的公共技術,好比說服務治理、平臺配置中心、分佈式事務和分佈式定時任務等等。併發

考拉的服務化實踐

微服務框架在服務化中起到了很重要的做用,是服務化改造的基石,通過嚴格的技術選型流程後,咱們選用了Dubbo來做爲考拉服務改造的一個重要支柱。Dubbo能夠解決服務化過程當中服務的定義、服務的註冊與發現、服務的調用和路由等問題,此外,Dubbo也具備一些服務治理的功能和服務監控的功能。下面我將介紹考拉基於Dubbo作的一些服務化實踐。app

首先來講一下 熔斷。

在進行服務化拆分以後,應用中原有的本地調用就會變成遠程調用,這樣就引入了更多的複雜性。好比說服務A依賴於服務B,這個過程當中可能會出現網絡抖動、網絡異常,或者說服務B變得不可用或者很差用時,也會影響到A的服務性能,甚至可能會使得服務A佔滿整個線程池,致使這個應用上其它的服務也受影響,從而引起更嚴重的雪崩效應。

所以,服務之間有這樣一種依賴關係以後,須要意識到服務的依賴實際上是不穩定的。此時,須要經過採起一些服務治理的措施,例如熔斷、降級、限流、隔離和超時等,來保障應用不被外部的異常拖垮。Dubbo提供了降級的特性,好比能夠經過mock參數來配置一些服務的失敗降級或者強制降級,可是Dubbo缺乏自動熔斷的特性,因此咱們在Dubbo上引入了Hystrix。

消費者在進行服務調用的時候會通過熔斷器,當服務提供者出現異常的時候,好比暫時性的不可用,熔斷器就會打開,對消費端進行調用短路,此時,消費端就不會再發起遠程調用,而是直接走向降級邏輯。與此同時,消費端會持續的探測服務的可用性,一旦服務恢復,熔斷器就會關閉,從新恢復調用。在Dubbo的服務治理平臺上,能夠對Hystrix上運行的各類動態參數進行動態的配置,包括是否容許自動熔斷,是否要強制熔斷,熔斷的失敗率和時間窗口等等。

下面再說一下 限流。

當用戶的請求量,調用超過系統可承受的併發時系統QPS會下降、出現不可用甚至存在宕機的風險。這就須要一個機制來保護咱們的系統,當預期併發超過系統可承受的範圍時,進行快速失敗、直接返回,以保護系統。

Dubbo提供了一些基礎的限流特性,例如能夠經過信號量的配置來限制咱們消費者的調用併發,或者限制提供者的執行併發。可是這些是遠遠不夠的,考拉自研了限流框架NFC,並基於Dubbo filter 的形式,實現了對Dubbo的支持,同時也支持對URL等其餘資源的限流。經過配置中心動態獲取流控規則,對於資源的請求,好比Dubbo調用會通過流控客戶端,進行處理並判斷是否觸發限流,一旦請求超出定義的閾值,就會快速失敗。

同時,這些限流的結果會上報到監控平臺。上圖中的頁面就是考拉流控平臺的一個監控頁面,咱們在頁面上能夠對每個資源(URL、Dubbo接口)進行一個閾值的配置,並對限流進行準實時監控,包括流控比率、限流次數和當前的QPS等。限流框架除了實現基本的併發限流以外,也基於令牌桶和漏桶算法實現了QPS限流,並基於Redis實現了集羣級別的限流。這些措施保障系統在高流量的狀況下不會被打垮。

考拉在監控服務方面的改造

在服務化的過程當中,系統變得愈來愈複雜,服務數量變得愈來愈多,此時須要引入更多維度的監控功能,幫助快速的去定位並解決系統中的各種問題。監控主要分爲這四個方面,日誌、Metrics、Trace和HealthCheck。

在應用程序、操做系統運行的時候,都會產生各類各樣的日誌,經過日誌平臺對這些日誌進行採集、分析和展現,並支持查詢和操做。Metrics反映的是系統運行的基本狀態,包括瞬時值或者聚合值,例如系統的CPU使用率、磁盤使用率,以及服務調用過程當中的平均延時等。Trace是對服務調用鏈的一個監控,例如調用過程當中的耗時分析、瓶頸分析、依賴分析和異常分析等。Healthcheck能夠探測應用是否準備就緒,是否健康,或者是否還存活。

接下來,圍繞Dubbo來介紹一下考拉在監控方面的改造實踐。

第一個是服務監控。

Dubbo提供了服務監控功能,支持按期上報服務監控數據,經過代碼加強的方式,採集Dubbo調用數據,存儲到時序數據庫裏面,將Dubbo的調用監控功能接入到考拉本身的監控平臺。

上圖中的頁面是對Dubbo提供者的服務監控,包括對服務接口、源集羣等不一樣維度的監控,除了全局的調用監控,還包括不一樣維度的監控,例如監控項裏的調用次數。有時候咱們更關心慢請求的狀況,因此會將響應時間分爲多個範圍,好比說從0到10毫秒,或是從10到50毫秒等,這樣就能夠看到在各個範圍內請求的數量,從而更好地瞭解服務質量。

同時,也能夠經過各類報警規則,對報警進行定義,當服務調用出現異常時,經過郵件、短信和電話的形式通知相關人員。監控平臺也會對異常堆棧進行採集,例如說此次服務調用的異常的緣由,是超時仍是線程滿了的,能夠在監控平臺上直接看到。同時生成一些監控報表,幫助咱們更好地瞭解服務的性能,推動開發去改進。

第二個是Trace。

咱們參考了Dapper,自研了Trace平臺,並經過代碼加強的方式,實現了對Dubbo調用鏈路的採集。相關調用鏈參數如TarceID,SpanID 等是經過Dubbo的隱式傳參來傳遞的。Trace能夠了解在服務調用鏈路中的一個耗時分析和瓶頸分析等。Trace平臺上能夠展現一次服務調用,經歷了哪些節點,最耗時的那個節點是在哪裏,從而能夠有針對性的去進行性能優化。Trace還能夠進行依賴分析,這些依賴是否合理,可否經過一些業務手段或者其它手段去減小一些不合理的依賴。

Trace對異常鏈路進行監控報警,及時的探測到系統異常並幫助咱們快速的定位問題,同時和日誌平臺作了打通,經過TraceId能夠很快的獲取到關聯的異常日誌。

第三個是健康檢查。

健康檢查也是監控中很重要的一個方面,以更優雅的方式上線應用實例。咱們和自動部署平臺結合,實現應用的健康檢查。服務啓動的時候能夠經過Readiness接口判斷應用依賴的各類資源,包括數據庫、消息隊列等等是否已經準備就緒。只有健康檢查成功的時候纔會觸發出注冊操做。同時Agent也會在程序運行的過程當中定時的檢查服務的運行狀態。

同時,也經過這些接口實現更優雅的停機,僅依賴shutdownhook,在某些狀況下不必定靠譜,好比會有shutdownhook執行前後順序的問題。應用發佈的時候,首先調用offline接口,將註冊服務所有從註冊中心反註冊,這時再也不有新的流量進來,等到一段時間後,再執行停機發布操做,能夠實現更加優雅的停機。

考拉在服務測試方面的改造

下面來介紹一下考拉在服務測試方面的實踐。服務測試分爲接口測試、單鏈路壓測、全鏈路壓測和異常測試四個維度。

接口測試

經過接口測試,能夠來驗證對外提供的Dubbo服務是否正確,所以咱們也有接口測試平臺,幫助QA更好的進行接口測試,包括對接口的編輯(入參、出參),用例的編輯和測試場景的執行等,

單鏈路壓測

單鏈路的壓測,主要面對單個功能的壓測,好比要上線一個重要功能或者比較重要的接口以前,必須經過性能測試的指標才能夠上線。

全鏈路壓測

考拉做爲電商平臺,在大促前都會作全鏈路壓測,用以探測系統的性能瓶頸,和對系統容量的預估。例如,探測系統的各種服務的容量是否夠,須要擴容多少,以及限流的閾值要定多少合適,均可以經過全鏈路壓測來給出一些合理的值。

異常測試

對服務調用鏈路中的一些節點進行系統異常和服務異常的注入,也能夠獲取他們的強度依賴關係。好比一個很是重要的接口,能夠從Trace獲取的調用鏈路,而後對調用鏈的依賴的各個服務節點進行異常注入。經過接口的表現,系統就會判斷這個接口的強度依賴關係,以改善這些不合理的強依賴關係。

考拉在API網關方面的改造

隨着考拉服務化的發展,咱們自研了API網關,API網關能夠做爲外部流量的統一接口,提供了包括路由轉發、流控和日誌監控等一些公共的功能。

考拉的API網關是經過泛化調用的方式來調用後臺Dubbo的服務的。Dubbo原生的泛化調用的性能比普通Api調用要差一些,因此咱們也對泛化調用性能作了一些優化,也就是去掉了泛化調用在返回結果時的一次對象轉換。最終壓測的結果泛化的性能甚至比正常的調用性能還要好些。

考拉在多語言方面的改造

考拉在業務發展的過程當中產生了很多多語言的需求,例如,咱們的前端團隊但願能夠用Node應用調用Dubbo服務。對比了易用性,選用了開源的jsonrpc 方案,而後在後端的Dubbo服務上暴露了雙協議,包括Dubbo協議和json rpc協議。

但在實施的過程當中,也遇到了一些小問題,好比說,對於Dubbo消費者來講,無論是什麼樣的協議提供者,都是invoker。經過一個負載均衡策略,選取一個invoker進行調用,這個時候就會致使原來的Java客戶端選用一個jsonrpc協議的提供者。這樣若是他們的API版本不一致,就有可能致使序列化異常,出現調用失敗的狀況。因此,咱們對Dubbo的一些調用邏輯作了改造,例如在Java客戶端的消費者進行調用的時候,除非顯示的配置,不然默認只用Dubbo協議去調用。另外,考拉也爲社區的jsonrpc擴展了隱式傳參的功能,由於能夠用Dubbo隱式傳參的功能來傳遞一些全鏈路參數。

考拉在解決註冊中心性能瓶頸方面的實踐

註冊中心瓶頸多是大部分電商企業都會遇到的問題,考拉也不例外。咱們如今線上的Dubbo服務實例大概有4000多個,可是在ZooKeeper中註冊的節點有一百多萬個,包括服務註冊的URL和消費者訂閱的URL。

Dubbo應用發佈時的驚羣效應、重複通知和消費者拉取帶來的瞬時流量一下就把ZooKeeper集羣的網卡打滿,ZooKeeper還有另一個問題,他的強一致性模型致使CPU的利用率不高。

就算擴容,也解決不了ZooKeeper寫性能的問題,ZooKeeper寫是不可擴展的,而且應用發佈時有大量的請求排隊,從而使得接口性能急劇降低,表現出來的現象就是應用啓動十分緩慢。

所以,在今年年初的時候就咱們決定把ZooKeeper註冊中心給替換掉,對比了現有的一些開源的註冊中心,包括Consul、Eruka、etcd等,以爲他們並不適合Dubbo這種單進程多服務的註冊模型,同時容量可否應對將來考拉的發展,也是一個問號。因而,咱們決定自研註冊中心,目前正在註冊中心的遷移過程中,採用的是雙註冊中心的遷移方案,即服務會同時註冊ZooKeeper註冊中心,還有新的註冊中心,這樣對原有的架構不會產生太大的影響。

考拉新的註冊中心改造方案和如今社區的差很少,好比說也作了一個註冊數據的拆分,往註冊中心註冊的數據只包含IP, Port 等關鍵數據,其它的數據都寫到了Redis裏面,註冊中心實現使用了去中心化的一個架構,包括使用最終一致性來換取咱們接口性能的一個提高。後面若是接入Dubbo,會考慮使用Nacos而不是ZooKeeper做爲註冊中心。

將來規劃

考拉最近也在進行第二機房的建設,經過兩個機房獨立部署相同的一套系統,以實現同城雙活。針對雙機房的場景,Dubbo會作必定的改造,例如同機房優先調用,相似於即將發佈的Dubbo2.7.0中的路由特性。在Dubbo在服務註冊的時候,讀取系統環境變量的環境標或者機房標,再將這些機房標註冊到註冊中心,而後消費端會作一個優先級路由,優先進行同機房的服務調用。

容器化也是咱們在規劃的一個方向。隨着服務化進程的演進,服務數也變得愈來愈多,經過容器化、DevOps能夠提高測試、部署和運維效率。

Service Mesh在今年很是火,經過Service Mesh將服務框架的的能力好比註冊發,路由和負載均衡,服務治理等下沉到Sidecar,使用獨立進程的方式來運行。對於業務工程的一個解耦,幫助咱們實現一個異構系統,對多語言支持,也能夠解決中間件升級推進困難以及各類依賴的衝突,業務方也能夠更好的關注於業務開發,這也會是將來探索的一個方向。

原文連接

相關文章
相關標籤/搜索