{%hackmd SybccZ6XD %} <style> .toc > ul > li:first-child { list-style: none; } .toc > ul > li:first-child > a { display: none; } </style> RETRY logic === ###### tags: `essay` `HTTP` > [name=Shueh Chou Lu][time=Dec 25, 2020] [TOC] --- ## 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,可使用 `ETAG` 和 `If-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 中。 ![](https://i.imgur.com/kBdS63z.png) 如上圖所示,這狀況就叫 `thundering herd`。 這時在各個 instance 中增加 ±10% 內的亂數會平均分散這些請求。這種做法就叫做 `jitter` ```javascript= let time = SCHEDULE[times] || DEFAULT; return Math.random() * (time * 0.2) + time * 0.9; ``` 或是增加 offset: ```javascript= const PERIOD = 60_000; const OFFSET = Math.random() * PERIOD; setTimeout(() => { setInterval(() => retry(), PERIOD); }, OFFSET); ```