Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
バッチ処理をパイプラインパターンで上手くやる
Search
yusuke misawa
September 17, 2019
Programming
2
1.5k
バッチ処理をパイプラインパターンで上手くやる
yusuke misawa
September 17, 2019
Tweet
Share
More Decks by yusuke misawa
See All by yusuke misawa
KYCとは何なのか
yusukemisa
0
470
Other Decks in Programming
See All in Programming
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
2
690
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
350
著者と進める!『AIと個人開発したくなったらまずCursorで要件定義だ!』
yasunacoffee
0
130
Context is King? 〜Verifiability時代とコンテキスト設計 / Beyond "Context is King"
rkaga
9
1.1k
堅牢なフロントエンドテスト基盤を構築するために行った取り組み
shogo4131
8
2.3k
TypeScriptで設計する 堅牢さとUXを両立した非同期ワークフローの実現
moeka__c
6
3k
WebRTC、 綺麗に見るか滑らかに見るか
sublimer
1
160
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
170
從冷知識到漏洞,你不懂的 Web,駭客懂 - Huli @ WebConf Taiwan 2025
aszx87410
2
2.3k
Go コードベースの構成と AI コンテキスト定義
andpad
0
120
なあ兄弟、 余白の意味を考えてから UI実装してくれ!
ktcryomm
11
11k
Flutter On-device AI로 완성하는 오프라인 앱, 박제창 @DevFest INCHEON 2025
itsmedreamwalker
1
100
Featured
See All Featured
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
Designing for Performance
lara
610
69k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
253
22k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.2k
How to Ace a Technical Interview
jacobian
280
24k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.3k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
Designing for humans not robots
tammielis
254
26k
The Cult of Friendly URLs
andyhume
79
6.7k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
Unsuck your backbone
ammeep
671
58k
Transcript
バッチ処理をパイプライン パターンで上手くやる Yusuke Misawa MediaDo.go@2019/09/17
Yusuke Misawa(三澤 悠介) • 決済系の自社サービスの会社 バックエンドエンジニア • 仕事でGoを使うようになって1年 • Goで個人情報周りの
マイクロサービス開発 • 趣味:ボルダリング♂ • Twitter: https://twitter.com/FpmpAmpm
話の流れ • なにかとバッチ処理を作る機会があるという話 • バッチ処理作成時の課題がいろいろあるよねという話 • パイプラインパターンでうまくやろうという話 ◦ パイプラインとはステージと呼ばれるデータ操作の組み合わせのパターン ◦
ステージをうまくやるためのパターン(ファンアウト・ファンイン・キャンセル) • パイプラインを使えばうまく作れそうだが残る課題として ◦ ゴルーチンがリークしないようにする話 ◦ チャネルのブロックと panicを防ぐ話 • まとめ
なにかとバッチ処理を作る機会がある • ユーザーデータの不整合を解消したい • 非同期で動くイベント送信が失敗したので再送したい (なお自動でリカバリーする仕組みはない) • ユーザーが個人情報の削除を要請してきた • 追加機能開発で増えたDBカラムの既存レコード分のデータ作成
• とにかくいろいろある
なにかとバッチ処理を作る機会がある • 組織・チーム体制にもよるけど前職だと関わっていたサービスの規模が大きく専業 のバッチチームやインフラチームがあった。 • なので個人的には最近まであまりバッチ処理を作る機会はあまりなかった • マイクロサービス構成だと各サービスの開発者がなんとかするしかない。
バッチ処理作成時の課題 • 処理量が多いので並行処理しようとするが複雑化 • 動きそうだがオレオレ実装で可読性が悪くレビューもし辛い • できれば再利用・拡張性あるものにしたい • ゴルーチンがうまく扱えているか不安 •
チャネルがうまく扱えているか不安 →コードの見通しが良く拡張性があり 安全でいい感じの実装方式があれば真似したい
「Goで並行処理するときにはパ ターンがあったな・・・」
並行処理のパターンに関する情報源 • The Go Blog:Go Concurrency Patterns: Pipelines and cancellation
◦ https://blog.golang.org/pipelines • 書籍「Go言語による並行処理」 ◦ オライリージャパン ◦ Katherine Cox-Buday 著、山口 能迪 訳 ◦ 原書: Concurrency in Go ◦ https://www.oreilly.co.jp/books/9784873118468/
• 入力を受け取り何らかの一連の操作(ステージと呼ぶ)を行い出力する この組み合わせをパイプラインと呼ぶ(Go特有の概念ではない) パイプラインと呼ばれる考え方 ステージ1 ステージ2 ステージ3 入力 出力
• Goで実装する場合ステージ間はチャネルでデータを共有する パイプラインと呼ばれる考え方 ステージ1 ステージ2 ステージ3 入力 出力 データを渡すチャネルを作りステージ 2に
渡し、入力をチャネルに流す データ受信チャネルを引数に持ち、そこ から入力を受信後データ操作を行う
• 各ステージは独立して修正や入れ替えが可能 ステージをファンアウト・ファンインにすることで 並行処理とその結果の集約もできる。 コードの見通しはよくなりそう。 パイプラインと呼ばれる考え方 ステージ1 ステージ2 ステージ3 入力
出力
• ステージ1で出力されたデータを複数のステージ2で処理 複数のゴルーチンでステージ2を行う ファンアウト ステージ1 ステージ2 ステージ3 入力 出力
• ステージ2で別々に出力されたデータをステージ3で集約 ファンインで結果の集約 ステージ1 ステージ2 ステージ3 入力 出力
パイプライン全体の擬似コード // ステージ1(ctx以下は入力) in := gen(ctx, 1,2,3,4,5) //genは受信専用チャネルinを返す // ステージ2
(ファンアウト) c1 := sq(ctx,in) // 何らかの操作を並行実行 c2 := sq(ctx,in) // c1,c2は実行結果の受信専用チャネル // ステージ3(ファンイン) for n := range merge(ctx,c1, c2) { // mergeもc1,c2をまとめた受信専用チャネルを返す fmt.Println(n) }
ファンインで複数のチャネルをまとめる 引数のチャネル個数分それぞれデータを取り出し返却済のチャネル に送信する データ集約先のチャネルは先に返却
バッチ処理作成時の課題(再掲) • 処理量が多いので並行処理しようとするが複雑化 ◦ ◎パイプラインで見通し良さそう • 動きそうだがオレオレ実装で可読性が悪くレビューもし辛い ◦ ◎パイプラインの考え方が共有されていれば話が早そうだしコードの見通し良さそう。 •
できれば再利用・拡張性あるものにしたい ◦ ◎パイプラインで拡張性良さそう • ゴルーチンがうまく扱えているか不安 ◦ パイプラインのステージ内の実装による • チャネルがうまく扱えているか不安 ◦ パイプラインのステージ内の実装による
ゴルーチンのリークが起きないようにしたい • リーク(=漏れ) ◦ 情報のリーク:関係者がマスコミに秘密を漏らしちゃう • ゴルーチンのリーク ◦ 非メインのゴルーチンが終了せず残り続けること。 ◦
ガベージコレクションで回収されずその分メモリを圧迫する。 ◦ バッチ処理の場合どこかでプロセスが終わるので永遠に増え続けることはな いが意図しないリークは避けたい。
ゴルーチンのリーク例 https://play.golang.org/p/_YJcrlApJRq
コンテキストキャンセルで解決 https://play.golang.org/p/U18DkwkN0SO メインゴルーチンのdefer cancel()が伝播してctx.Doneがcloseされこ ちらのゴルーチンも終了する。
パイプラインでチャネルをうまく扱う • panicが起きる条件を知る ◦ closedチャネルへの送信(https://play.golang.org/p/puTTlBWgSTh) ◦ closedチャネルのclose ◦ nilチャネルのclose •
意図せずブロックしないようにする ◦ nilチャネルの読み書きをしない(https://play.golang.org/p/jCnURn3qaiU ) ◦ 所有権(誰が初期化するか、送受信の制限)を決める
チャネルのpanicを回避するパターン defer でcloseして二重にcloseを防ぎ、初期化 スコープでやることで nilチャネルのcloseを防ぐ 初期化したスコープでのみ送信する チャネルは初期化して受信専用で返却する(外 部で勝手に書き込ませない)
チャネルのブロックを回避するパターン • 作成者(ジェネレーター) ◦ パイプラインに流すデータのチャネルの作成、初期化し返却 ◦ 並行してデータ送信、チャネルのclose • 消費者(コンシューマー) ◦
ジェネレーターから受け取ったチャネルからデータ受信 ◦ もちろん必要な業務上の処理をやる
バッチ処理作成時の課題(再々掲) • 処理量が多いので並行処理しようとするが複雑化 ◦ ◎パイプラインで見通し良さそう • 動きそうだがオレオレ実装で可読性が悪くレビューもし辛い ◦ ◎パイプラインの考え方が共有されていれば話が早そうだしコードの見通し良さそう。 •
できれば再利用・拡張性あるものにしたい ◦ ◎パイプラインで拡張性良さそう • ゴルーチンがうまく扱えているか不安 ◦ ◎コンテキストで処理終了を伝えゴルーチンのリークを回避 • チャネルがうまく扱えているか不安 ◦ ◎チャネルの作成者と消費者で役割分担し不要なブロックや panicを回避
パイプラインまとめ ステージ1 ステージ2 ステージ3 入力 出力 • パイプラインは入力を受け取りステージと呼ばれる独立したデータ操作の組み合わせるパターン • ステージの組み合わせで柔軟に処理の分割、並行実行が可能になる。
◦ ステージ同士はチャネルでデータを受け渡しする • ステージ(個々のデータ操作を上手くやる)のためのパターン ◦ ファンアウト・ファンイン(ステージ同士の連携のためのパターン) ◦ コンテキストキャンセル(ステージを安全に終了するためのパターン) ◦ ジェネレーターとコンシューマー(ステージを安全に終了するための役割分担のパターン)
最後に • バッチ処理作成時に課題と思ったいくつかのトピックは解決できた。 しかし並行処理の沼はまだまだ深い。 ◦ 競合状態 ◦ ロック ◦ エラー処理
◦ ゴルーチンのスケジューリング ◦ 並行処理の速度・律速問題 etc… • 今ここで話すために並行処理の勉強をしたけどまだ氷山の一角に過ぎないと感じ た。これからも備えていきたい。 • 懇親会では是非声をかけてください。