架構師小組交流會:每期選擇一個時下最熱門的技術話題進行實踐經驗分享。前端
本期小組交流會邀請到了滬江黃凱、惟品會鄭明華、滴滴趙偉、七牛雲肖勤,對微服務粒度、高可用、持續交互展開了交流。數據庫
本期接着上期惟品會、滴滴、滬江架構師,關於微服務粒度、高可用、持續交互的實踐分享交流(上)進行了交流。後端
第二輪:話題交流設計模式
滴滴趙偉:在整個服務,從單體服務到微服務的演進過程中,如何去影響業務的這種正常發展?服務器
惟品會鄭明華:從單體服務到微服務的改造,有兩種方式,一種是小打小鬧,每次稍微改一點,這個時間會很是長,有時候會發現改不動了,改的成本很是高。我舉個例子,之前咱們作訂單改造的時候,後來咱們怎麼作呢?就是一個個來,先把物流分出去,由於物流是相對獨立的。先把物流的訂單拆除,怎麼作呢?讓物流把他的業務和數據先存到,建套模型、物流的上層業務會有另外東西就是作雙寫。寫的時候寫兩邊,老的訂單系統寫,新的訂單系統也寫,兩個都寫。雙寫帶來的複雜度仍是挺高的。網絡
滴滴趙偉:對,你的數據的一致性,一邊寫成功一邊沒寫成功,這個確實是很麻煩的。架構
惟品會鄭明華:咱們讀的時候會有校驗。寫的時候是雙寫,但讀起來會有校驗,就是把新老兩個地方讀,而後校驗。若是校驗對兩個數據均可以,可是若是發現不對,以老的數據爲主,而且告警。負載均衡
滴滴趙偉:你怎麼去判斷哪一個是老的數據?好比個人隱私的操做,我下了個訂單,下完訂單,新系統和老系統。框架
惟品會鄭明華:寫的時候並無對比,可是讀的時候會有對比。我舉個例子,回顧一下剛纔講的那個同窗,寫的時候的確是寫了兩套不一樣的數據庫。咱們對比有兩種方式,一種是咱們有個 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 的功能,使開發只要提交代碼就自動進入全自動交付流程,直至上線。
其基本流程是這樣的:
開發成功提交代碼觸發 Jenkins pipeline。
Pipeline 由這樣幾部構成:測試、編譯、打成 Docker 鏡像、上傳鏡像、調用 Marathon API發佈到 QA 環境。
QA 經過自動或手動測試對 QA 環境進行驗證,若有問題返回開發修改並從新觸發 Pipeline。
測試經過後仍是由 Pipeline 自動發佈到驗證環境並調用腳本進行 FBT。
全部驗證無問題後 Pipeline 先對產線使用金絲雀發佈確認有無問題,若是沒有問題便可全面部署。
整個持續交付流程中有幾個特色:
整個發佈,所有是由 Pipeline 腳本調用 Marathon API 進行的,沒有任何人工參與。在實際使用能夠根據業務的敏感性作必定的人工干預,好比發佈到產線環境多是由運維人員協助完成。
交付過程當中的幾個環境除了產線環境之外,並非物理隔離的。而是根據需求動態建立或消亡的,相似於每次部署都是一個全新的環境,這樣作的好處是不容易產生髮布的冗餘數據和配置錯誤,這也是整個流程中最有特點的一個。
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 裏面去,這個受不了的,萬一有問題的話,你承擔不起這個責任吧。
滬江黃凱:對,是從一些小的應用開始實驗的。其實一個流程驗證跑通了,那麼接下來就能夠大規模的推進了,由於流程都是同樣的。