1. 程式人生 > >spring cloud從看不懂到放棄

spring cloud從看不懂到放棄

why

當我們使用一個新技術的時候,應該首先問的一個問題就是why:為什麼要使用這個技術?或者問:這個技術是可以解決什麼問題。 我也想寫篇微服務的文章,以及微服務的優缺點 在微服務架構中,當一個大型系統被拆分成微服務系統以後,不僅包括功能拆分,還包括系統拆分、程式碼拆分、資料庫拆分、快取拆分等,多個系統的部署、維護、呼叫關係、排程、監控、fail over就會成為一系列問題。同時微服務系統劃分越多,呼叫鏈路可能會越長,呼叫鏈監控、全鏈路trace也會成為問題。 自然和自然的法則在黑夜中隱藏,上帝說讓牛頓誕生吧,於是一切都被照亮。spring cloud 就是這樣誕生的。spring cloud為服務治理而生。

舉個栗子,當一個大型系統被拆分成5個小業務系統以後,最容易想到的後端架構是:

前端需要維持多個系統

這樣問題很明顯,client需要維持5個業務系統地址,可能經常出現某個動作需要呼叫超過1個業務系統才能完成,而且無法保證事務性。於是出現了下面一個架構:

各個子系統之間不具有強關聯關係 api gateway和各個業務系統之間通過負載均衡發生呼叫關係,client只需要呼叫api gateway。 看起來好像解決了拆分問題、呼叫問題和client端問題。但是因為負載均衡裝置的存在,各個子系統之間不再有強關聯關係,子系統看起來像是互不關聯的系統一樣,各提供各的服務,當某一個子系統響應變慢時,可能會造成api gateway或者其他呼叫者系統也變慢,甚至會造成整個架構雪崩。自然,這種問題可以設定呼叫超時來一定程度上解決,但是spring cloud可以提供更優雅的方案。這種結構,要想解決排程、監控、fail over、全鏈路trace等問題,也需要接入其他第三方系統或工具,而spring cloud針對這些問題提供了一套完整的解決方案。

spring cloud簡介

先來看一下spring cloud包含了什麼元件:

這6張圖來自https://springcloud.cc/ 包括了spring cloud現在有的所有元件,以及每個元件的作用。我這裡粗淺介紹10個。
  1. spring cloud config

    • 遠端配置服務。
    • 遠端配置是每個都必不可少的中介軟體,遠端配置的特點一般需要:多節點主備、配置化、動態修改、配置本地化快取、動態修改的實時推送等。
    • config允許配置檔案放在git上或者svn上,和spring boot的整合非常容易,但是缺點就是修改了git上的配置以後,只能一個一個的請求每個service的介面,讓他們去更新配置,沒有修改配置的推送訊息。而且,如果要根據配置檔案的修改,做一些重新初始化操作的話(如執行緒池的容量變化等),會需要一些work around的方法,所以建議如果有其他方案,不建議選擇spring cloud config。
  2. spring cloud bus

    • 事件、訊息匯流排,用於在叢集(例如,配置變化事件)中傳播狀態變化。經常與Spring Cloud Config聯合使用。
    • spring cloud config本身不能向註冊過來的服務提供實時更新的推送。比如我們配置放在了git上,那麼當修改github上配置內容的時候,最多可以配置webhook到一臺config-server上,但是config-server自己不會將配置更新實時推送到各個服務上。
    • bus的作用就是將大家連結在一條總線上,這條線上的所有server共享狀態,當webhook到bus上的某一臺server的時候,其他server也會收到相同的hook狀態。
    • 但是bus的使用需要依賴於MQ,bus直接繼承了RabbitMq & kafka,只需要在spring中直接配置地址即可,但是對於其他型別的MQ,就需要一些手動配置。
    • 最大的問題還是,如果僅僅因為spring cloud bus而讓自己的系統引入MQ,顯然會有些得不償失。我理解系統應該在滿足現有業務需求的基礎上,越簡單越好,依賴越少鏈路越短,越能減少出問題的風險。
  3. eureka

    • spring cloud的服務發現元件。這個元件講起來需要大篇幅,最好和consul一起講。
    • eureka負責服務註冊和服務發現,為了高可用,一般需要多個eureka server相互註冊,組成叢集。Eureka Server的同步遵循著一個非常簡單的原則:只要有一條邊將節點連線,就可以進行資訊傳播與同步。
    • eureka內部對於註冊的service主要通過心跳來監控service是否已經掛掉,預設心跳時間是15s。這就意味著,當一個服務提供方掛掉以後,服務訂閱者最長可能30s以後才發現。
    • service啟動連上eureka之後,會同步一份服務列表到本地快取,服務註冊有更新時,eureka會推送到每個service。
    • eureka也會有一些策略防止由於某個服務所在網路的不穩定導致的所有服務心跳停止的雪崩現象。
    • eureka自帶web頁面,在頁面上能看到所有的服務註冊情況 和 eureka叢集狀態。
    • eureka支援服務自己主動下掉自己,請求service的下列地址,可以讓服務從eureka上下掉自己,同時service程序也會自己停掉自己。 curl -H 'Accept:application/json' -X POST localhost:${management.port}/shutdown
  4. consul

    • 也是一個服務發現工具,而且自帶key-value儲存服務、健康檢查 和 web頁面。
    • 聽起來好像比eureka高大上一些,裡面使用了gossip協議和Raft協議,但是他的缺點就是比eureka難維護。
    • 服務註冊是微服務架構的關鍵節點。所以我們現階段選擇的是eureka,然後遠端配置使用的是spring cloud config。如果要上容器和編排的話,會再看具體情況做選擇。
    • 但是,後來發現其實consul提供了官方的docker映象,直接使用docker-consul叢集使用者服務發現的話,運維成本會直線下降,後面會考慮把eureka + spring cloud config 換成consul。
  5. ribbon:

    • 客戶端負載均衡元件。
    • 服務發現以後,每個service在本地知道自己要呼叫的服務有多少臺機器,機器的ip是什麼,埠號是多少,那這個service在本地需要有一個負載均衡策略,為每一次請求選擇一臺目標機器進行呼叫,而ribbon做的就是負載均衡策略的選擇。
    • ribbon提供了多種負載均衡策略,包括BestAvailableRule、AvailabilityFilteringRule、WeightedResponseTimeRule、RetryRule、RoundRobinRule、RandomRule、ZoneAvoidanceRule等,沒記錯的話,預設是ZoneAvoidanceRule。當然,也可以自定義自己的負載均衡策略,比如被呼叫服務需要灰度釋出或者A/B測試的話,就可以在ribbon這一層做自定義。
  6. feign

    • 宣告式、模板化的HTTP客戶端。
    • 微服務之間的呼叫本質還是http請求,如果對於每個請求都需要寫請求程式碼,增加請求引數,同時對請求結果做處理,就會存在大量重複工作,而feign非常優雅的幫助我們解決了這個問題,只需要定義一個interface,fegin就知道http請求的時候引數應該如何設定。
    • 同時,feign也集成了ribbon,只要在微服務中依賴了ribbon,feign預設會使用ribbon定義的負載均衡策略。
    • 最重要的是,feign並不是僅僅只能使用在有eureka或者ribbon的微服務系統中,任何系統中,只要涉及到http呼叫第三方服務,都可以使用feign,幫我們解決http請求的程式碼重複編寫。
  7. hystrix

    • 斷路器,類似於物理電路圖中的斷路器。
    • 正常情況下,當整個服務環境中,某一個服務提供方由於網路原因、資料庫原因或者效能原因等,造成響應很慢的話,呼叫方就有可能短時間內累計大量的請求執行緒,最終造成呼叫方down,甚至整個系統崩潰。而加入hystrix之後,如果hystrix發現某個服務的某臺機器呼叫非常緩慢或者多次呼叫失敗,就會短時間內把這條路斷掉,所有的請求都不會再發到這臺機器上。
    • 如果某個服務所有的機器都掛了,hystrix會迅速失敗,馬上返回,保證被呼叫方不會有大量的執行緒堆積。
    • Feign預設集成了hystrix。
    • 上面有提到,使用eureka時,當一個服務提供方掛掉以後,服務訂閱者最長可能30s以後才知道,那這30s就會出現大量的呼叫失敗。如果在系統裡面集成了hystrix,就會馬上把掛掉的這臺服務提供方斷路掉,讓請求不再轉發到這臺機器上,大量減少呼叫失敗。
    • hystrix執行斷路操作以後,並不表示這條路就永遠斷了,而是會一定時間間隔內緩慢嘗試去請求這條路,如果能請求成功,斷路就會恢復。
    • 有一點需要注意的是hystrix在做斷路時,預設所有的呼叫請求都會放在一個的執行緒池中進行,執行緒池的作用很明顯,有隔離性。比如gateway,集成了5個子業務系統,可能其中一個系統的呼叫量非常大,而另外四個系統的呼叫很小,如果沒有執行緒池的話,顯然第一個系統的大量呼叫會影響到後面四個系統的呼叫效能。hystrix的執行緒池和java標準執行緒池一樣,可以配置一些引數:coreSize、maximumSize、maxQueueSize、queueSizeRejectionThreshold、allowMaximumSizeToDivergeFromCoreSize、keepAliveTimeMinutes等,如果某一個子系統的呼叫量突然激增,超過了執行緒池的容量,也會迅速失敗,直接返回,起到降級和保護系統本身的作用。當然hystrix也支援非執行緒池的方式,在本地請求執行緒中做呼叫,即semaphore模式,官方不建議,除非系統qps真的很大。
  8. zuul

    • 是一個閘道器元件。提供動態路由,監控,彈性,安全等邊緣服務的框架。
    • zuul主需要簡單配置一下properties檔案,不需要寫具體的程式碼就可以實現將請求轉發到相應的服務上去。
    • 還可以定製化一些filter做驗證、隔離、限流、檔案處理等切面,對於閘道器來說,使用zuul能減少大量的程式碼。
    • 不過我沒有使用過,不太瞭解,現在我們的閘道器主要還是基於feignClient、ribbon、hystrix來實現的。zuul預設也集成了這些元件。有興趣可以研究研究。
  9. turbine

    • 是聚合伺服器傳送事件流資料的一個工具,用來監控叢集下hystrix的metrics情況.
    • 在複雜的分散式系統中,相同服務的節點經常需要部署上百甚至上千個,很多時候,運維人員希望能夠把相同服務的節點狀態以一個整體叢集的形式展現出來,這樣可以更好的把握整個系統的狀態。
    • turbine提供把多個hystrix.stream的內容聚合為一個數據源供Dashboard展示.
  10. Spring Cloud Starters

    • spring boot熱插拔、提供預設配置、開箱即用的依賴。
    • starter 是spring boot框架非常基礎的部分。可以自定義starter。

我們現階段的後臺系統中,上述除了spring cloud bus、consul和zuul,其他都使用到。Talking is cheap, github地址: https://github.com/chxfantasy/spring-cloud-demo

作者:不如假如 連結:https://www.jianshu.com/p/7468643ead77 來源:簡書 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。