天天看點

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

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

導讀:

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

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

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

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

在上線之初的時候,這種架構還是比較有優勢的,因為當時考拉的開發人員也不是很多,把所有的功能都耦合在一個程序裡面,利于集中開發、測試和上線,是一種比較高效和節省成本的方式。

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

再例如上線成本高:幾乎所有的釋出需求都會涉及到這些應用的上線,同時不斷增長的業務需求,也會使得我們的代碼越來越臃腫,造成維護困難、可用性差,功能之間互相耦合,都耦合在一個程序裡面,導緻一旦某一個業務需求涉及的代碼或者資源出現問題,那麼就會影響其他的業務。比如說我們曾經在online工程裡面,因為優惠券兌換熱點的問題,影響了核心的下單服務。

這個架構在考拉運作的4到5個月的時間裡,從開發到測試再到上線,大家都特别痛苦。是以我們就開始進行了服務化拆分的工作。

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

這個是考拉現在的分布式服務架構。伴随着服務化的拆分,我們的組織架構也進行了很多調整,出現了商品中心、使用者中心和訂單中心等等。拆分其實是由業務驅動的,通過業務來進行一些橫向拆分或者縱向拆分,同時,拆分也會面對一個拆分粒度的問題,比如怎麼才算一個服務,或者說服務拆的過細,是不是會導緻我們管理成本過高,又或者說是否會帶來架構上的新問題。

考拉的拆分由粗到細是一個逐漸演進的過程。随着服務化的拆分,使得服務架構越來越複雜,随之而來産生了各種各樣的公共技術,比如說服務治理、平台配置中心、分布式事務和分布式定時任務等等。

考拉的服務化實踐

微服務架構在服務化中起到了很重要的作用,是服務化改造的基石,經過嚴格的技術選型流程後,我們選用了Dubbo來作為考拉服務改造的一個重要支柱。Dubbo可以解決服務化過程中服務的定義、服務的注冊與發現、服務的調用和路由等問題,此外,Dubbo也具有一些服務治理的功能和服務監控的功能。下面我将介紹考拉基于Dubbo做的一些服務化實踐。

首先來說一下 熔斷。

在進行服務化拆分之後,應用中原有的本地調用就會變成遠端調用,這樣就引入了更多的複雜性。比如說服務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,使用獨立程序的方式來運作。對于業務工程的一個解耦,幫助我們實作一個異構系統,對多語言支援,也可以解決中間件更新推動困難以及各種依賴的沖突,業務方也可以更好的關注于業務開發,這也會是未來探索的一個方向。

以上就是我們團隊在服務化程序中的一些實踐和思考,謝謝大家。

繼續閱讀