跳轉到

Retry 的策略

Retry in HTTP method

Method Idempotent Destructive Safe 4XX 5XX Ambiguous Purpose
GET O X O No Retry Retry Retry 取得資料
POST X X X No Retry No Retry No Retry 建立資料
PUT O O X No Retry Retry Retry 建立或編輯資料
PATCH X O X No Retry Retry Retry 編輯資料
DELETE O O X No Retry Retry Retry 刪除資料

Idempotent

冪等的,重複執行後結果仍相同

Destructive:

破壞性的,執行後會可能會造成資料的無法復原

PUT 可能為 user.name = 'Evan',PATH 可能為 user.access_count += 1,故冪等是不同的。

若為 Destructive,可使用 ETAGIf-Match 的 HTTP 表頭來確認是否重複修改,或在更改過程中,從他處已經被修改。

就如同 Memcached 的 CAS

每次 Request 中增加 idempotency key 可以用作 cache key

Circuit Breaker Pattern

多久 Retry 一次?

  • 網路斷線,可能僅造成數毫秒的 rejection
  • DB connection,可能造成數秒的 rejection
  • reboot 可能造成數分鐘的 rejection
  • rolling back 可能造成小時的 rejection

在上述的情況下,exponential backoff 就是業界的 retry 標準,例如:

  • 100ms
  • 250ms
  • 500ms
  • 1s
  • 2.5s
  • 5s
  • 5s
  • ...
  • quit

Jitter

若同時有許多 instance 要 retry connection,可能會導致同時間過多的 request 進入 server 中。

如上圖所示,這狀況就叫 thundering herd

這時在各個 instance 中增加 ±10% 內的亂數會平均分散這些請求。這種做法就叫做 jitter

let time = SCHEDULE[times] || DEFAULT;
return Math.random() * (time * 0.2) + time * 0.9;

或是增加 offset:

const PERIOD = 60_000;
const OFFSET = Math.random() * PERIOD;
setTimeout(() => {
    setInterval(() => retry(), PERIOD);
}, OFFSET);