咱們如何在Linkerd 2.2裏設計重試

圖片描述
做者:Alex Leonglinux

重試是處理分佈式系統中的部分或瞬態故障的基本機制。但重試也多是危險的,若是作得很差,他們能夠迅速將一個小錯誤升級爲系統範圍的中斷。在這篇文章中,咱們描述了咱們如何在Linkerd 2.2裏設計重試,使Linkerd可以在最小化風險的同時,自動提升系統可靠性。git

將路由標記爲可重試

在Linkerd 2.2裏,咱們引入了重試,就是Linkerd可以自動重試失敗的請求。這使Linkerd可以自動處理服務中的部分或瞬態故障,而無需應用程序知道:若是請求失敗,Linkerd能夠再次嘗試!結合Linkerd的請求級負載平衡,這容許Linkerd處理各個pod的故障。github

在Linkerd裏,您將重試指定爲服務配置文件的一部分(在以前的博客文章中介紹)。將路由標記爲可重試就像添加isRetryable同樣簡單:設定true到相應的服務配置文件條目:json

- name: HEAD /authors/{id}.json
    condition:
      method: HEAD
      pathRegex: /authors/[^/]*\\.json
    isRetryable: true

固然,在向路由添加劇試行爲以前,應該確保路由是冪等的(idempotent)。換句話說,對具備相同參數的相同路由的屢次調用將沒有不良影響。這很重要,由於重試(根據定義!)可能致使將同一請求的多個副本發送到服務。若是請求作了非冪等的(non-idempotent)事情,例如從您的銀行賬戶中減去一美圓,您可能不但願它自動重試。api

啓用後,重試有兩個重要參數:預算(budget)和超時(timeout)。讓咱們依次考慮這兩個方面。瀏覽器

使用重試預算

將路由標記爲可重試後,Linkerd容許您爲服務配置重試預算。Linkerd附帶了合理的默認值,但若是您想自定義預算,能夠在服務配置文件中進行設置:服務器

retryBudget:
  # The retryRatio is the maximum ratio of retries requests to original
  # requests.  A retryRatio of 0.2 means that retries may add at most an
  # additional 20% to the request load.
  retryRatio: 0.2

  # This is an allowance of retries per second in addition to those allowed
  # by the retryRatio.  This allows retries to be performed, when the request
  # rate is very low.
  minRetriesPerSecond: 10

  # This duration indicates for how long requests should be considered for the
  # purposes of calculating the retryRatio.  A higher value considers a larger
  # window and therefore allows burstier retries.
  ttl: 10s

Linkerd使用重試預算,較使用最大重試次數配置重試的常規作法,是更好替代方法。咱們花一點時間來理解爲何。網絡

爲何預算而不是最大重試次數?

首先,一些背景。配置重試的最經常使用方法,是指定在放棄以前執行的最大重試次數。對於使用網絡瀏覽器的任何人來講,這是一個熟悉的想法:您嘗試加載網頁,若是沒有加載,則再試一次。若是仍然沒法加載,則第三次嘗試。最後您放棄了。app

不幸的是,以這種方式配置重試至少有兩個問題:curl

選擇最大重試次數是猜謎遊戲。您須要選擇一個足夠高的數字,以便在出現某種故障時發揮做用,但不要過高,以致於當系統真正失敗時會在系統上產生額外負載。在實踐中,您一般會從帽子中選擇最大重試次數(例如3),並但願得到最佳效果。

以這種方式配置的系統易受重試風暴的影響。當一個服務開始出現大於正常的故障率時,重試風暴開始。這會致使其客戶端重試這些失敗的請求。重試帶來的額外負載,會致使服務進一步減速,並使更多請求失敗,從而觸發更多重試。若是每一個客戶端配置爲最多重試3次,則能夠將發送的請求數量翻兩番!更糟糕的是,若是任何客戶端的客戶端配置了重試,則重試次數會成倍增長,而且能夠將少許錯誤轉化爲自我形成的拒絕服務攻擊。

爲了不這些問題,Linkerd使用重試預算。Linkerd不是爲每一個請求指定固定的最大重試次數,而是跟蹤常規請求和重試之間的比率,並將此數字保持在限制之下。例如,您能夠指定要重試最多添加20%的請求。而後,Linkerd將盡量多地重試,同時保持該比率。

所以,使用重試預算能夠明確在提升成功率和額外負載之間進行權衡。您的重試預算正是您的系統願意從重試中接受的額外負載。

(最後,Linkerd的重試預算還包括容許的最小重試次數,這將是惟一容許的,與比率無關。這使得Linkerd能夠在很是低的流量系統中重試。)

設置每一個請求的超時

除了預算以外,重試還按每一個請求的超時參數。超時可確保始終失敗的請求最終會返回響應,即便該響應失敗也是如此。超時時,Linkerd將取消請求並返回HTTP 504響應。

與重試預算相似,重試超時具備可在服務配置文件中覆蓋的合理默認值:

- name: HEAD /authors/{id}.json
    condition:
      method: HEAD
      pathRegex: /authors/[^/]*\\.json
    timeout: 50ms

誰管有重試行爲?客戶端仍是服務器?

您可能已經注意到上面的配置片斷中的有趣內容。在「傳統」重試系統(例如Web瀏覽器)中,是在客戶端上配置重試行爲,畢竟,這是重試實際發生的地方。可是在上面的服務配置文件中,咱們將在服務器端指定重試政策。

可以將政策附加到服務器端,但客戶端必須遵照該政策,這是Linkerd服務配置文件方法的基本優點之一。重試配置在邏輯上屬於服務級別(「這是您應該和我說話的方式」)。因爲Linkerd控制客戶端和服務器行爲,咱們能夠正確的方式執行此操做:服務配置文件容許服務準確發佈「這是我但願您與我交談的方式」,經過Linkerd的全部流量,不管來源如何,會尊重這種行爲。太酷了!

把它們放在一塊兒

咱們已經展現瞭如何經過組合超時、預算和可重試性來配置Linkerd的重試行爲。如今讓咱們將它們放在一塊兒進行簡短的演示。若是您有一個終端窗口和一個Kubernetes集羣,您能夠在家裏跟隨。

咱們首先安裝Linkerd和咱們的樣本書應用程序:

$ linkerd install | kubectl apply -f -
$ curl https://run.linkerd.io/bookapp.yml | linkerd inject - | kubectl apply -f -
$ linkerd check

關於這個應用程序,咱們能夠注意到的一件事是,從書籍服務到做者服務的請求的成功率很是低:

$ linkerd routes deploy/books --to svc/authors
ROUTE       SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
[DEFAULT]   authors    54.24%   3.9rps           5ms          14ms          19ms

爲了更好地瞭解這裏發生了什麼,讓咱們爲做者服務添加一個服務配置文件,從Swagger定義生成:

$ curl https://run.linkerd.io/booksapp/authors.swagger | linkerd profile --open-api - authors | kubectl apply -f  -
$ linkerd routes deploy/books --to svc/authors
ROUTE                       SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /authors/{id}.json   authors     0.00%   0.0rps           0ms           0ms           0ms
GET /authors.json           authors     0.00%   0.0rps           0ms           0ms           0ms
GET /authors/{id}.json      authors     0.00%   0.0rps           0ms           0ms           0ms
HEAD /authors/{id}.json     authors    50.85%   3.9rps           5ms          10ms          17ms
POST /authors.json          authors     0.00%   0.0rps           0ms           0ms           0ms
[DEFAULT]                   authors     0.00%   0.0rps           0ms           0ms           0ms

有一件事是清楚的,從書籍到做者的全部請求都是針對HEAD /authors/{id}.json路線,這些請求在大約50%的時間內失敗。爲了糾正這個問題,讓咱們編輯做者服務配置文件,並使這些請求能夠重試:

$ kubectl edit sp/authors.default.svc.cluster.local
[...]
  - condition:
      method: HEAD
      pathRegex: /authors/[^/]*\\.json
    name: HEAD /authors/{id}.json
    isRetryable: true ### ADD THIS LINE ###

在編輯服務配置文件後,咱們看到成功率幾乎當即有所改善:

$ linkerd routes deploy/books --to svc/authors -o wide
ROUTE                       SERVICE   EFFECTIVE_SUCCESS   EFFECTIVE_RPS   ACTUAL_SUCCESS   ACTUAL_RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /authors/{id}.json   authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
GET /authors.json           authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
GET /authors/{id}.json      authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
HEAD /authors/{id}.json     authors             100.00%          2.8rps           58.45%       4.7rps           7ms          25ms          37ms
POST /authors.json          authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
[DEFAULT]                   authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms

成功率看起來很好,但p95和p99延遲有所增長。這是能夠預料到的,由於重試須要時間。可是,咱們能夠經過設置超時,Linkerd 2.x的另外一個新功能,在咱們願意等待的最長持續時間來限制此操做。出於本演示的目的,我將設置25ms的超時。您的結果將根據系統的特性而有所不一樣。

$ kubectl edit sp/authors.default.svc.cluster.local
[...]
  - condition:
      method: HEAD
      pathRegex: /authors/[^/]*\\.json
    isRetryable: true
    name: HEAD /authors/{id}.json
    timeout: 25ms ### ADD THIS LINE ###

咱們如今看到成功率略有降低,由於有些請求超時,但尾部延遲已大大減小:

$ linkerd routes deploy/books --to svc/authors -o wide
ROUTE                       SERVICE   EFFECTIVE_SUCCESS   EFFECTIVE_RPS   ACTUAL_SUCCESS   ACTUAL_RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /authors/{id}.json   authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
GET /authors.json           authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
GET /authors/{id}.json      authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
HEAD /authors/{id}.json     authors              97.73%          2.9rps           49.71%       5.8rps           9ms          25ms          29ms
POST /authors.json          authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms
[DEFAULT]                   authors               0.00%          0.0rps            0.00%       0.0rps           0ms           0ms           0ms

請注意,因爲直方圖分段工件,p99延遲彷佛大於咱們的25ms超時。

總結

在這篇文章中,咱們描述了Linkerd如何以最小化系統風險的方式自動重試請求。咱們描述了爲何在服務器,而不是客戶端級別,指定了重試行爲,咱們向您介紹瞭如何在演示應用程序中部署服務的重試和超時功能。

重試是Linkerd可靠性路線圖中的一大進步。服務配置文件、重試和診斷的交集是Linkerd特別使人興奮的領域,您能夠期待將來版本中更酷的功能。敬請期待!

喜歡這篇文章?Linkerd是一個社區項目,由CNCF託管。若是您有功能請求、問題或評論,咱們很樂意讓您加入咱們快速發展的社區!Linkerd的倉庫在GitHub上,咱們在Slack、Twitter和郵件列表上擁有一個蓬勃發展的社區。快來加入吧!


KubeCon + CloudNativeCon和Open Source Summit大會日期:

  • 會議日程通告日期:2019 年 4 月 10 日
  • 會議活動舉辦日期:2019 年 6 月 24 至 26 日

KubeCon + CloudNativeCon和Open Source Summit贊助方案
KubeCon + CloudNativeCon和Open Source Summit多元化獎學金現正接受申請
KubeCon + CloudNativeCon和Open Source Summit即將首次合體落地中國

相關文章
相關標籤/搜索