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
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.7k
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
200
関数型プログラミングのメリットって何だろう?
wanko_it
0
140
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
170
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
140
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
140
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
1
230
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
2.3k
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
450
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
340
Vite+ Unified Toolchain for the Web
naokihaba
0
690
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
830
Featured
See All Featured
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
270
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
460
Why Our Code Smells
bkeepers
PRO
340
58k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
250
GitHub's CSS Performance
jonrohan
1033
470k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Deep Space Network (abreviated)
tonyrice
0
220
Prompt Engineering for Job Search
mfonobong
0
370
How to train your dragon (web standard)
notwaldorf
97
6.7k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
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