Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
mercari.go #12 go-circuitbreakerのご紹介
Search
Yasuharu Goto
December 06, 2019
Programming
6.2k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
mercari.go #12 go-circuitbreakerのご紹介
mercari.go #12 の登壇資料です。
Yasuharu Goto
December 06, 2019
Other Decks in Programming
See All in Programming
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
The Bowling Game- From Imperative to Functional Programming - Part 1
philipschwarz
PRO
0
280
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
130
AIエージェントで 変わるAndroid開発環境
takahirom
1
450
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
0
1.3k
スマートグラスで並列バイブコーディング
hyshu
0
280
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
4.9k
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
1
230
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
500
なぜ関数型プログラミングで「型」と「証明」が語られるのか #fp_matsuri
kajitack
3
580
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
1.3k
Featured
See All Featured
A Tale of Four Properties
chriscoyier
163
24k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.9k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
640
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
200
Thoughts on Productivity
jonyablonski
76
5.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.3k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Bash Introduction
62gerente
615
220k
Rails Girls Zürich Keynote
gr2m
96
14k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
670
Transcript
@ono_matope go-circuitbreakerのご紹介
• Yasuharu Goto ◦ Backend Engineer ◦ 前職:ヤフー:Goでオブジェクトストレージ開発 • 株式会社メルペイ
(2019年9月1日-) ◦ ID Platformチーム所属 ◦ 認証認可Microservicesの開発 小野マトペ (ono_matope) 2
Go用 Circuit Breaker ライブラリ go-circuitbreaker を公開しました 3
https://github.com/mercari/go-circuitbreaker
Background 5
Failures in Microservices Architecture • Microservices Architecture においては、依存サービスの障害は平常状態 • 下位サービスの障害時
◦ リクエストのブロック時間が上位サービスに伝播 ◦ リトライすると下位サービスへの負荷をさらに高める悪循環 6 Microsrervice B Microsrervice C 10s Latency 10s+ Latency リトライによる 過負荷 Fail! Microsrervice A
Failures in Microservices Architecture 連鎖的な障害を防ぐため、障害サービスへのリクエストを遮断したい 7 Microsrervice C Fail! Fail
Fast Fail Fast Microsrervice B Microsrervice A
Circuit Breaker パターン Circuit Breaker = ブレーカー 外部リクエストのエラーカウンタがしきい値を超えたら Circuit Openし、しばらくは処理を省略して
即座にエラーを返す(Fail Fast)パターン ・障害時の連鎖的なレイテンシの増加を防げる ・リトライによる下位サービスの過負荷を緩和 8 External Service Success Error (1) Error (2) Error (3) Trip Circuit Open! Trip Fail!
CLOSED Circuit Breaker • CLOSED: リクエストが一定回数失敗したら OPEN に遷移 • OPEN:
一定の時間リクエストを止める (ブレーカーが落ちている状態) • HALF-OPEN: リクエストが失敗したら OPEN に戻る。一定回数成功したら CLOSED に復帰。 9 External Service HALF-OPEN OPEN CLOSED
Circuit Breaker =障害を検知して遮断するパターン
Circuit Breaker in Go 11
Circuit Breaker packages • github.com/rubyist/circuitbreaker • github.com/sony/gobreaker 12
github.com/sony/gobreaker 13 • Execute メソッドに外部呼び出し処理を渡す ◦ 戻り値 error がnil →
成功カウンタ++ ◦ 戻り値 error がnon-nil → 失敗カウンタ++ ◦ Circuit Open時 → 関数が実行されず ErrOpenState がreturn
現実はもう少し複雑 • Goの関数が返すエラーにはいろいろな種類がある ◦ 障害起因のエラー ◦ その他のエラー • Goコード上のerrorをすべて
「失敗」とみなしていいのだろうか? 14
現実の例 HTTPレスポンスボディ全体を読むコードを サーキットブレーカーで保護
リクエスト作成エラー:リクエストしてない。 無視したい
HTTPリクエスト失敗:「失敗」 リクエスト作成エラー:リクエストしてない。 無視したい
HTTPリクエスト失敗:「失敗」 HTTP 5xx系ステータス:「失敗」 リクエスト作成エラー:リクエストしてない。 無視したい
HTTPリクエスト失敗:「失敗」 HTTP 5xx系ステータス:「失敗」 HTTP 4xx系ステータス:サービス自体は生きてる。 場合によるが「成功」とみなしたい リクエスト作成エラー:リクエストしてない。 無視したい
レスポンスボディ読み込み失敗 => 「失敗」 HTTPリクエスト失敗:「失敗」 HTTP 5xx系ステータス:「失敗」 HTTP 4xx系ステータス:サービス自体は生きてる。 場合によるが「成功」とみなしたい リクエスト作成エラー:リクエストしてない。
無視したい
context ・contextを使ってユーザーがリクエストをキャ ンセルしたり、タイムアウト時間を指定したりす ると、リクエストがエラー終了する。 →障害とは無関係 ・ユーザーが発火可能。失敗として扱うとユー ザーがサーキットブレイカーを落とすことが出 来てしまう。
(gRPCではユーザーがキャンセルも タイムアウトも指定可能) https://www.irasutoya.com/2018/06/blog-post_972.html
課題 • 現実のコードには様々な error が ◦ 障害起因のerror ▪ 失敗として扱いたい ◦
障害と関係ないerror ▪ 「失敗」として扱うとFalse-Positive ▪ 「成功」として扱うとFalse-Negativeのケースも ◦ context起因のerror ▪ contexに対応した処理は、ユーザーがエラー終了させる可能性 • これらをCircuit Breakerに正しく伝えることは難しい 22
go-circuitbreaker 23 https://github.com/mercari/go-circuitbreaker
Doメソッド 24 • Doメソッドが保護対象関数とともにcontext.Context を受け取る • 基本的にはgobreakerと同じ ◦
戻り値 error が nil : 成功 ◦ 戻り値 error が non-nil : 失敗 ◦ ブレーカーが落ちたら関数は実行されずエラー
特徴1: 特定のエラーを無視・成功扱いに指定できる 25 func Ignore(err) error func MarkAsSuccess(err) error
ラップしたエラーをサーキットブレーカに 「無視」させる。無視されたエラーは失敗 にも成功にもカウントされない。 ラップしたエラーをサーキットブレーカー に「成功」としてカウントさせる。 どちらもfuncの外にはアンラップしてreturnさ れる
特徴2: context のキャンセル・タイムアウトを無視 26 • オプションで変更可能 • returnしたエラーはそのままDoの外側で受け取れる
外部リクエストのタイムアウトを失敗とみなす方法 27 • Do() の内側でcontextを派生してください。 • 内側のcontextがtimeoutしても外側はtimeoutしない→失敗としてカウント
実装上の工夫 28
29 https://docs.microsoft.com/ja-jp/azure/architecture/patterns/circuit-breaker • Circuit Breakerは成功・失敗カウンターと ク ローズ, オープン, ハーフオープン と3つの内
部状態を持つ • 単純な実装では分岐が多く複雑になる
State パターン in Go CBの内部状態 state を interface 定義。 30
type state interface { onEntry(cb *CircuitBreaker) // 状態開始時の処理 onExit(cb *CircuitBreaker) // 状態終了時の処理 onSuccess(cb *CircuitBreaker) // 成功時の処理 onFail(cb *CircuitBreaker) // 失敗時の処理 ready() bool // 処理を開始できるかの問い合わせ // ... } state.go (抜粋)
State パターン in Go CircuitBreaker は state を保持し、 特有の処理を移譲する。 (カウンタの増分は共通処理なので移譲していない)
31 func (cb *CircuitBreaker) Success() { cb.mu.Lock() defer cb.mu.Unlock() cb.cnt.incrementSuccesses() cb.state.onSuccess(cb) } func (cb *CircuitBreaker) Fail() { cb.mu.Lock() defer cb.mu.Unlock() cb.cnt.incrementFailures() cb.state.onFail(cb) } breaker.go (抜粋) type CircuitBreaker struct { state state cnt Counters // ... } breaker.go (抜粋)
state.go (抜粋) func (st *stateClosed) onEntry(cb *CircuitBreaker) { cb.cnt.resetFailures() //
... } func (st *stateClosed) onSuccess(cb *CircuitBreaker) {} func (st *stateClosed) onFail(cb *CircuitBreaker) { if cb.shouldTrip(&cb.cnt) { cb.setState(&stateOpen{}) } } 32 https://docs.microsoft.com/ja-jp/azure/architecture/patt erns/circuit-breaker Closed
func (st *stateOpen) onEntry(cb *CircuitBreaker) { // ... cb.clock.AfterFunc(timeout, cb.setStateWithLock(&stateHalfOpen{}))
} func (st *stateOpen) onSuccess(cb *CircuitBreaker) {} func (st *stateOpen) onFail(cb *CircuitBreaker) {} 33 https://docs.microsoft.com/ja-jp/azure/architecture/patterns/circuit-b reaker Open state.go (抜粋)
func (st *stateHalfOpen) onEntry(cb *CircuitBreaker) { cb.cnt.resetSuccesses() } func (st
*stateHalfOpen) onSuccess(cb *CircuitBreaker) { if cb.cnt.Successes >= cb.halfOpenMaxSuccesses { cb.setState(&stateClosed{}) } } func (st *stateHalfOpen) onFail(cb *CircuitBreaker) { cb.setState(&stateOpen{}) } 34 https://docs.microsoft.com/ja-jp/azure/architecture/patterns/circuit-b reaker Half Open state.go (抜粋)
State デザインパターン ・内部状態を型として表現 ・分岐の少ない保守性の高いコードに 35
まとめ 36
Go用Circuit Breakerを作りました 既存のアプリケーションに組み込みやすいはず 使ってみてください! 01 02 03 37
Thank you! 38
39