回到 Istio 的微服務。 第2部分

回到 Istio 的微服務。 第2部分

筆記。 翻譯。: 第一部分 本系列致力於介紹 Istio 的功能並在實踐中演示它們。 現在我們將討論此服務網格的配置和使用的更複雜方面,特別是精細調整的路由和網路流量管理。

我們也提醒您,本文使用儲存庫中的配置(Kubernetes 和 Istio 的清單) istio 掌握.

交通管理

借助 Istio,集群中出現了新功能,可提供:

  • 動態請求路由:金絲雀部署、A/B 測試;
  • 負載平衡:簡單且一致,基於哈希;
  • 跌倒後恢復:超時、重試、斷路器;
  • 插入故障:延遲、放棄請求等。

隨著本文的繼續,將使用所選應用程式作為範例來說明這些功能,並在此過程中引入新概念。 第一個這樣的概念將是 DestinationRules (即有關流量/請求接收者的規則 - 大約翻譯),在此幫助下我們啟動 A/B 測試。

A/B 測驗:實踐中的 DestinationRules

A/B 測試用於應用程式有兩個版本(通常它們在視覺上不同)並且我們不能 100% 確定哪一個版本會改善使用者體驗的情況。 因此,我們同時運行兩個版本並收集指標。

若要部署示範 A/B 測試所需的第二個前端版本,請執行下列命令:

$ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml
deployment.extensions/sa-frontend-green created

綠色版本的部署清單有兩個地方不同:

  1. 該圖像基於不同的標籤 - istio-green,
  2. Pod 有標籤 version: green.

由於兩個部署都有標籤 app: sa-frontend,由虛擬服務路由的請求 sa-external-services 用於服務 sa-frontend,將被重定向到其所有實例,並且負載將通過 循環演算法,這會導致以下情況:

回到 Istio 的微服務。 第2部分
找不到所要求的文件

找不到這些文件,因為它們在不同版本的應用程式中的命名不同。 讓我們確定一下:

$ curl --silent http://$EXTERNAL_IP/ | tr '"' 'n' | grep main
/static/css/main.c7071b22.css
/static/js/main.059f8e9c.js
$ curl --silent http://$EXTERNAL_IP/ | tr '"' 'n' | grep main
/static/css/main.f87cd8c9.css
/static/js/main.f7659dbb.js

這意味著 index.html請求一個版本的靜態文件,負載平衡器可以將其發送到具有不同版本的 Pod,而由於顯而易見的原因,這些文件不存在。 因此,為了讓應用程式正常運作,我們需要設定一個限制:“為index.html提供服務的應用程式的相同版本應該為後續請求提供服務“。

我們將透過一致的基於哈希的負載平衡來實現這一目標 (一致哈希負載平衡)... 在這種情況下 來自同一客戶端的請求會傳送到同一後端實例,使用預先定義的屬性 - 例如 HTTP 標頭。 使用 DestinationRules 實作。

目的地規則

虛擬服務 向所需服務發送請求,使用 DestinationRules 我們可以定義將套用於發送到該服務實例的流量的策略:

回到 Istio 的微服務。 第2部分
使用 Istio 資源進行流量管理

注意:這裡以易於理解的方式呈現了 Istio 資源對網路流量的影響。 確切地說,將請求傳送到哪個實例是由 CRD 中配置的 Ingress Gateway 中的 Envoy 決定的。

透過目標規則,我們可以配置負載平衡以使用一致的雜湊值並確保相同的服務實例回應相同的使用者。 以下配置可讓您實現此目的(目的地規則-sa-frontend.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: sa-frontend
spec:
  host: sa-frontend
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpHeaderName: version   # 1

1 - 將根據 HTTP 標頭的內容產生哈希值 version.

使用以下命令應用程式配置:

$ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml
destinationrule.networking.istio.io/sa-frontend created

現在運行下面的命令並確保在指定標頭時獲得正確的文件 version:

$ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' 'n' | grep main

注意:要在 header 中新增不同的值並直接在瀏覽器中測試結果,可以使用 這個擴展 至 Chrome (或者 有了這個 對於 Firefox - 大約。 譯).

一般來說,DestinationRules 在負載平衡方面具有更多功能 - 查看詳細信息 官方文檔.

在進一步研究VirtualService之前,我們先透過執行以下命令來刪除「綠色版」應用程式以及對應的流向規則:

$ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml
deployment.extensions “sa-frontend-green” deleted
$ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml
destinationrule.networking.istio.io “sa-frontend” deleted

鏡像:實踐中的虛擬服務

遮蔽 (「屏蔽」) 或鏡像 (“鏡像”) 用於我們想要在不影響最終用戶的情況下測試生產中的變更的情況:為此,我們將請求複製(「鏡像」)到已進行所需變更的第二個實例,並查看結果。 簡而言之,這是當你的同事選擇最關鍵的問題並以如此巨大的污垢形式提出拉取請求時,沒有人可以真正審查它。

為了測試這個場景的實際效果,讓我們建立第二個帶有錯誤的 SA-Logic 實例(buggy)透過執行以下命令:

$ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml
deployment.extensions/sa-logic-buggy created

現在讓我們運行命令以確保所有實例 app=sa-logic 它們也有相應版本的標籤:

$ kubectl get pods -l app=sa-logic --show-labels
NAME                              READY   LABELS
sa-logic-568498cb4d-2sjwj         2/2     app=sa-logic,version=v1
sa-logic-568498cb4d-p4f8c         2/2     app=sa-logic,version=v1
sa-logic-buggy-76dff55847-2fl66   2/2     app=sa-logic,version=v2
sa-logic-buggy-76dff55847-kx8zz   2/2     app=sa-logic,version=v2

服務 sa-logic 定位有標籤的 pod app=sa-logic,因此所有請求將分佈在所有實例之間:

回到 Istio 的微服務。 第2部分

……但我們希望請求傳送到 v1 實例並鏡像到 v2 實例:

回到 Istio 的微服務。 第2部分

我們將透過 VirtualService 與 DestinationRule 結合來實現這一點,其中規則將確定 VirtualService 的子集以及到特定子集的路由。

在目標規則中定義子集

子集 (子集) 由以下配置決定(sa-logic-subsets-destinationrule.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: sa-logic
spec:
  host: sa-logic    # 1
  subsets:
  - name: v1        # 2
    labels:
      version: v1   # 3
  - name: v2
    labels:
      version: v2

  1. 主持人 (host) 定義此規則僅適用於路由指向服務的情況 sa-logic;
  2. 標題(name) 路由到子集實例時使用子集;
  3. 標籤 (label) 定義實例必須匹配才能成為子集一部分的鍵值對。

使用以下命令應用程式配置:

$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml
destinationrule.networking.istio.io/sa-logic created

現在已經定義了子集,我們可以繼續並配置 VirtualService 以將規則套用至 sa-logic 的請求,以便它們:

  1. 路由到子集 v1,
  2. 鏡像到子集 v2.

以下宣言可協助您實現您的計劃(sa-logic-subsets-shadowing-vs.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sa-logic
spec:
  hosts:
    - sa-logic          
  http:
  - route:
    - destination:
        host: sa-logic  
        subset: v1      
    mirror:             
      host: sa-logic     
      subset: v2

這裡不需要解釋,所以讓我們看看它的實際效果:

$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml
virtualservice.networking.istio.io/sa-logic created

讓我們透過呼叫以下命令來新增負載:

$ while true; do curl -v http://$EXTERNAL_IP/sentiment 
    -H "Content-type: application/json" 
    -d '{"sentence": "I love yogobella"}'; 
    sleep .8; done

我們來看看 Grafana 中的結果,可以看到有 bug 的版本(buggy)導致約 60% 的請求失敗,但這些失敗都不會影響最終用戶,因為它們是由正在運行的服務回應的。

回到 Istio 的微服務。 第2部分
sa-logic服務不同版本的成功回應

這裡我們首先看到 VirtualService 是如何應用在我們服務的 Envoy 上的: sa-web-app 提出請求 sa-logic,它透過 sidecar Envoy,它透過 VirtualService 配置為將請求路由到 v1 子集,並將請求鏡像到服務的 v2 子集 sa-logic.

我知道,您可能已經認為虛擬服務很簡單。 在下一節中,我們將對此進行擴展,並說它們也確實很棒。

金絲雀推出

金絲雀部署是向少數用戶推出應用程式新版本的過程。 它用於確保版本中沒有問題,並且只有在對其(版本)品質充滿信心之後,才將其分發給其他用戶。о更多的觀眾。

為了展示金絲雀推出,我們將繼續與一個子集合作 buggy у sa-logic.

我們不要在瑣事上浪費時間,立即將 20% 的用戶發送到有 bug 的版本(這將代表我們的金絲雀部署),其餘 80% 的用戶發送到正常服務。 為此,請使用以下 VirtualService (sa-logic-subsets-canary-vs.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sa-logic
spec:
  hosts:
    - sa-logic    
  http:
  - route: 
    - destination: 
        host: sa-logic
        subset: v1
      weight: 80         # 1
    - destination: 
        host: sa-logic
        subset: v2
      weight: 20 # 1

1 是重量 (weight),它指定將定向到收件者或收件者子集的請求的百分比。

讓我們更新先前的 VirtualService 配置 sa-logic 使用以下命令:

$ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml
virtualservice.networking.istio.io/sa-logic configured

……我們會立即看到一些請求會導致失敗:

$ while true; do 
   curl -i http://$EXTERNAL_IP/sentiment 
   -H "Content-type: application/json" 
   -d '{"sentence": "I love yogobella"}' 
   --silent -w "Time: %{time_total}s t Status: %{http_code}n" 
   -o /dev/null; sleep .1; done
Time: 0.153075s Status: 200
Time: 0.137581s Status: 200
Time: 0.139345s Status: 200
Time: 30.291806s Status: 500

VirtualServices 支援金絲雀部署:在這種情況下,我們已將問題的潛在影響範圍縮小到了 20% 的用戶群。 精彩的! 現在,在每種情況下,當我們不確定我們的程式碼時(換句話說 - 總是...),我們可以使用鏡像和金絲雀部署。

超時和重試

但錯誤並不總是出現在程式碼中。 在列表中“關於分散式計算的 8 個誤解「首先是『網路是可靠的』這個錯誤信念。 現實中的網絡 沒有 可靠,因此我們需要超時 (超時) 並重試 (重試).

為了演示,我們將繼續使用相同的問題版本 sa-logic (buggy),我們將模擬隨機故障網路的不可靠性。

讓我們的有 bug 的服務有 1/3 的機會回應時間過長,有 1/3 的機會以內部伺服器錯誤結束,還有 1/3 的機會成功返回頁面。

為了減輕此類問題的影響並讓用戶的生活更美好,我們可以:

  1. 如果服務回應時間超過 8 秒,則新增逾時,
  2. 如果請求失敗則重試。

為了實現,我們將使用以下資源定義(sa-logic-重試-超時-vs.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sa-logic
spec:
  hosts:
    - sa-logic
  http:
  - route: 
    - destination: 
        host: sa-logic
        subset: v1
      weight: 50
    - destination: 
        host: sa-logic
        subset: v2
      weight: 50
    timeout: 8s           # 1
    retries:
      attempts: 3         # 2
      perTryTimeout: 3s # 3

  1. 請求的超時時間設定為8秒;
  2. 請求重試3次;
  3. 如果反應時間超過3秒,則每次嘗試都被認為不成功。

這是一項優化,因為用戶等待的時間不會超過 8 秒,並且在失敗的情況下我們將進行 XNUMX 次新的嘗試來獲取回應,從而增加了成功回應的機會。

使用以下命令套用更新的配置:

$ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml
virtualservice.networking.istio.io/sa-logic configured

檢查 Grafana 圖表,成功回應的數量已增加:

回到 Istio 的微服務。 第2部分
添加超時和重試後成功響應統計數據的改進

在繼續下一部分之前 (或者更確切地說,到本文的下一部分,因為在這方面將不再有實際的實驗 - 大約翻譯。), 刪除 sa-logic-buggy 和 VirtualService 透過執行以下命令:

$ kubectl delete deployment sa-logic-buggy
deployment.extensions “sa-logic-buggy” deleted
$ kubectl delete virtualservice sa-logic
virtualservice.networking.istio.io “sa-logic” deleted

斷路器和艙壁圖案

我們正在討論微服務架構中的兩個重要模式,它們可以讓您實現自我恢復 (自癒) 服務。

斷路器 (“斷路器”) 用於終止傳入被認為不健康的服務實例的請求,並在客戶端請求重定向到該服務的健康實例時恢復它(這會增加成功回應的百分比)。 (註:可以找到該模式的更詳細描述,例如, 這裡.)

艙壁 (「分割」) 隔離服務故障對整個系統的影響。 例如,服務 B 發生故障,另一個服務(服務 B 的用戶端)向服務 B 發出請求,導致其耗盡執行緒池並無法為其他請求提供服務(即使它們不是來自服務 B)。 (註:可以找到該模式的更詳細描述,例如, 這裡.)

我將省略這些模式的實作細節,因為它們很容易在 官方文檔,我也很想展示身份驗證和授權,這將在本文的下一部分中討論。

譯者PS

另請閱讀我們的博客:

來源: www.habr.com

添加評論