來自京東、唯品會對微服務編排、API網關、持續集成的實踐分享(上)

架構師小組交流會:每期選一個時下最熱門的技術話題進行實踐經驗分享。
第三期:微服務。微服務架構以其高度的彈性、靈活性和效率的巨大提升,快速受到各領域架構師和技術決策者的關注。它的基本理念是將一個肥大的系統拆分成若干小的服務組件,組件之間的通訊採用輕量的協議完成。我們本期小組交流會來探討一下,現在互聯網公司的微服務實踐情況。
嘉賓:京東章耿、原唯品會石廷鑫、七牛陳愛珍
本文是對此次交流的整理,分了上下兩篇文章。

第一輪:自由交流
京東章耿:大家好,我是京東基礎架構部平臺中間件的章耿,主要負責京東的服務框架,配置中心等項目。京東11年底進行.NET轉Java的技術變革,當時就提出了接口的SOA化的概念。那時京東業務發展非常快,項目越來越多,服務化是必然的趨勢。京東的服務化框架是一共有兩代。第一代是12年開始,我們使用開源的一個實現,用Dubbo作爲RPC框架,Zookeeper 作爲註冊中心,那時應該算一個主流的技術選型。我們在開源的基礎上做了一些易用性和功能擴展,比如說支持REST、支持kryo/thrift等序列化,服務監控等,這個框架在那時的業務規模和節點數量下面還是比較穩定的。14年初我們開始自研服務框架。爲什麼這麼做呢?一個是之前的服務框架還是有很多可以提升的地方,不管是性能還是服務治理的一些功能,因爲京東的機器數,機房也在不停的建,網絡拓撲的複雜直接需要高級的服務治理功能;還有一個就是接口節點等數量級的增加,當時我們的接口規模慢慢的已經好幾千了,接口的實例也幾十萬;另外就是用開源的有些內部系統打通比較麻煩,所以我們要做升級換代。當時也是考量了用開源的改改,還是全部自己重新做的抉擇。後來覺得一個是有時間,二是覺得自己有能力做一個符合京東自己的定製化的服務框架,所以14年我們就開始自研框架,做了整整一年。15年初我們上線新版的服務框架。

我們新的註冊中心,是無狀態的一些節點,基於數據庫做最終一致性。爲什麼選數據庫,替換以前的Zookeeper?因爲Zookeeper是樹狀結構,從某些維度查詢它要遍歷整棵數,用數據庫的好處就是可以從多維度的查詢分析過濾,不管是機房、 IP,都可以去查詢,分析,過濾比較結果。然後Zookeeper在跨機房的時候有一個問題,它是半數節點存活纔可以用,所以如果跨機房部署的話,最起碼得3個機房,才能保證集羣整體可用。還有Zookeeper它是強一致性的的,比較依賴網絡。如果網絡不好,如果跨機房斷網的時候,它其實是不可用的,讀都不能讀,所以會帶來一定的問題。以前用zookeeper註冊服務端,就是寫一個臨時節點,等服務端死了節點自動消失的。但是你在網絡一抖的時候,或者是服務端和Zookeeper之間有網絡故障的時候,它其實會不小心把它摘掉,因爲Zookeeper認爲它死了,但其實它不一定真的死了,所以這個時候就需要有一些輔助的去判斷它是不是真的死了。第一次遇到的情況是那個臨時節點,後來我們是把它改成永久節點,然後定時的去telnet 它的端口,像Dubbo是直執行ls 命令,我們也是直接執行一個命令,看它有沒有響應,那是第一代的時候。在JSF的框架裏有一個哨兵的組件,我們的Provider會定時的發心跳,對於註冊中心來說,它知道最後的心跳時間,然後定時刷到數據庫裏面,看哨兵的情況,如果沒有哨兵,數據庫裏面保存一個最後心跳時間,這時候你可以用定時任務去找它,這是我們最早的一個版本。後來我們改進了,因爲有時斷網了,這個心跳時間就不準了。所以在每個機房還布了一套獨立的程序,沒心跳的同時再由它來判斷是否可用,如果這個同機房的程序都連不上,我們再把它置成一個不可用的狀態,雙重保證。另外以前Zookeeper的時候服務列表是下發的全量列表,例如1000臺加一臺,下發的是1001臺,而新版註冊中心我們是推變化的部分,只推加1臺,大大節省了數據的推送量。

RPC框架,我們內部叫傑夫,JSF,京東服務框架的簡稱我們是用基於Netty自己研發的。爲了兼容上一代版本,兼容之前的dubbo協議,所以我們也是用的無代碼入侵的;我們在同一個端口支持多協議,包括自定義的JSF協議,http協議,dubbo協議等。目前我們只有C++和Java的客戶端,然後如果是其它語言例如Golang,python,PHP的話,我們都會讓他向我們的一個HTTP的網關發請求,這個網關主要就是轉發。把前面的http請求轉換到後面一個JSF請求,也是基於Netty做的。序列化默認是Message Pack,是個跨語言的協議,也支持hessian,json,Java,Protobuf等。註冊中心和RPC框架直接是長連接,可以進行一個通訊。

唯品會石廷鑫:大家好,我是石廷鑫,原來在京東、唯品會,現在在宅急送。我基本上都是在倉儲物流這方面。以前在亞洲一號是按照倉庫的整個操作細節分成各個模塊來做的服務拆分每個模塊是單獨部署的。倉儲的每個倉,根據種品類不一樣,整個的操作流程是不一樣的。但是核心的東西,庫存、訂單管理,都是一樣的,只是一些組合不一樣。舉個例子,小件商品上下架都要做的,但是對於大件商品,比如說大家電,基本上都不需要放架。打訂單也不需要,完成配送才需要訂單,實際上是到了最後才綁定訂單。所以每個流程不一樣,需要的組合也不一樣。那時我們就想到了,把每個模塊先拆出來,主要是KVM運行整個節點業務部分用這節點來整個串聯起來。核心的東西比如說庫存、訂單、商品資料,基本上都是用這個簡單的模塊。

唯品會的倉儲也是按這種思路來做的。當時唯品會用的是Dropwizard,實際上是我們用了它的一個殼,後面還是用Spring,也做了一個模塊,Spring集成到一塊來Springboot做了出來,基本上就把Dropwizard拋棄掉了因爲Dropwizard版本升級變化比較大。它有一個好處,就是Bundle比較好,服務化拆分的時候可以根據它大小進行可分可合,如果不需要拆分的時候,我們就把Bundle合到一塊,如果需要拆分的話,就把Bundle再拆出來,單獨這個應用是非常容易的。

去年到的宅急送,我們的服務註冊、服務發現、網關都使用的Spring Cloud的這一套。目前來說還是不錯的,基本沒發現大的毛病。唯一的問題是如果前期沒有做好的整個數據抽取,整個報表可能會比較麻煩一些。

七牛陳愛珍:大家好,我是七牛的陳愛珍。微服務架構的設計理念非常適合七牛的業務特點每個服務只負責單一的職責。比如音視頻的處理服務:音視頻轉碼 , 音視頻拼接 , 視頻幀縮略圖,點播流式轉碼,都是以微服務的方式構建,這樣每個服務都擁有獨立的運行環境,並且可以根據自身的業務壓力情況進行獨立擴展,動態的彈性擴展還可以提高資源的利用率。一個可落地的微服務架構應該爲微服務提供獨立的運行環境,調度框架,註冊中心,配置管理中心和監控平臺。 七牛採用的是Mesos+Docker+自研調度系統的架構。Docker做環境封將,Mesos做資源調度,自研的調度系統負責對Docker進行彈性的調度。

我們使用Consul做註冊中心,實現服務的註冊與發現。Consul自帶key/value存儲,可通過DNS接口做服務發現,且具體健康檢查的功能,並支持跨數據中心的服務發現。API Gateway 可以通過 Consul提供的DNS接口查詢到服務所有的可用實例的列表信息,並將請求進行轉發。流量轉發具有負載均衡的功能,採用的是輪詢的方式,服務發現則是基於Consul做的。用戶請求進來後通過Consul查詢到所有可用節點的訪問地址,再通過輪詢的方式將請求發給後端的服務進行處理,對於返回的結果僅作轉發,由請求方解釋和使用。並且在API網關中帶有監控的組件,對請求數,失敗數等進行監控,傳送到Prometheus服務器上。通過監控數據對請求進行流量控制及服務降級等相應的處理。

當需要調用多個微服務時,根據七牛雲的數據處理的業務特點我們使用管道(pipeline)來進行串行的處理。每一個微服務的輸出都是下一個微服務的輸入,直到最後一個微服務執行結束纔是最終數據處理的內容。比如上傳一個視頻資源後,需要做兩個數據處理操作: 轉成mp4資源和進行HLS切片,這種場景下不能對原資源同時執行兩個數據處理的操作,必須按序執行。 
   
第二輪:話題交流
主持人:服務與服務之間的依賴關係怎麼管理?服務編排怎麼做?把這些服務節點串起來。

唯品會石廷鑫:比方說不是業務的,基礎服務,如圖片服務器這些都是獨立的。唯一相關的是下面的業務層和底下的基礎服務有之間調用,還有是業務模塊之間有服務的調用,在系統裏是沒做體現的,但是我們在服務和服務之間,就加了類似於熔斷的那個默認的東西。系統之間的依賴關係,我們自己做了一個簡單的系統進行維護。Spring cloud eureka是都是存在內存裏,我們改良過,我都改到一個數據庫我們交互全部都是Rest ,我們後邊還寫過一套,Google protobuf。我們倉儲的內部的業務模塊之間是用Google protobuf來做的。我們自個做了一套虛擬化的在裏邊

唯品會石鑫:我現用的是Apache camel做編排,可以用DSL描述把服務串起來。其實更多的是業務的流程怎麼組織,怎麼去把基礎服務讓串起來,形成一個真正大的業務場景。

京東章耿:目前京東大部分一個接口一個方法就已經是操作多張表了,一般認爲是一個比較性的操作了,如果再在外面有一個東西把它包一下,例如把3個方法包成一個方法,其實意義不大,所以我們現在是沒有做這方面的工作。另外京東有彈性雲,用的Docker,不過不是你們想象中那種微服的那個Docker用法,京東現在用叫“胖容器”,更像一個虛擬機一樣的一個東西。Docker裏面運行的是一個應用,然後這個應用,它可能包含多個接口多個方法。可能大家理解微服務的Docker用法應該是一個容器裏面,他只跑一個獨立的邏輯,對數據的一個操作,或者對一個資源的操作。比如說下訂單、庫存,這兩步操作,他可能跑了兩個容器把它編排成一個service的這種,我們好像沒有這種

主持人:服務拆分是怎麼做的?
京東章耿:京東現在的服務其實也是沒拆太細主要還是業務部門自己控制服務粒度京東的業務還是比較複雜的,各個應用之間互相依賴,互相調用,每個操作基本都會涉及到很多資源的變更,像微服務推崇的那種對單一資源的操作,基本上沒有。說實話,這種大型互聯網公司裏面的服務根本就微不起來的,不可能像RESTful一樣,對一個資源的一個put post 操作基本不可能,我們現在都是力度還是由使用我們框架的研發人員自己定的,然後一般他們都是根據這種方法之間的一些關聯性或者原子性,或者是擴展性來進行組合或者拆分所以我們一般叫自己服務化框架,不叫微服務框架。另外他們可能還會考慮一些服務是否可以獨立部署,拆的時候可能會考慮一下這些。

主持人:其實很多大型電商互聯網也拆不開,也不能稱之微服務,是那種服務力度很粗,然後每個服務號有若干個接口,其實耦合性很高的合在一起,相關度很高,數據都在一起

京東章耿:都差不多,都是業務開發自己來折分服務粒度。就像剛纔說的單。肯定是一次要操作好多表業務開發認爲這是幾次表操作其實是一個下單的原子操作那麼他就拆到這麼細了。

唯品會石鑫:我們服務不是說一個部一個,實際上它是和數據相關的,都擱到一塊。

唯品會石鑫:按功能分的,功能跟功能之間調用,如果不是同一個數據域裏邊的,還是用RPC來調用的。

京東章耿:那個聽起來很美好,你想我們現在這樣拆,都已經上萬了接口,方法基本都上十萬了。你這樣拆的話,起碼乘以10的接口,而且這樣搞的話就得整個公司都要動用非常非常大的能力去搞好這個事情。

主持人:單體他如果拆成市場上去提倡的那種微服務,其實他對內部的消耗是非常大的,因爲我們很多的服務內部的調用,其實是非常頻繁,如果都把它拆開了去獨立部署的話,它其實對網絡的消耗是要求非常高的。

唯品會石鑫:就是最難的點,一開始你是拆不開這個數據。

主持人:數據只要能拆開,你什麼都好乾。你只要能把數據粒度拆的很細的話,那就沒問題了,那也能做的很細,就是拆不開。其實好多數據都是陳年老表,都是很都是從原來系統繼承下來的,就很難拆。

唯品會石鑫:所以做一個系統還可以。要做這個老系統計劃很難的,拆個表就要拆很多天。

京東章耿:而且是數據量比較少,然後邏輯比較簡單的,例如那種創業型公司,使用開源的方案,這種可以很方便。

主持人:雙11各個電商肯定會有大型的促銷,這時服務的壓力肯定有很大的增長,怎麼解決服務的伸縮的問題

唯品會石鑫:就像我們這邊的話,就看哪個基點的壓力比較大一些,然後你多布幾個基點就可以了。現在基本上都是中泰的那個,就是Spring cloud那套。擴展都是提前先做一步。自動擴的話,就是相當於我們租了一個類似於簡單的監控。就是根據他的實例,然後因爲微服務,我們現在是Spring cloud ,基本上都是java -jar,然後自己就得了,反正那個jar,你可以放到一個公用的地,遠程java -jar要幹架就起來了,監控的時候根據他的量,然後隨時可以就行了。

京東章耿:京東的服務發佈都是掛在應用下面的,而應用發佈的平臺其實會和各個系統打通,比如說數據庫授權的系統,然後自動掛VIP的一些系統,掛控平臺,日誌系統等。然後我們還有個監控平臺,監控一些指標,例如機器情況,應用情況,還有自己業務埋點的性能等數據。至於服務是否有壓力,都自己評估,自己提前擴展。 一般大促前會進行大規模的壓測,他們自己壓測,然後根據結果自己擴就可以了。京東是沒有自動彈性擴展的,基本都大促前提前申請容器,然後提前擴

唯品會鑫:併發量大的業務都是放在公有云,雙十一比平常多了兩倍的機器,我們只買 了一個月的雲主機。臨時用幾天,結束就不用了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章