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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
typoなんかねぇよ
raspython3
0
680
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
120
一参加者から『中の人』へ 〜全通PHPerがブースに立って学んだ、カンファレンスを100倍楽しむコツ〜
wp_daisuke
0
140
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
270
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
660
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
120
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
4
1.1k
業務時間外もAIに働いてもらう話
colorful12
3
10k
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
0
150
Press start. Python's next generation.
willingc
PRO
3
320
Hello, Hiroshima Geospatial Data! — Exploring DoboX with Python
ra0kley
0
180
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
My Coaching Mixtape
mlcsv
0
310
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
400
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
230
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
690
Visualization
eitanlees
152
17k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
67
58k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
260
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
320
Building Adaptive Systems
keathley
44
3.2k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
990
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