1. 程式人生 > >微服務Springcloud超詳細教程+實戰(十二)

微服務Springcloud超詳細教程+實戰(十二)

本人正在找深圳Java實習工作,求大佬帶飛 QQ:1172796094
如在文件中遇到什麼問題請聯絡作者
——————————————————————————————————————

CAP

CAP原則:CAP原則又稱CAP定理,指的是在一個分散式系統中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分割槽容錯性),三者不可兼得

分割槽容錯性

大多數分散式系統都分佈在多個子網路。每個子網路就叫做一個區(partition)。分割槽容錯的意思是,區間通訊可能失敗。比如,一臺伺服器放在中國,另一臺伺服器放在美國,這就是兩個區,它們之間可能無法通訊。
在這裡插入圖片描述


上圖中,G1 和 G2 是兩臺跨區的伺服器。G1 向 G2 傳送一條訊息,G2 可能無法收到。系統設計的時候,必須考慮到這種情況。

一般來說,分割槽容錯無法避免,因此可以認為 CAP 的 P 總是成立。CAP 定理告訴我們,剩下的 C 和 A 無法同時做到。

一致性

Consistency 中文叫做"一致性"。意思是,寫操作之後的讀操作,必須返回該值。舉例來說,某條記錄是 v0,使用者向 G1 發起一個寫操作,將其改為 v1。
在這裡插入圖片描述
接下來,使用者的讀操作就會得到 v1。這就叫一致性。
在這裡插入圖片描述
問題是,使用者有可能向 G2 發起讀操作,由於 G2 的值沒有來得及發生變化,因此返回的是 v0。G1 和 G2 讀操作的結果不一致,這就不滿足一致性了。
在這裡插入圖片描述


為了讓 G2 也能變為 v1,就要在 G1 寫操作的時候,讓 G1 向 G2 傳送一條訊息,要求 G2 也改成 v1。
在這裡插入圖片描述
這樣的話,使用者向 G2 發起讀操作,也能得到 v1。
在這裡插入圖片描述

可用性

Availability 中文叫做"可用性",意思是隻要收到使用者的請求,伺服器就必須給出迴應。

使用者可以選擇向 G1 或 G2 發起讀操作。不管是哪臺伺服器,只要收到請求,就必須告訴使用者,到底是 v0 還是 v1,否則就不滿足可用性。

一致性和可用性的矛盾

一致性和可用性,為什麼不可能同時成立?答案很簡單,因為可能通訊失敗(即出現分割槽容錯)。

如果保證 G2 的一致性,那麼 G1 必須在寫操作時,鎖定 G2 的讀操作和寫操作。只有資料同步後,才能重新開放讀寫。鎖定期間,G2 不能讀寫,沒有可用性。

如果保證 G2 的可用性,那麼勢必不能鎖定 G2,所以一致性不成立。

綜上所述,G2 無法同時做到一致性和可用性。系統設計時只能選擇一個目標。如果追求一致性,那麼無法保證所有節點的可用性;如果追求所有節點的可用性,那就沒法做到一致性。

總結:

  1. 分割槽容錯性/可靠性P:不同地區的同一個系統的叢集,叢集間的通訊可能失敗(必然事件)
  2. 一致性C:同一時間請求叢集中任何一個節點,返回的資料一致
  3. 可用性A:叢集中的每個節點,任何時候都是可用的

CP:一致性+分割槽容錯性/可靠性-------->zookeeper,淘寶

AP:可用性+分割槽容錯性/可靠性--------->SpringCloud

重試機制

Eureka的服務治理強調了CAP原則中的AP,即可用性和可靠性。它與Zookeeper這一類強調CP(一致性,分割槽容錯)的服務治理框架最大的區別在於:Eureka為了實現更高的服務可用性,犧牲了一定的一致性,極端情況下它寧願接收故障例項也不願丟掉健康例項,正如我們上面所說的自我保護機制。

但是,此時如果我們呼叫了這些不正常的服務,呼叫就會失敗,從而導致其它服務不能正常工作!這顯然不是我們願意看到的。

我們現在關閉一個user-service例項:
在這裡插入圖片描述
因為服務剔除的延遲,consumer並不會立即得到最新的服務列表,此時再次訪問你會得到錯誤提示:
在這裡插入圖片描述
但是此時,8081服務其實是正常的。

因此Spring Cloud 整合了Spring Retry 來增強RestTemplate的重試能力,當一次服務呼叫失敗後,不會立即丟擲異常,而是再次重試另一個服務。

只需要(user-consumer)簡單配置即可實現Ribbon的重試:

spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true # 開啟Spring Cloud的重試功能
user-service:
  ribbon:
    ConnectTimeout: 250 # Ribbon的連線超時時間
    ReadTimeout: 1000 # Ribbon的資料讀取超時時間
    OkToRetryOnAllOperations: true # 是否對所有操作都進行重試
    MaxAutoRetriesNextServer: 1 # 切換例項的重試次數
    MaxAutoRetries: 1 # 對當前例項的重試次數

根據如上配置,當訪問到某個服務超時後,它會再次嘗試訪問下一個服務例項,如果不行就再換一個例項,如果不行,則返回失敗。切換次數取決於MaxAutoRetriesNextServer引數的值

引入spring-retry依賴

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

我們重啟user-consumer-demo,測試,發現即使user-service2宕機,也能通過另一臺服務例項獲取到結果!
在這裡插入圖片描述