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
バッチ処理をパイプラインパターンで上手くやる
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
Package Management Learnings from Homebrew
mikemcquaid
0
230
開発者から情シスまで - 多様なユーザー層に届けるAPI提供戦略 / Postman API Night Okinawa 2026 Winter
tasshi
0
210
IFSによる形状設計/デモシーンの魅力 @ 慶應大学SFC
gam0022
1
310
CSC307 Lecture 09
javiergs
PRO
1
840
Gemini for developers
meteatamel
0
100
疑似コードによるプロンプト記述、どのくらい正確に実行される?
kokuyouwind
0
390
登壇資料を作る時に意識していること #登壇資料_findy
konifar
4
1.7k
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
6.1k
Raku Raku Notion 20260128
hareyakayuruyaka
0
370
16年目のピクシブ百科事典を支える最新の技術基盤 / The Modern Tech Stack Powering Pixiv Encyclopedia in its 16th Year
ahuglajbclajep
5
1k
CSC307 Lecture 07
javiergs
PRO
1
560
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
7
2.8k
Featured
See All Featured
Why Our Code Smells
bkeepers
PRO
340
58k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.9k
How to Think Like a Performance Engineer
csswizardry
28
2.5k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
290
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Optimising Largest Contentful Paint
csswizardry
37
3.6k
Building an army of robots
kneath
306
46k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.4k
Testing 201, or: Great Expectations
jmmastey
46
8.1k
Git: the NoSQL Database
bkeepers
PRO
432
66k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
180
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
130
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… • 今ここで話すために並行処理の勉強をしたけどまだ氷山の一角に過ぎないと感じ た。これからも備えていきたい。 • 懇親会では是非声をかけてください。