外行人都能看懂的SpringCloud,錯過了血虧!

Java3y發表於2018-08-27

一、前言

只有光頭才能變強

認識我的朋友可能都知道我這陣子去實習啦,去的公司說是用SpringCloud(但我覺得使用的力度並不大啊~~)...

所以,這篇主要來講講SpringCloud的一些基礎的知識。(我就是現學現賣了,主要當做我學習SpringCloud的筆記吧!)當然了,我的水平是有限的,可能會有一些理解錯的的概念/知識點,還請大家不吝在評論區指正啊~~

SpringCloud GitHub Demo(看完文章的同學可以自己練手玩玩):

專案結構圖:

外行人都能看懂的SpringCloud,錯過了血虧!

二、叢集/分散式/微服務/SOA是什麼?

像我這種技術小白,看到這些詞(叢集/分散式/微服務/SOA)的時候,感覺就是遙不可及的(高大尚的技術!!)。就好像剛學Java物件導向的時候,在論壇上翻閱資料的時候,無意看到"面向切面程式設計",也認為這是遙不可及的(高大尚的技術!!)。

但真正接觸到"面向切面程式設計"的時候,發現原來就是如此啊,也沒什麼大不了的。只不過當時被它的名字給唬住了...

不知道各位在剛接觸這些名字叢集/分散式/微服務/SOA的時候,有沒有被唬住了呢??

  • 下面我就簡單說說這些名詞的意思

2.1什麼是叢集

以下內容來源維基百科:

計算機叢集簡稱叢集是一種計算機系統,它通過一組鬆散整合的計算機軟體和/或硬體連線起來高度緊密地協作完成計算工作。在某種意義上,他們可以被看作是一臺計算機。叢集系統中的單個計算機通常稱為節點,通常通過區域網連線,但也有其它的可能連線方式。叢集計算機通常用來改進單個計算機的計算速度和/或可靠性。一般情況下叢集計算機比單個計算機,比如工作站或超級計算機效能價格比要高得多

叢集技術特點:

  • 通過多臺計算機完成同一個工作,達到更高的效率。
  • 兩機或多機內容、工作過程等完全一樣。如果一臺當機,另一臺可以起作用。

在維基百科上說得也挺明白的了,我來舉個例子吧。

  • 小周在公司寫Java程式,但公司業務在發展,一個Java開發者可能忙不過來,小周有的時候也得請個假呀。於是請了3y過去一起做Java開發。平時小周和3y就寫Java程式,但3y可能有事要回學校一趟。沒事,公司還有小周做Java開發呢,公司開發還能繼續運作。
    • 3y跟小周都是做Java開發
    • 3y來了,小周的工作可以分擔一些。
    • 3y請假了,還有小周在呢。

我寫了一個910便利網釋出到伺服器去了,現在越來越多的人訪問了,訪問有點慢,怎麼辦???很簡單,(只有充錢才能變強),加配置吧(加cpu,加記憶體)。升級完配置之後,訪問人數越來越多,於是發現又不禁用啦,在這臺機器上加配置已經解決不了了,怎麼辦???很簡單,(只有充錢才能變強),我再買一臺伺服器,將910便利網也釋出到新買的這臺伺服器上去

特點:

  • 這兩臺伺服器都是執行同一個系統--->910便利網

好處:

  • 本來只有一臺機器處理訪問,現在有兩臺機器處理訪問了,分擔了壓力
  • 如果其中一臺忘記繳費了,暫時用不了了。沒關係,還有另一臺可以用呢。

叢集:同一個業務,部署在多個伺服器上(不同的伺服器執行同樣的程式碼,幹同一件事)

2.2什麼是分散式

以下內容來源維基百科:

分散式系統是一組計算機,通過網路相互連線傳遞訊息與通訊後並協調它們的行為而形成的系統。元件之間彼此進行互動以實現一個共同的目標

我也來舉個例子來說明一下吧:

  • 現在公司有小周和3y一起做Java開發,做Java開發一般jQuery,AJAX都能寫一點,所以這些活都由我們來幹。可是呢,3y對前端不是很熟,有的時候除錯半天都調不出來。老闆認為3y是真的菜!於是讓小周專門來處理前端的事情。這樣3y就高興了,可以專心寫自己的Java,前端就專門交由小周負責了。於是,小周和3y就變成了協作開發
    • 3y對前端不熟(能寫出來),但在除錯的時候可能會花費很多時間
    • 小周來專門做前端的事,3y可以專心寫自己的Java程式了。
    • 都是為了專案正常執行以及迭代。

我的910便利網已經部署到兩臺伺服器去了,但是越來越多的人去訪問。現在也逐漸承受不住啦。那現在怎麼辦啊??那繼續充錢變強??作為一個理智的我,肯定得想想是哪裡有問題。現在910便利網的模組有好幾個,全都丟在同一個Tomcat裡邊。

其實有些模組的訪問是很低的(比如後臺管理),那我可不可以這樣做:將每個模組抽取獨立出來,訪問量大的模組用好的伺服器裝著,沒啥人訪問的模組用差的伺服器裝著。這樣的好處是:一、資源合理利用了(沒人訪問的模組用效能差的伺服器,訪問量大的模組單獨提升效能就好了)。二、耦合度降低了:每個模組獨立出來,各幹各的事(專業的人做專業的事),便於擴充套件

特點:

  • 將910便利網的功能拆分,模組之間獨立,在使用的時候再將這些獨立的模組組合起來就是一個系統了。

好處:

  • 模組之間獨立,各做各的事,便於擴充套件,複用性高
  • 高吞吐量。某個任務需要一個機器執行10個小時,將該任務用10臺機器的分散式跑(將這個任務拆分成10個小任務),可能2個小時就跑完了

分散式:一個業務分拆多個子業務,部署在不同的伺服器上(不同的伺服器,執行不同的程式碼,為了同一個目的)

2.3叢集/分散式

叢集和分散式並不衝突,可以有分散式叢集

現在3y的公司規模變大了,有5個小夥子寫Java,4個小夥子寫前端,2個小夥子做測試,1個小夥子做DBA。

  • Java,前端,測試,DBA的關係看作是分散式的
  • 5個Java看作是叢集的(前端,測試同理)...

2.4分散式/微服務/SOA

其實我認為分散式/微服務/SOA這三個概念是差不多的,瞭解了其中的一個,然後將自己的理解往上面套就好了。沒必要細分每個的具體概念~~(當然了,我很期待有大佬可以在評論區留言說下自己的看法哈)

參考資料:

三、CAP理論

從上面所講的分散式概念我們已經知道,分散式簡單理解就是:一個業務分拆多個子業務,部署在不同的伺服器上

  • 一般來說,一個子業務我們稱為節點

如果你接觸過一些分散式的基礎概念,那肯定會聽過CAP這個理論。就比如說:你學了MySQL的InnoDB儲存引擎相關知識,你肯定聽過ACID!

首先,我們來看一下CAP分別代表的是什麼意思:

  • C:資料一致性(consistency)
    • 所有節點擁有資料的最新版本
  • A:可用性(availability)
    • 資料具備高可用性
  • P:分割槽容錯性(partition-tolerance)
    • 容忍網路出現分割槽,分割槽之間網路不可達。

下面有三個節點(它們是叢集的),此時三個節點都能夠相互通訊:

外行人都能看懂的SpringCloud,錯過了血虧!

由於我們的系統是分散式的,節點之間的通訊是通過網路來進行的。只要是分散式系統,那很有可能會出現一種情況:因為一些故障,使得有些節點之間不連通了,整個網路就分成了幾塊區域

  • 資料就散佈在了這些不連通的區域中,這就叫分割槽

外行人都能看懂的SpringCloud,錯過了血虧!

現在出現了網路分割槽後,此時有一個請求過來了,想要註冊一個賬戶。

外行人都能看懂的SpringCloud,錯過了血虧!

此時我們節點一和節點三是不可通訊的,這就有了抉擇:

  • 如果允許當前使用者註冊一個賬戶,此時註冊的記錄資料只會在節點一和節點二或者節點二和節點三同步,因為節點一和節點三的記錄不能同步的。
    • 這種情況其實就是選擇了可用性(availability),拋棄了資料一致性(consistency)
  • 如果不允許當前使用者註冊一個賬戶(就是要等到節點一和節點三恢復通訊)。節點一和節點三一旦恢復通訊,我們就可以保證節點擁有的資料是最新版本
    • 這種情況其實就是拋棄了可用性(availability),選擇了資料一致性(consistency)

3.1再次梳理一下CAP理論

一般我們說的分散式系統,P:分割槽容錯性(partition-tolerance)這個是必需的,這是客觀存在的。

CAP是無法完全兼顧的,從上面的例子也可以看出,我們可以選AP,也可以選CP。但是,要注意的是:不是說選了AP,C就完全拋棄了。不是說選了CP,A就完全拋棄了!

在CAP理論中,C所表示的一致性是強一致性(每個節點的資料都是最新版本),其實一致性還有其他級別的:

  • 弱一致性:弱一致性是相對於強一致性而言,它不保證總能得到最新的值;
  • 最終一致性(eventual consistency):放寬對時間的要求,在被調完成操作響應後的某個時間點,被調多個節點的資料最終達成一致

可用性的值域可以定義成0到100%的連續區間

外行人都能看懂的SpringCloud,錯過了血虧!

所以,CAP理論定義的其實是在容忍網路分割槽的條件下,“強一致性”和“極致可用性”無法同時達到

參考資料:

擴充套件閱讀:

四、SpringCloud就是這麼簡單

相信大家讀到這裡,對分散式/微服務已經有一定的瞭解了,其實單從概念來說,是非常容易理解的。只是很可能被它的名字給唬住了。

下面我就來講講SpringCloud最基礎的知識~

4.1為什麼需要SpringCloud?

前面也講了,從分散式/微服務的角度而言:就是把我們一的專案,分解成多個的模組。這些小的模組組合起來,完成功能。

舉個可能不太恰當的例子(現實可能不會這麼拆分,但意思到位就好了):

外行人都能看懂的SpringCloud,錯過了血虧!

拆分出多個模組以後,就會出現各種各樣的問題,而SpringCloud提供了一整套的解決方案!

  • 注:這些模組是獨立成一個子系統的(不同主機)。

SpringCloud的基礎功能

  • 服務治理: Spring Cloud Eureka
  • 客戶端負載均衡: Spring Cloud Ribbon
  • 服務容錯保護: Spring Cloud Hystrix
  • 宣告式服務呼叫: Spring Cloud Feign
  • API閘道器服務:Spring Cloud Zuul
  • 分散式配置中心: Spring Cloud Config

SpringCloud的高階功能(本文不講):

  • 訊息匯流排: Spring Cloud Bus
  • 訊息驅動的微服務: Spring Cloud Stream
  • 分散式服務跟蹤: Spring Cloud Sleuth

五、引出Eureka

那會出現什麼問題呢??首當其衝的就是子系統之間的通訊問題。子系統與子系統之間不是在同一個環境下,那就需要遠端呼叫。遠端呼叫可能就會想到httpClient,WebService等等這些技術來實現。

既然是遠端呼叫,就必須知道ip地址,我們可能有以下的場景。

  • 功能實現一:A服務需要呼叫B服務
    • 在A服務的程式碼裡面呼叫B服務,顯式通過IP地址呼叫http://123.123.123.123:8888/java3y/3
  • 功能實現二:A服務呼叫B服務,B服務呼叫C服務,C服務呼叫D服務
    • 在A服務的程式碼裡面呼叫B服務,顯式通過IP地址呼叫:http://123.123.123.123:8888/java3y/3,(同樣地)B->C,C->D
  • 功能實現三:D服務呼叫B服務,B服務呼叫C服務
    • 在D服務的程式碼裡面呼叫B服務,顯式通過IP地址呼叫:http://123.123.123.123:8888/java3y/3,(同樣地)B->C
  • .....等等等等

萬一,我們B服務的IP地址變了,想想會出現什麼問題:A服務,D服務(等等)需要手動更新B服務的地址

  • 在服務多的情況下,手動來維護這些靜態配置就是噩夢!

為了解決微服務架構中的服務例項維護問題(ip地址), 產生了大量的服務治理框架和產品。 這些框架和產品的實現都圍繞著服務註冊與服務發現機制來完成對微服務應用例項的自動化管理

在SpringCloud中我們的服務治理框架一般使用的就是Eureka。

我們的問題:

  • 現在有A、B、C、D四個服務,它們之間會互相呼叫(而且IP地址很可能會發生變化),一旦某個服務的IP地址變了,那服務中的程式碼要跟著變,手動維護這些靜態配置(IP)非常麻煩!

Eureka是這樣解決上面所說的情況的:

  • 建立一個E服務,將A、B、C、D四個服務的資訊都註冊到E服務上,E服務維護這些已經註冊進來的資訊

外行人都能看懂的SpringCloud,錯過了血虧!

A、B、C、D四個服務都可以拿到Eureka(服務E)那份註冊清單。A、B、C、D四個服務互相呼叫不再通過具體的IP地址,而是通過服務名來呼叫

  • 拿到註冊清單--->註冊清單上有服務名--->自然就能夠拿到服務具體的位置了(IP)。
  • 其實簡單來說就是:程式碼中通過服務名找到對應的IP地址(IP地址會變,但服務名一般不會變)

外行人都能看懂的SpringCloud,錯過了血虧!

5.1Eureka細節

Eureka專門用於給其他服務註冊的稱為Eureka Server(服務註冊中心),其餘註冊到Eureka Server的服務稱為Eureka Client。

外行人都能看懂的SpringCloud,錯過了血虧!

在Eureka Server一般我們會這樣配置:


    register-with-eureka: false     #false表示不向註冊中心註冊自己。
    fetch-registry: false     #false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要去檢索服務
複製程式碼

Eureka Client分為服務提供者和服務消費者

  • 但很可能,某服務既是服務提供者又是服務消費者

如果在網上看到SpringCloud的某個服務配置沒有"註冊"到Eureka-Server也不用過於驚訝(但是它是可以獲取Eureka服務清單的)

  • 很可能只是作者把該服務認作為單純的服務消費者,單純的服務消費者無需對外提供服務,也就無須註冊到Eureka中了

eureka:
  client:
    register-with-eureka: false  # 當前微服務不註冊到eureka中(消費端)
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

複製程式碼

下面是Eureka的治理機制:

  • 服務提供者
    • 服務註冊:啟動的時候會通過傳送REST請求的方式將自己註冊到Eureka Server上,同時帶上了自身服務的一些後設資料資訊。
    • **服務續約:**在註冊完服務之後,服務提供者會維護一個心跳用來持續告訴Eureka Server: "我還活著 ” 、
    • 服務下線:當服務例項進行正常的關閉操作時,它會觸發一個服務下線的REST請求給Eureka Server, 告訴服務註冊中心:“我要下線了 ”。
  • 服務消費者
    • 獲取服務:當我們啟動服務消費者的時候,它會傳送一個REST請求給服務註冊中心,來獲取上面註冊的服務清單
    • 服務呼叫:服務消費者在獲取服務清單後,通過服務名可以獲得具體提供服務的例項名和該例項的後設資料資訊。在進行服務呼叫的時候,優先訪問同處一個Zone中的服務提供方
  • Eureka Server(服務註冊中心):
    • **失效剔除:**預設每隔一段時間(預設為60秒) 將當前清單中超時(預設為90秒)沒有續約的服務剔除出去
    • 自我保護:。EurekaServer 在執行期間,會統計心跳失敗的比例在15分鐘之內是否低於85%(通常由於網路不穩定導致)。 Eureka Server會將當前的例項註冊資訊保護起來, 讓這些例項不會過期,儘可能保護這些註冊資訊

最後,我們就有了這張圖:

外行人都能看懂的SpringCloud,錯過了血虧!

舉個例子:

  • 3y跟女朋友去東站的東方寶泰逛街,但不知道東方寶泰有什麼好玩的。於是就去物業搜了一下東方寶泰商戶清單,發現一樓有優衣庫,二樓有星巴克,三樓有麥當勞。
  • 在優衣庫旁邊,有新開張的KFC,在牆壁打上了很大的標識“歡迎KFC入駐東方寶泰”。
  • 商家們需要定時交物業費給物業。
  • 物業維持東方寶泰的穩定性。如果某個商家不想在東方寶泰運營了,告訴了物業。物業自然就會將其在東方寶泰商戶清單去除。

優秀博文:

六、引出RestTemplate和Ribbon

通過Eureka服務治理框架,我們可以通過服務名來獲取具體的服務例項的位置了(IP)。一般在使用SpringCloud的時候不需要自己手動建立HttpClient來進行遠端呼叫。

可以使用Spring封裝好的RestTemplate工具類,使用起來很簡單:


	// 傳統的方式,直接顯示寫死IP是不好的!
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
	
	// 服務例項名
    private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

    /**
     * 使用 使用restTemplate訪問restful介面非常的簡單粗暴無腦。 (url, requestMap,
     * ResponseBean.class)這三個引數分別代表 REST請求地址、請求引數、HTTP響應轉換被轉換成的物件型別。
     */
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/consumer/dept/add")
    public boolean add(Dept dept) {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
    }

複製程式碼

為了實現服務的高可用,我們可以將服務提供者叢集。比如說,現在一個秒殺系統設計出來了,準備上線了。在11月11號時為了能夠支援高併發,我們開多臺機器來支援併發量。

外行人都能看懂的SpringCloud,錯過了血虧!

現在想要這三個秒殺系統合理攤分使用者的請求(專業來說就是負載均衡),可能你會想到nginx。

其實SpringCloud也支援的負載均衡功能,只不過它是客戶端的負載均衡,這個功能實現就是Ribbon!

負載均衡又區分了兩種型別:

  • 客戶端負載均衡(Ribbon)
    • 服務例項的清單在客戶端,客戶端進行負載均衡演算法分配。
    • (從上面的知識我們已經知道了:客戶端可以從Eureka Server中得到一份服務清單,在傳送請求時通過負載均衡演算法,在多個伺服器之間選擇一個進行訪問)
  • 服務端負載均衡(Nginx)
    • 服務例項的清單在服務端,伺服器進行負載均衡演算法分配

所以,我們的圖可以畫成這樣:

外行人都能看懂的SpringCloud,錯過了血虧!

6.1Ribbon細節

Ribbon是支援負載均衡,預設的負載均衡策略是輪詢,我們也是可以根據自己實際的需求自定義負載均衡策略的。


@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule()
	{
		//return new RandomRule();// Ribbon預設是輪詢,我自定義為隨機
		//return new RoundRobinRule();// Ribbon預設是輪詢,我自定義為隨機
		
		return new RandomRule_ZY();// 我自定義為每臺機器5次
	}
}

複製程式碼

實現起來也很簡單:繼承AbstractLoadBalancerRule類,重寫public Server choose(ILoadBalancer lb, Object key)即可。

SpringCloud 在CAP理論是選擇了AP的,在Ribbon中還可以配置重試機制的(有興趣的同學可以去搜搜)~

舉個例子:

  • 3y跟女朋友過了幾個月,又去東方寶泰了。由於記性不好,又去物業那弄了一份東方寶泰商戶清單。
  • 這次看到東方寶泰又開了一間麥當勞,一間在二樓,一間在三樓。原來生意太好了,為了能提高使用者體驗,在二樓多開了一間麥當勞
  • 這時,3y問女朋友:“去哪間麥當勞比較好?要不我們拋硬幣決定?”3y女朋友說:”你是不是傻,肯定哪間近去哪間啊“

優秀博文:

七、引出Hystrix

到目前為止,我們的服務看起來好像挺好的了:能夠根據服務名來遠端呼叫其他的服務,可以實現客戶端的負載均衡。

外行人都能看懂的SpringCloud,錯過了血虧!

但是,如果我們在呼叫多個遠端服務時,某個服務出現延遲,會怎麼樣??

外行人都能看懂的SpringCloud,錯過了血虧!

高併發的情況下,由於單個服務的延遲,可能導致所有的請求都處於延遲狀態,甚至在幾秒鐘就使服務處於負載飽和的狀態,資源耗盡,直到不可用,最終導致這個分散式系統都不可用,這就是“雪崩”。

外行人都能看懂的SpringCloud,錯過了血虧!

針對上述問題, Spring Cloud Hystrix實現了斷路器、執行緒隔離等一系列服務保護功能。

  • Fallback(失敗快速返回):當某個服務單元發生故障(類似用電器發生短路)之後,通過斷路器的故障監控(類似熔斷保險絲), 向呼叫方返回一個錯誤響應, 而不是長時間的等待。這樣就不會使得執行緒因呼叫故障服務被長時間佔用不釋放,避免了故障在分散式系統中的蔓延
  • 資源/依賴隔離(執行緒池隔離):它會為每一個依賴服務建立一個獨立的執行緒池,這樣就算某個依賴服務出現延遲過高的情況,也只是對該依賴服務的呼叫產生影響, 而不會拖慢其他的依賴服務

Hystrix提供幾個熔斷關鍵引數:滑動視窗大小(20)、 熔斷器開關間隔(5s)、錯誤率(50%)

  • 每當20個請求中,有50%失敗時,熔斷器就會開啟,此時再呼叫此服務,將會直接返回失敗,不再調遠端服務。
  • 直到5s鍾之後,重新檢測該觸發條件,判斷是否把熔斷器關閉,或者繼續開啟

Hystrix還有請求合併、請求快取這樣強大的功能,在此我就不具體說明了,有興趣的同學可繼續深入學習~

7.1Hystrix儀表盤

Hystrix儀表盤:它主要用來實時監控Hystrix的各項指標資訊。通過Hystrix Dashboard反饋的實時資訊,可以幫助我們快速發現系統中存在的問題,從而及時地採取應對措施。

啟動時的頁面:

外行人都能看懂的SpringCloud,錯過了血虧!

監控單服務的頁面:

外行人都能看懂的SpringCloud,錯過了血虧!

我們現在的服務是這樣的:

外行人都能看懂的SpringCloud,錯過了血虧!

除了可以開啟單個例項的監控頁面之外,還有一個監控端點 /turbine.stream是對叢集使用的。 從端點的命名中,可以引入Turbine, 通過它來彙集監控資訊,並將聚合後的資訊提供給 HystrixDashboard 來集中展示和監控

外行人都能看懂的SpringCloud,錯過了血虧!

舉個例子:

  • 3y和女朋友決定去萬達玩,去到萬達的停車場發現在負一層已經大大寫上“負一層已停滿,請下負二層,負二層空餘停車位還有100個!”
  • 這時,3y就跟女朋友說:“萬達停車場是做得挺好的,如果它沒有直接告知我負一層已滿,可能我就去負一層找位置了,要是一堆人跑去負一層但都找不到車位的話,恐怕就塞死了”。3y接著說:“看停車位的狀態也做得不錯,在停車位上頭有一個感應(監控),如果是紅色就代表已被停了,如果是綠色就說明停車位是空的”。
  • 3y女朋友不屑的說:“你話是真的多”

參考資料:

八、引出Feign

上面已經介紹了Ribbon和Hystrix了,可以發現的是:他倆作為基礎工具類框架廣泛地應用在各個微服務的實現中。我們會發現對這兩個框架的使用幾乎是同時出現的。

為了簡化我們的開發,Spring Cloud Feign出現了!它基於 Netflix Feign 實現,整合了 Spring Cloud Ribbon 與 Spring Cloud Hystrix, 除了整合這兩者的強大功能之外,它還提 供了宣告式的服務呼叫(不再通過RestTemplate)。

Feign是一種宣告式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請求遠端服務時能與呼叫本地方法一樣的編碼體驗,開發者完全感知不到這是遠端方法,更感知不到這是個HTTP請求。

下面就簡單看看Feign是怎麼優雅地實現遠端呼叫的:

服務繫結:


// value --->指定呼叫哪個服務
// fallbackFactory--->熔斷器的降級提示
@FeignClient(value = "MICROSERVICECLOUD-DEPT", fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {


    // 採用Feign我們可以使用SpringMVC的註解來對服務進行繫結!
    @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    public Dept get(@PathVariable("id") long id);

    @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
    public List<Dept> list();

    @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
    public boolean add(Dept dept);
}
複製程式碼

Feign中使用熔斷器:


/**
 * Feign中使用斷路器
 * 這裡主要是處理異常出錯的情況(降級/熔斷時服務不可用,fallback就會找到這裡來)
 */
@Component // 不要忘記新增,不要忘記新增
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept get(long id) {
                return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的資訊,Consumer客戶端提供的降級資訊,此刻服務Provider已經關閉")
                        .setDb_source("no this database in MySQL");
            }

            @Override
            public List<Dept> list() {
                return null;
            }

            @Override
            public boolean add(Dept dept) {
                return false;
            }
        };
    }
}

複製程式碼

呼叫:

外行人都能看懂的SpringCloud,錯過了血虧!

九、引出Zuul

基於上面的學習,我們現在的架構很可能會設計成這樣:

外行人都能看懂的SpringCloud,錯過了血虧!

這樣的架構會有兩個比較麻煩的問題:

  1. 路由規則與服務例項的維護間題:外層的負載均衡(nginx)需要維護所有的服務例項清單(圖上的OpenService)
  2. 簽名校驗、 登入校驗冗餘問題:為了保證對外服務的安全性, 我們在服務端實現的微服務介面,往往都會有一定的許可權校驗機制,但我們的服務是獨立的,我們不得不在這些應用中都實現這樣一套校驗邏輯,這就會造成校驗邏輯的冗餘。

還是畫個圖來理解一下吧:

外行人都能看懂的SpringCloud,錯過了血虧!

每個服務都有自己的IP地址,Nginx想要正確請求轉發到服務上,就必須維護著每個服務例項的地址

  • 更是災難的是:這些服務例項的IP地址還有可能會變,服務之間的劃分也很可能會變。

http://123.123.123.123

http://123.123.123.124

http://123.123.123.125

http://123.123.123.126

http://123.123.123.127

複製程式碼

購物車和訂單模組都需要使用者登入了才可以正常訪問,基於現在的架構,只能在購物車和訂單模組都編寫校驗邏輯,這無疑是冗餘的程式碼。

為了解決上面這些常見的架構問題,API閘道器的概念應運而生。在SpringCloud中了提供了基於Netfl ix Zuul實現的API閘道器元件Spring Cloud Zuul

Spring Cloud Zuul是這樣解決上述兩個問題的:

  • SpringCloud Zuul通過與SpringCloud Eureka進行整合,將自身註冊為Eureka服務治理下的應用,同時從Eureka中獲得了所有其他微服務的例項資訊。外層呼叫都必須通過API閘道器,使得將維護服務例項的工作交給了服務治理框架自動完成
  • 在API閘道器服務上進行統一呼叫來對微服務介面做前置過濾,以實現對微服務介面的攔截和校驗

Zuul天生就擁有執行緒隔離和斷路器的自我保護功能,以及對服務呼叫的客戶端負載均衡功能。也就是說:Zuul也是支援Hystrix和Ribbon

關於Zuul還有很多知識點(由於篇幅問題,這裡我就不細說了):

  • 路由匹配(動態路由)
  • 過濾器實現(動態過濾器)
  • 預設會過濾掉Cookie與敏感的HTTP頭資訊(額外配置)

9.1可能對Zuul的疑問

Zuul支援Ribbon和Hystrix,也能夠實現客戶端的負載均衡。我們的Feign不也是實現客戶端的負載均衡和Hystrix的嗎?既然Zuul已經能夠實現了,那我們的Feign還有必要嗎?

外行人都能看懂的SpringCloud,錯過了血虧!

或者可以這樣理解:

  • zuul是對外暴露的唯一介面相當於路由的是controller的請求,而Ribbonhe和Fegin路由了service的請求
  • zuul做最外層請求的負載均衡 ,而Ribbon和Fegin做的是系統內部各個微服務的service的呼叫的負載均衡

有了Zuul,還需要Nginx嗎?他倆可以一起使用嗎?

  • 我的理解:Zuul和Nginx是可以一起使用的(畢竟我們的Zuul也是可以搭成叢集來實現高可用的),要不要一起使用得看架構的複雜度了(業務)~~~

參考資料:

十、引出SpringCloud Config

隨著業務的擴充套件,我們的服務會越來越多,越來越多。每個服務都有自己的配置檔案。

既然是配置檔案,給我們配置的東西,那難免會有些改動的。

比如我們的Demo中,每個服務都寫上相同的配置檔案。萬一我們有一天,配置檔案中的密碼需要更換了,那就得三個都要重新更改

外行人都能看懂的SpringCloud,錯過了血虧!

在分散式系統中,某一個基礎服務資訊變更,都很可能會引起一系列的更新和重啟

Spring Cloud Config專案是一個解決分散式系統的配置管理方案。它包含了Client和Server兩個部分,server提供配置檔案的儲存、以介面的形式將配置檔案的內容提供出去,client通過介面獲取資料、並依據此資料初始化自己的應用

  • 簡單來說,使用Spring Cloud Config就是將配置檔案放到統一的位置管理(比如GitHub),客戶端通過介面去獲取這些配置檔案。
  • 在GitHub上修改了某個配置檔案,應用載入的就是修改後的配置檔案。

外行人都能看懂的SpringCloud,錯過了血虧!

SpringCloud Config其他的知識:

  • 在SpringCloud Config的服務端, 對於配置倉庫的預設實現採用了Git,我們也可以配置SVN。
  • 配置檔案內的資訊加密和解密
  • 修改了配置檔案,希望不用重啟來動態重新整理配置,配合Spring Cloud Bus 使用~

使用SpringCloud Config可能的疑問:application.yml和 bootstrap.yml區別

總結

本文主要寫了SpringCloud的基礎知識,希望大家看完能有所幫助~

SpringCloud的資料也很多,我整理一些我認為比較好,想要深入的同學不妨看看下邊的資源~~~

SpringCloud系列文章參考資料:

參考書籍:

  • 《SpringCloud 微服務實戰》

SpringCloud GitHub Demo(看完文章的同學可以自己練手玩玩,寫好了ReadMe了):

如果想看更多的原創技術文章,歡迎大家關注我的微信公眾號:Java3y。公眾號還有海量的視訊資源哦,關注即可免費領取。

可能感興趣的連結:

相關文章