京東、宅急送的微服務實踐分享(下)| 架構師小組交流會

七牛雲發表於2017-02-07

架構師小組交流會是由國內知名公司技術專家參與的技術交流會,每期選擇一個時下最熱門的技術話題進行實踐經驗分享。

第一期:來自滬江、滴滴、蘑菇街、扇貝架構師的 Docker 實踐分享

第二期:來自滴滴、微博、唯品會、魅族、點評關於高可用架構的實踐分享

第三期:京東、宅急送的微服務實踐分享(上)

第三期小組交流會邀請到了國內電商領頭羊京東、宅急送技術負責人,在上篇京東、宅急送的微服務實踐分享(上)中他們介紹了各自產品的微服務實踐,本次他們就 API 閘道器的設計、服務的 Docker 化、服務測試、持續整合等具體話題展開了討論。


話題交流

Q:API 閘道器是怎麼設計的?

京東章耿:我們有個 HTTP 的閘道器,但不是一個對外網服務的一個閘道器。對外的話業務自己都有一些閘道器,例如無線有自己的閘道器,網站有自己的閘道器,而另外一個公共的開放的是一個叫京東開放平臺的閘道器。然後我們的閘道器幹嘛用的?主要做的就是一個跨語言支援用的,協議轉發和限流。這個閘道器存在的意義,主要是為了讓有的呼叫端不用傑夫協議,或者不依賴服務端的情況下,來調服務端的服務。最主要就是剛才說那個 HTTP 轉成內部協議的一個轉發的功能,其次我們在上面做了一個介面級隔離,不要一個介面就把閘道器搞掛。還有一個就是限流,每分鐘調多少次。還有授權,以前的閘道器轉發的做法,一般是比如說類似於一個 VIP,然後前面掛個域名。然後那個虛 IP 後面掛的服務列表一般都是要手動維護上。而我們的網購自動就掛到這個閘道器上面,就是一個服務發現,還有就是我們的結果,統計方面,我們會統一包裝一下,我們的閘道器主要是做這個功能,現在一天應該是幾十億的呼叫量,九十臺,差不多這些。 服務發現是到資料庫裡面去讀服務列表,從註冊中心讀出來以後會推給我們的閘道器。閘道器跟呼叫者是類似的。它其實也是一個呼叫者,只不過它是一個代理的呼叫者。它的服務列表,也是從我們的註冊中心訂閱的,不直接連資料庫,可以認為自己是呼叫者。閘道器第一次去註冊中心去讀,後面的話我們可以推變化的部分。比如說你原來 1000 臺,你要是加了一臺,按以前拉的思路你會拉 1001 臺,然後你自己比較一下,多了哪一臺。但我們現在不是,我們現在是反向給他推加一臺。這樣的話,大量的減少那個,還有網路 IO 的推送。京東章耿:我們想用 nginx+luaw 做一個 HTTP 轉我們內部 JSF 協議的,但不是 worker 就是一個程式。會產生很多長連結,所以我們後來就放棄了,我們現在是基於 nitty 做了一個轉發,就是對外是 HTTP,對內就 JSF 協議。也做了一些授權,限流,還有服務之間的執行緒隔離,服務發現,還有一個是結果的包裝,包裝成標準的 HTTP 的響應。因為像對外網的那些其實都是有自己的系統,不管你是無線,還是 PC 他都有自己的系統,那個不需要我們做。對第三方的話,它也有其中京東一個開發平臺,還有更嚴格的那個驗證,我們這個主要還是做協議轉換的 API 閘道器。

Q:你們怎麼驗證請求的合法性的,你們採用什麼方法?就是就那種效率與安全性的這種平衡你們怎麼做的?

京東章耿:我們是有個授權,就是有個應用 ID,京東是每個啟動的都有個應用 ID,帶著那個應用 ID 過來,我們也可以支援頭上帶 token。京東開放的那種是對外比較嚴格,我們這個不需要那麼嚴格,反正就看你物件,就看你的閘道器給誰用了。

Q:你們現在有兩種型別,一種是內部之間呼叫的,另外一部分是外部呼叫內部的呼叫你們系統。 京東章耿:那個是開放服務,有些供應商內部的系統,想要調京東的系統,那種就是京東開放服務,是需要 Oauth 認證。

**京東章耿:**HTTP+keepalive 也挺快的,因為它無非就是頭上大一點,HTTP 的頭大了一點。但如果後臺是調 redis 那就比較明顯的感覺,那如果後臺是一個有個幾百毫秒的,那你感覺不到那麼明顯。如果後臺,你這就是讀不取一下,讀一下 redis,你感覺比較明顯。我們這邊是用 netty 做的 HTTP 跟二進位制都是在同一個埠支援的。

Q:你怎麼劃分,哪些用二進位制的,那些用 restful 協議的呢?

京東章耿:那個我們沒有強制要求,業務它自己想用什麼用什麼。 京東章耿:對我們來說,它一啟動端線口它就支援這兩種協議。啟動同一個埠,兩種協議都支撐的。

Q:你們是怎麼區分一種埠種協議的呢?

京東章耿:每個資料包括頭上前兩位不是模數位嗎?它們都有自己的模數位。然後我們自己協議有自己的模數位,你 HTTP 就是那幾個打頭的 H,然後我們的 decode 是自動裝載的,它不是說你可以一開始裝載一個什麼那是介面卡 decode。當你請求來的時候,你再自動裝載量,因為我們是超連結,不管你是 HTTP,我們一般都預設開啟 keepalive 也是個超連結。其實,你可以知道這個長連結對應的是什麼協議。

Q:它一般保持穩定的一個超連結,肯定是一種協議持續下去,不可能說動態的變質。

京東章耿:是,看效率要求,其實 HTTP keepalive 也還可以,效能也還可以,如果不是那種調量特別特別大的話,它效率也還是可以的。然後 debug 的時候可能可讀性會好一點。二進位制最大問題還是比較麻煩,特別是,我們現在用 message pack,然後會生成一堆的代理類,模板類,反正問題也比較麻煩。

宅急送石廷鑫:我們都用 Spring cloud 的那一套,然後自個改了一部分東西。像 Consul 好像也和 Zookeeper 一樣的問題,所以說後邊都改造資料庫了。我現在用的是開源的 eureka,只是後邊從屬變了。目前來說還沒發現問題,因為我沒有跨機房的問題。如果是跨機房的話,基本上都是資料庫同步,兩個資料之間同步的問題。

京東章耿:一般我們是有一個功能服務降級,其實最主要還是業務部門自己的程式碼實現,那我們其實有提供一個 mok 功能,就是那在我們配置這邊直接配上一個,如果這個介面不可用返回的什麼東西有沒有開關,這也是可以。但是這個用起來比較少,一般他們自己在業務程式碼上也是容錯的,就是沒有說從平臺這種角度去搞,一般都是自己考慮。然後如果是有一個目視跟蹤系統的話,就一般的也可以跟蹤整個呼叫鏈,就會看出來這個。比如說這個介面它依賴其他的介面,然後京東其實是沒有投資這麼細,因為目前我們分公司跟蹤還沒有上,我們現在主要是依賴我們內部的一個應用管理系統,我們叫 JOne,有點像自動部署。我們每個程式啟動的時候都會帶上這個應用 ID,在我們管理端是能看到這個介面是屬於哪個應用的,我們只能看到應用級別的,這個應用調了哪些介面?哪些介面依賴?調的那些介面還被誰呼叫了?到這個級別。

宅急送石廷鑫:我們用 Springcloud,熔斷機制的降級處理的話,它有一個統計的介面,基本上按那個規則來做。呼叫關係的話,一個是我們做了一個 trace ID,就是 google zipkin,它本身有自帶的工具。還有一部分就是服務的排層,我們現在就是用 camel 來做的,把這個業務整個來排層次做,大體是這樣。目前來說,大的情況就是監控時會有一些出經常會出現一些抖動。就比方說 trace ID 那部分,不能用它自帶的 stream 的模式。我們現在還是用 elk 來做,然後把 trace ID 打出來,然後做了一套簡單的監控,類似於模仿它整個 trace 的路徑。當然不要用 google 自帶的監控,我們發現機器多了自帶的監控不太可靠。我們都是做到日誌裡面,然後用 elk 收集起來。說起來自個做一個監控的呼叫量,這個就是稍微有點延遲。

京東章耿:我們這邊最近正在做,然後我們的思路是這樣的。有個包放在應用裡面,它會輸出日誌,然後我們有一個日誌收集,原來就有日誌收集的我們只是擴充套件了一下。在每臺機子上把它收到一個 kafka 裡面,然後後面是用一個 storm 去把它讀出來,寫到 H base 裡做分析,然後我們是有個取樣率的一個概念,比如說一千次,才寫一次,或者是一萬次才寫一次,做個取樣率。然後最終我們現在是分兩部分,剛才說寫 H base 是一個離線資料,其實我們還有一些簡單例子,就是直接做一些統計,實時的,大概延遲在一分鐘左右。

Q:關於服務的 Docker 化有什麼進展?

京東章耿:我們主要還是應用級別的 Docker。現在只是說,可能這種釋出模式會改一下。現在是基於一個 Docker VM,比如說你起來以後,其實整個映象檔案都在那裡。然後你彈的時候其實還是比較慢的。比如我要擴的話,得先建立一個 Docker 的 VM,再把那些東西複製進去,才能有個裝機的過程。就是比較慢一點,可能得分鐘級別才能把它給提起來。但是未來我們希望把它改用映象的那種形式,就你上線完成以後,生成一個映象。每次上線,你只需要布一臺機器,後面全是複製的一個過程。未來會改成這樣,估計今年開發,明年推。現在相當於要布 20 個節點,那相當於是給你 20 個 Docker VM,你上線釋出 20 次,未來是希望給你一個,然後你釋出一次以後,系統自動給你複製 19 個。而且反正後面服務發現什麼這些都是原生的,都是無所謂的。

京東章耿:京東的 Docker 主要解決資源排程的問題。就相當於現在部物理機,你可能自己要需要部署機器 。但 Docker 可以把資源分配均勻一點,用演算法給算出來,在分配時不會分到同一個機架上,不會分到同一個主機上,還有不會分到很繁忙的機器上。這些都會幫你考慮一下。

京東章耿:京東這邊是自己有一套部署系統,雖然他沒有像你說就映象這樣釋出,雖然沒這麼快,但對於我們開發人員上線來說,其實是一樣的,他只需要配一下,然後一點,他 24 臺自動就上去了,就是有一套工具,也很快。只不過,他需要提前建立好,比如說你剛才說 20 個,你要提前建立 20 個 VM。就比映象的話肯定是要慢在這一步,你映象的話,你直接拉下來一起,然後可以排程到哪臺機子上到個 Docker API 一調,他直接就提起來了,那也是我們未來的改變方向。

七牛陳愛珍:我們的資料處理系統系統上執行的都是 CPU 密集型的計算,獲取一個原檔案,進行資料處理演算法的執行,比如對一個視訊進行轉碼,而在轉碼的過程中需要大量的 CPU 資源來進行處理,處理完後就可以獲得預設的檔案樣式。不同的資料處理對資源的需求是不一樣的,比如獲取一個檔案的 hash 值,這個處理邏輯非常簡單,也沒有大量的運算,配置的資源就相對小一些,而視訊轉碼則非常的複雜,配置的資源就會相對多一些。現在在我們的平臺上執行了數千種資料處理應用,每種處理的的請求量不一樣,比如有些圖片處理每秒可以達到數十萬的請求量,而有一些則可能是每秒幾萬的請求量,幾千種資料處理應用的高峰期也不一樣,有些可能在早上,有些可能在晚上,並且每種處理都會存在突發流量的情況,比如一些電商型的客戶,在做大促銷時,就會導致圖片處理的請求量突增,而一些音視訊的客戶在會在一些活動時會突然增長對音視訊的處理。

這個系統的核心問題是如何把硬體資源對每一種應用不同高峰期的請求量和突發流量做合理的資源分配,不合理的資源分配就可能會造成資源的浪費,或導致負載過重的機器會當機,不能及時響應使用者的需求。原有的系統架構的資源是靜態規劃的,也就是把指定的資源給指定的應用使用,而這種資源的分配往往是按照每個應用的業務高峰進行規劃的,為了應對突發的流量並會預設一定的冗餘,那麼這樣就會需要準備很多的資源。後來我們使用容器,因為容器可以封裝環境,動態遷移,底層使用 Mesos 做資源的排程,這就可以對整個環境按需動態分配,很好的解決了資源利用率的問題。

Q:關於服務測試、持續整合,大家分享一下實踐經驗吧。

京東章耿:持續整合我們這邊其實在編譯環節就做了,上線我們這邊是有一個灰度上線功能。我們有一個預釋出環節,它可以直接把它標記為預發,然後有個測試平臺可以對它進行一個服務的測試。那如果是正式環境的話,那就他就得自己想辦法,因為我們現在這個環節是不能隨便測試的,因為我無法判斷你這個是讀還是寫,我不能讓你隨便測。

Q:因為你們是把一個業務系統拆成了很多這種服務化的服務去跑,那肯定是要涉及到這種單元測試、整合測試和業務流的這種測試,那這種測試的話你們都是怎麼做的呢?

京東章耿:這邊都是提前測的,就是你測都沒測,那你根本就提不到上線這一步。你上線的時候必須有一個測試審批通過,其實他其實就是已經線上下就測過了。

七牛陳愛珍:我們是基於 Jenkins 做的持續整合,把程式碼上傳到 Github 後,會做自動的程式碼靜態檢查和單元測試,再做自動的整合測試。這樣的好處是開發只需要開發程式碼,不需要構建環境,都是自動完成的,而且反饋的速度也會非常快速。

宅急送石廷鑫:測試環境是由開發人員去部署,線上正式環節,是從這個測試環境把報測試通過去的,直接拷貝過去。我覺得 Docker 是解決整個配置的問題,因為生產環境測試環境和開發環境不一樣。配置環境這個東西很難很麻煩做的,儘可能就是 UAT 的環境和測試環境,就是使用者測試的環境和線上的環境儘量是一樣。現在不是有配置管理嗎?這三個環境能來回切換。比方說 spring boot 這種,實際上就是一個 Jar 包命令。Jar 包命令唯一不同的就是它的配置問題,你只要一上線,那邊一監控就可以看到。因為你啟動時候他有註冊,註冊基本上他要調哪些東西就能看到他註冊的配置。

京東章耿:京東測試環境,預發,線上都是從原始碼庫裡編譯為準。主幹編譯為準,所以說程式碼應該是一樣的。線上配置我們是管理在配置中心,但是目前我們測試環境就沒有這個東西。預發,線上有配置中心,這個配置中心也整合到我們那個釋出平臺 JOne 上。

相關文章