唯品會、滴滴、滬江架構師,關於微服務粒度、高可用、持續交互的實踐分享交流(下)

架構師小組交流會:每期選擇一個時下最熱門的技術話題進行實踐經驗分享。

本期小組交流會邀請到了滬江黃凱、唯品會鄭明華、滴滴趙偉、七牛雲肖勤,對微服務粒度、高可用、持續交互展開了交流。

本期接着上期唯品會、滴滴、滬江架構師,關於微服務粒度、高可用、持續交互的實踐分享交流(上)進行了交流。

第一輪:話題交流

滴滴趙偉:在整個服務,從單體服務到微服務的演進過程當中,如何去影響業務的這種正常發展?

唯品會鄭明華:從單體服務到微服務的改造,有兩種方式,一種是小打小鬧,每次稍微改一點,這個時間會非常長,有時候會發現改不動了,改的成本非常高。我舉個例子,以前我們做訂單改造的時候,後來我們怎麼做呢?就是一個個來,先把物流分出去,因爲物流是相對獨立的。先把物流的訂單拆除,怎麼做呢?讓物流把他的業務和數據先存到,建套模型、物流的上層業務會有另外東西就是做雙寫。寫的時候寫兩邊,老的訂單系統寫,新的訂單系統也寫,兩個都寫。雙寫帶來的複雜度還是挺高的。

滴滴趙偉:對,你的數據的一致性,一邊寫成功一邊沒寫成功,這個確實是很麻煩的。

唯品會鄭明華:我們讀的時候會有校驗。寫的時候是雙寫,但讀起來會有校驗,就是把新老兩個地方讀,然後校驗。如果校驗對兩個數據都可以,但是如果發現不對,以老的數據爲主,並且告警。

滴滴趙偉:你怎麼去判斷哪個是老的數據?比如我的隱私的操作,我下了個訂單,下完訂單,新系統和老系統。

唯品會鄭明華:寫的時候並沒有對比,但是讀的時候會有對比。我舉個例子,回顧一下剛纔講的那個同學,寫的時候的確是寫了兩套不同的數據庫。我們對比有兩種方式,一種是我們有個 bcp 系統,兩個數據都會歸結到另外一個地方幫你做檢查,這種方式我們很少做,所有的機器平臺以外,物流系統是不做的。比如說客戶在讀訂單,他在打訂單的時候會把這兩個訂單都讀出來,讀出來接口會幫他做對比,這兩個訂單是否一致,如果不一致,以老接口讀出來的數據爲主。新的接口數據告警,要麼人工參與,看問題是出現在哪裏。

滴滴趙偉:現在運行的效果怎麼樣?


唯品會鄭明華:這是一種傳統的做法,還是可以的。我在前公司的時候基本上是按照剛纔我講的方法解決了,而且我們該拆的都拆了很多,物流、金融、外匯、退稅、訂單,基本都是按照這種模式一個個拆的。但是你說不影響業務根本是不可能的,其中人力參與對訂單的拆分,對業務系統的拆分,本身參與的人力都會影響到業務系統的。還有另外一種比較乾脆的方式,就是做另外一個系統。整個系統一旦上線以後,新的業務能在兩個系統實現,直到有一天,我把老系統卸掉。

滴滴趙偉:那你牽扯到數據遷移吧?

唯品會鄭明華:無論哪種方式都會涉及到數據的遷移,一旦數據模型變化以後,都會涉及到數據的清洗遷移。如果新老兩個數據模型不能兼容,數據沒法遷移,數據的遷移會帶來數據損失。

滴滴趙偉:那你在遷移當中你需要停服務嗎?

唯品會鄭明華:基本上不需要停服務,目前爲止,我在阿里的時候,不會停止服務。因爲新的業務都已經在設計,兩邊的數據都有,我把老的數據遷回來就可以了,不會影響到我真正的業務。

滴滴趙偉:我們最早就是按微服務的架構去設計的,並沒有經歷從單體服務到微服務的演變過程,所以我很好奇的一點,在做單體到微服務,整個過程當中你覺得有哪些點是你要去關注的,或者是那個地方有這種挑戰性,或者那些點是必須去考慮的,或者那些是要去做好的?

唯品會鄭明華:把一個大的系統拆成了多個服務,很多個服務到了數據庫以後,這個分佈式的問題怎麼解決?這的確有考慮的問題,包括消息中間件,多個服務,每個服務我通過消息的方式來做通訊的時候,那消息的穩定性、順序性怎麼去解決,這就是從技術角度考慮的。

然後我怎麼拆服務,還是從業務角度來拆。我希望每個業務是自包含的,可獨立部署的。比如訂單的拆單和訂單的尋倉,這是兩個不同的服務,而這兩個服務應該完全解耦關係,按供應商或者商戶拆單,做完拆單以後,你才能把訂單分發到不同倉庫裏面去,這是兩個先後的動作。這兩個動作不應該糾纏在一起,這兩個動作對應的是不同服務,應該是完全隔離開的,而且他們之間的數據庫也是隔離開的。所以如果從業務角度考慮,只要業務瞭解深熟以後,對服務的拆分不是很大難題。

七牛肖勤:服務的分拆肯定會讓結構更加複雜,但微服務在理念描述上已經意識到,從服務架構着眼,設計上考慮了部署的問題,運營在架構中的優先級也是排在第一位的,而以往在設計模式、軟件架構基本不會考慮到部署、運營的問題。所以,如果要支持微服務架構,必須有一套行之有效的運營、部署的工具和方式,這也是容器相關技術和容器雲現在備受關注的一個原因。

依賴的問題,包括一部分的複雜性問題,取決於拆分時候邊界和接口的定義、數據聯通的方式,設計得是不是足夠合理,服務提供者是不是清楚需求的方式,服務調用者是不是理解接口的意圖,也就是說團隊針對每個服務的溝通,對事情的定位,對接口的抽象,是不是有一個同樣的認知水平,達成一個共識。只要保證接口穩定、合理,實現不管怎麼變化,對整合架構就不會有負面影響。服務的局部修改反而可以更快速,因爲不會涉及一個大系統的調整。

所以說,不能爲了拆分而拆分,拆分的意圖要準確描述問題的解決。在一個系統裏面,定義接口比怎麼實現更重要,不要設計不好理解、不合理的接口。

滴滴趙偉:因爲我也在考慮如果讓我去做單體服務到微服務,我覺得監控告警必須先行,然後這種服務的降級之類的,可能要去考慮到位的。

唯品會鄭明華:你說的是大的問題。如果沒有很好的監控對大的互聯網來說是個災難。

滴滴趙偉:據我所知從這種單體服務到微服務的這種轉變過程當中,可能像他們這種東西都是缺失的,除了這些還包括人員能力的問題。他以前做單體服務,你讓他突然轉成這種微服務它可能有種不適應,包括他定位問題的這種方式轉化都有些發生變化了。

唯品會鄭明華:無論在阿里還是唯品會都是有比較完善的監控。包括一旦用了我們服務框架以後,從外部調用到我們後臺服務,到數據層的調用。每個調動服務,包括操作都有很詳細的監控,包括每一個環節的耗時,它都能幫你監控出來。舉個淘寶的例子,淘寶有個鷹眼系統,那個鷹眼系統就能檢測到所有的電容鏈路。包括每個鏈路的後期說話。所以淘寶也有詳細的告警系統。包括流控、限流、降級,這些都有詳細的方案。比如服務怎麼去註冊,怎麼去發現,機器出現故障以後,它怎麼去告警,怎麼從你的服務器中去拆掉,卸下來,這些都是你要做微服務的基礎措施吧。沒有這東西你靠員工去做,如果幾百臺機器,幾百個服務,還能應付。就幾萬個服務,幾萬個機器,可能就搞不下去。

所以這種基礎措施應該是搞大型互聯網系統的必備的。沒有這東西我覺得搞互聯網簡直吃不好,睡不着,你都不知道那個地方出了點小毛病。如果有很好的監控設施,我們就能及時發現問題。小毛病也有可能後面藏着重大隱患。

我曾經碰到一個事故就是我的硬盤滿了,因爲所有應用日誌都存進去了,當時沒有監控硬盤的利用率,結果線上服務異常。如果有監控的話,包括 CPU、IP,包括硬盤、監控系統、降級限流,還有另外一種是系統壓測,都是我認爲大型互聯網系統必備的手段方法。


主持人:單體服務到微服務這種重構拆封的會遇到什麼樣的難點?或者怎麼樣去解決?

唯品會鄭明華:剛纔都討論了,像服務框架、架構框架、基礎設施,是要解決的問題,沒有這些儲備,服務或者微服務根本就是實現不了。

滴滴趙偉:另外的一個的話,我覺得微服務的話整個成本會很高。微服務的成本,比如機器,運維人員的能力成本,對吧?這都要提升的。

唯品會鄭明華:包括這個測試定位都是成本。

滴滴趙偉:對。都是成本,整個成本都會上升的,小公司的話他可能這個在這方面投入應該不會大的,因爲沒錢了。

唯品會鄭明華:所以服務後微服務是要看團隊的能力,要看公司。


主持人:API 網關是怎麼設計的?

七牛肖勤:在微服務架構中,每一個微服務都可以做爲服務的提供點,客戶端可以直接調用。當要同時調用多個微服務時,客戶端則需要逐一發送多個獨立的請求,這樣效率會很低效。通過設計 API 網關做爲系統唯一的接入點,客戶端所有請求都先經過 API 網關,然後再由它將請求路由到合適的微服務。這樣客戶端只需要同 API 網關交互,而不必調用特定的服務,而且 API 網關可以調用多個微服務來處理同一個請求,這樣簡化了客戶端與服務之間交互的次數,同時簡化了客戶端的代碼。我們的 API 網關目前具備流量轉發,服務發現,流量控制,服務降級,權限控制,容錯及監控的功能。

流量轉發具有負載均衡的功能,採用的是輪詢的方式,服務發現則是基於 Consul 做的。用戶請求進來後通過 Consul 查詢到所有可用節點的訪問地址,再通過輪詢的方式將請求發給後端的服務進行處理,對於返回的結果僅作轉發,由請求方解釋和使用。並且在 API 網關中帶有監控的組件,對請求數,失敗數等進行監控,傳送到 Prometheus 服務器上。通過監控數據對請求進行流量控制及服務降級等相應的處理。

滴滴趙偉:我們的 API 網關,主要分兩部分。一部分是承接外部的請求,即所謂的 API 網關。另外一部分是對 API 進行生命週期後臺管理服務。這兩套東西全部都是以外部方式提供服務的。我們當時使用網關也就解決幾個問題。

第一是解耦,對於前端跟後端,內部服務不要在公網直接暴露,通過網關可除去,外部服務通過 HTTP 請求過來,外部也不需要依賴 Client 的這種東西。然後後端的話也是可以去持續開發,降低外部調用成本。然後通過這種調用的,也通過 Json 的這種格式。網關對 Json 進行入參,然後到後面把 Json 轉成對象,然後出參數才能對象轉 Json 這種屏蔽這種複雜性。通過網關,我們也會去做一些這種鑑權、流控、降級、監控這方面的。通過網關可以把整個口就收攏掉了。然後管理後臺,主要是對 API 的生命週期的管理,包括鑑權,還有 API 這種後端這種服務之間的映射,這種關係之類。我們就通過在管理後臺,一旦改完之後,所以互聯網關不是單臺機器,然後所有的網關都要同時要生效之類的這種,也通過 MQ 這種去廣播這種消息。

滬江黃凱:那這個 API 網管是不是相當於一個單點?這樣會導致所有的流量全部通過網關轉送到下一個服務中去。網關一旦出現什麼事情,或者是它的效率很慢,會導致整個的業務流程都慢下來了。

滴滴趙偉:我們首先看整個業務量吧,對代駕來說,它業務量其實並沒有那麼高。因爲它不是很高頻。我們雖然是單點,但是我們機器不是單點的,有多臺機器的。一般要出問題的話,網關不太會出問題。可能後端服務會出問題。後端的服務出問題,不是它做一次新的這種發佈,有 bug,或者他的這種服務的耗時從過去。比如說 5 毫秒,6 毫秒,突然變成 500,600 毫秒的這種,可能會導致一些問題。所以我們在網關上面,會去做流控、降級、監控這些事情,以保證它的這種。在網關上面做流控。做流控降級這種去保證它的這種金融健康。

滬江黃凱:服務註冊進來以後,你的網關是怎麼樣發現這個服務呢?

滴滴趙偉:我們有管理後臺人工去配置的。每上一個服務要暴露的話,是需要去到我管理後臺上面去配它的那個 Class,那個什麼類名,方法,參數之類的都是要配進去的,然後跟我的 API Gateway 對外暴露的名字要做映射關係的。

唯品會鄭明華:網關我們也在做,我們網關是一個集羣,或者多個集羣,不是單個集羣。首先不是一個單臺服務器,而是一堆服務器,而且這對服務器可能還不是一個小集羣,而是一個大的集羣,這個大集羣可能還有多個小集羣,他每個集成可能是對應不同業務的,所以說即使是像你說的某個網絡出問題了,它也不影響他所有的業務,這是第一個;第二個是網關主要就是一個通道,無狀態、無業務邏輯,所以就是說他出問題的可能性很小。

滬江黃凱:你們用什麼語言開發?

唯品會鄭明華:我們一般是用 Java 開發。

滬江黃凱:如果我是 HTTP 請求,會使用類似 HTTP client 作爲轉發工具對不對?

滴滴趙偉:我們是以 Doubbo 的方式,那個 API 的 Gateway,他實際上也是在 Doubbo 上面,會去從 Doubbo 上面拿到你底層的服務,他的這個淨化之類的,去調撥去的,他不會走那種的,就是說他會網關他會進來,我們就進來計算,接受的是 Json,轉成對象,然後打成二進制流,通過這種 Double 的這種 RPC 給調到後臺去了。

滬江黃凱:所以你服務都是 Java 開發了,沒有任何的其他的語言?

唯品會鄭明華:這個不是。這個首先是服務跟語言沒有關係,跟序列化協議有關係。

滴滴趙偉:他這種主要是序列化,因爲語言是序列號的這種前後高地位之類的,這種可能不太一樣,你自己的長度可能不一樣,所以可能就是用這種業界比較通用的一些,比如 Stream 的這類這些東西,或者說你自己去搞一套這種二進制的這種序列化。

滴滴趙偉:有些語言他可能不太支持,比如說像可能新進來的這種 Go,可能有些不太支持,所以這個有時候也比較麻煩一點。

滬江黃凱:我們很多服務都是用其他語言寫的,比如 Go,C++ 和 .NET 語言,如果要推 RPC協議,會造成其他的部門的反對,因爲他們接不進去,這樣對於驅動項目效率太低。爲統一這些項目的管理,我們都統一使用 Restful 作爲服務間的交流方式。

滴滴趙偉:另外 HTTP,他的性能可能要比 RPC,TCP 這種純的這種 TCP 可能要性能要低。因爲我覺得公司發展到最後,技術框架應該會統一。從業界來看,除了阿里,阿里做的方法他 HTTP 轉成純 Java。業界其他的一些大的公司,比如騰訊、百度好像都是多語言開發的,前面用 PHP,後面用 C。但是好像只有阿里做的比較好,整個技術框架統一。我覺得可能是要方向,這樣成本會很低,業務間打通成本就會很低,後面發展會加速的,但是去做這件事確實很難。

唯品會鄭明華:我現在在唯品會就是做這種事情,把 PHP 的語言逐步改成 Java 的開發。但我一直相信這個事情要做的。因爲在公司內部,團隊是流動的。如果都是 Java 的,流動還好。但是一個是 C,一個是 PHP 的,流動的難度就大。比如我們有的業務不做了,技術團隊也不好轉成其他的語言。從另外一個角度看,技術統一以後,開發維護或者溝通協調的成本都會降低很多。


主持人:如何提高服務的高可用?

滬江黃凱:微服務天生就是高可用的吧。微服務大部分屬於無狀態的服務,只要解決了橫向的拓展問題就解決了高可用問題。對於這種無狀態的微服務,我們公司提供了Docker+mesos+marathon 三劍客的解決方案,所以應用程序不會死掉,如果死掉也會自動重啓。那對於有狀態的服務來說高可用比較難,所以我之前就在問,大家的微服務都是無狀態的嗎。如果是有狀態的,那就必須解決高可用的問題。

唯品會鄭明華:如果有狀態的服務,必須做到客戶 Session 粘連,但性能會大幅度下降。

滬江黃凱:解決方法是不是 Active+standby 模式?客戶端通過 VIP 訪問?

唯品會鄭明華:但是你還是解決不了這個,一旦它死掉以後,客戶連上來的狀態也丟了。

唯品會鄭明華:因爲你現在客戶都是連的 Tcp。

滴滴趙偉:它肯定會斷掉的,要重新連一下的,這肯定的,你這邊使用那個虛擬 IP 的話。當它連到後面還是連到某一臺固定的機器上,機器就死掉了,就是內部的那個 socket 就斷掉了,雖然外部的沒有斷,實際上還是要重新建。

滴滴趙偉:一旦一鍵 Retry 過了嘛,整個鏈路就打通了,這個時候斷了其實用戶實際上還是要重新連一下的。

主持人:客戶端 Retry 一下。

唯品會鄭明華:可能還有難度的,因爲當時你第一次建連接的時候,你用的那個 Docker,可能都沒了,你再連接再重試也沒用了,是看你連的是哪一個。

滬江黃凱:那是不是要有一個 Session 的服務來存儲狀態?服務狀態會存在 Redis 或內存中嗎?

滴滴趙偉:所以你的這種服務就是無狀態的了,因爲你把狀態已經搞到 Redis,所以說你的服務就成無狀態的了,所以你得服務是可以互相擴展的,或者擴服務,減服務都沒問題。

唯品會鄭明華:要做到客戶的黏粘,那個服務器起來以後才還能用,否則的話基本上很難做。另外一個是你選擇什麼服務框架,就比如 Doubbo,這也是一個常見的模式。所以這裏面已經解決了服務故障以後怎麼重試的的問題。


主持人:線上的微服務怎麼做持續交付?

滴滴趙偉:我們其實還沒有做持續交付,還在嘗試持續集成。因爲你要做持續交互的話,不是你一個業務部門能夠單獨去做的這件事情。因爲你會涉及到很多,比如 IP 的分配,服務層報道。我們是想通過 Docker 來做持續交互,你將來的 IP 怎麼去分配,端口怎麼去分配,包括 Docker 的持續分配。我們原先最早的時候用的是騰訊的機器人,他那個系統,現在出來鏡像都沒辦法用,你知道嗎?真的搞得就很蛋疼,包括以後將來日誌收集的查看,這些問題不是一個業務系統能夠解決的,它必須跟運維部門去合作做這件事情,包括你要牽涉到一個發佈的流程,我們現在在嘗試這種持續集成,持續交互我們現在還做不了。

唯品會鄭明華:我簡單說下,就是持續集成/交付是一個比較大的東西。從開發到測試環境,包括灰度環境,包括預發佈環境。比如在測試環境裏怎麼去集成,因爲你是一個微服務,你想再把整個業務順起來,需要周邊的幾十個,幾百個服務才能把這個業務跑起來,那怎麼解決開發的版本跟其他服務的測試問題,這是個大的問題。在以前的工序裏面,它做了很多工作,包括建個人的測試環境,然後建整個團隊的那種聯調測試環境,以及你持續發佈測試環境?那麼這東西都要把它建立起來才能做到,才能正真做持續發佈。

滴滴趙偉:就這個問題,這樣除了你的業務之外還要牽扯到存儲,比如 MySQL,Redis 這類東西,確確實實持續集成持續交互都是比較難的,現在 Docker,Kubernetes 是在解決這個問題,但是現在很多公司目前都還在嘗試 Docker ,但業界玩的很好的還沒怎麼見過。

滬江黃凱:我們已經有持續集成/發佈的方案。由於我們課件系統所有的服務全部使用 Docker部署。基於 Devops 和 Openstack 的啓發,我們充分利用了 Docker 一次製作隨處使用的特性,利用 Jenkins pipeline 的功能,使開發只要提交代碼就自動進入全自動交付流程,直至上線。

其基本流程是這樣的:

  1. 開發成功提交代碼觸發 Jenkins pipeline。

  2. Pipeline 由這樣幾部構成:測試、編譯、打成 Docker 鏡像、上傳鏡像、調用 Marathon API發佈到 QA 環境。

  3. QA 通過自動或手動測試對 QA 環境進行驗證,如有問題返回開發修改並重新觸發 Pipeline。

  4. 測試通過後還是由 Pipeline 自動發佈到驗證環境並調用腳本進行 FBT。

  5. 所有驗證無問題後 Pipeline 先對產線使用金絲雀發佈確認有無問題,如果沒有問題即可全面部署。

整個持續交付流程中有幾個特點:

  1. 整個發佈,全部是由 Pipeline 腳本調用 Marathon API 進行的,沒有任何人工參與。在實際使用可以根據業務的敏感性做一定的人工干預,比如發佈到產線環境可能是由運維人員協助完成。

  2. 交付過程中的幾個環境除了產線環境以外,並不是物理隔離的。而是根據需求動態創建或消亡的,類似於每次部署都是一個全新的環境,這樣做的好處是不容易產生髮布的冗餘數據和配置錯誤,這也是整個流程中最有特色的一個。

  3. Docker 的一次製作,隨處可用特性在交付流程中大大的避免了環境不一致問題造成的部署複雜度。

滴滴趙偉:我們現在想做這些事情,但是其中有一個比較麻煩的事,現在用這個的話。我們肯定要嘗試新的技術的,不可能就是一刀切,就直接全部就上去了,每次全部就上去了,因爲你並不熟這個東西,也沒有經過現場的驗證,肯定也是逐步去試的。逐步去試問題就在於我們有一部分服務是在 Docker 類似裏面改的,有一部分服務它在外部的。服務的註冊和發現,你們現在是怎麼搞的?包括像這種日誌,因爲它放到鏡像裏面去,日誌相當於輸出,你怎麼定位問題這個查日誌,包括你的監控這塊會怎麼去做呢?

滬江黃凱:其實在整個框架中註冊與發現有兩種方式,一種是服務啓動之後主動地向註冊服務器註冊信息。我們現在使用 Consul,也就是說服務在啓動後會自動調 Consul 的註冊服務API,告訴 Consul 服務的 IP 地址和端口。這裏 IP 地址是宿主機的 IP+ 映射的端口,宿主機 IP 通過環境變量自動注入 Docker 中,每個 Docker 就自動知道了宿主機 IP。這種方法有侵入性,其實在我們使用編排框架,比如 Kubernetes 或 Mesos,是知道啓動在資源池中的 Docker 服務的端口是什麼,名字叫什麼,儘管端口和 IP 都動態的。還有一點是要解決內網和外網互通,這是我們實現 Docker 微服務編排的必要步驟。如果啓動了很多微服務,如果這些微服務都是無狀態的,而且是平行服務,一定需要一個 Load balance。只要在這個 Load balance 上開端口映射,內外網就打通了。

滬江黃凱:另外一種服務註冊與發現是通過三方的工具不斷監控編排服務的變化,如果發現有新服務啓動,則自動註冊。關於日誌的輸出,我們使用 Volume 掛載 HOST 本地文件系統的方式,把 Docker 中的日誌文件“引”到宿主機上,再通過ELK套件管理和查詢。每個日誌文件都會有具體的 Docker 的 IP,查詢問題非常方便。

滴滴趙偉:對於業務部門這個事情很難做很難做,除非你進來之後他們幫你解決這種問題或者系統部進來幫你解決這種問題。

滴滴趙偉:但問題是我們現在還沒有 Loadbalance 服務,他們都是自己通過 ZK 去搞得這種,Doubbo 的那個東西就相當於我們在用 Loadbalance 這種東西。所以對我們來說,這東西就很麻煩很難去做。所以就一直搞不定,肯定要先拿小服務去試一下,不能強上去,全部放到 Docker 裏面去,這個受不了的,萬一有問題的話,你承擔不起這個責任吧。

滬江黃凱:對,是從一些小的應用開始實驗的。其實一個流程驗證跑通了,那麼接下來就可以大規模的推動了,因爲流程都是一樣的。


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