Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.2k
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
590
AHC070解法紹介
eijirou
0
140
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
280
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
230
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
420
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
320
AWSに止められる覚悟してますか?
morizo_1984
2
480
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
130
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
110
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
360
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
720
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
290
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
3.1k
Side Projects
sachag
456
43k
Accessibility Awareness
sabderemane
1
220
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
590
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
290
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
310
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