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
yusuke misawa
September 17, 2019
Programming
2
1.2k
バッチ処理をパイプラインパターンで上手くやる
yusuke misawa
September 17, 2019
Tweet
Share
More Decks by yusuke misawa
See All by yusuke misawa
KYCとは何なのか
yusukemisa
0
410
Other Decks in Programming
See All in Programming
CSC307 Lecture 05
javiergs
PRO
0
210
Polarsの成長: v0.14からv1.0までの変遷と今後の展望
zerebom
1
350
Activities at Cairo Library
cairolibrary720
0
1.2k
君たちはどうコードをレビューする (される) か / 大吉祥寺.pm
utgwkk
15
8.5k
Exploring the Gradually Lost Technical Skills in the Cloud Native Era
hwchiu
2
3.9k
CSC307 Lecture 13
javiergs
PRO
0
150
はしめてのプログラミングとロボット制御
watawatavoltage
0
290
Introduction of Happy Eyeballs Version 2 (RFC8305) to the Socket library
coe401_
1
220
Harnessing Large Language Models for Training-free Video Anomaly Detection
tereka114
1
1.3k
Prompt FlowによるLLMアプリケーション開発
yuto2000
1
1k
Trial
cairolibrary720
1
130
SRE チーム立ち上げ前に考えたこと・取り組んだこと / Considerations and Preparations Before Establishing an SRE Team
mackey0225
3
320
Featured
See All Featured
Making Projects Easy
brettharned
111
5.7k
What’s in a name? Adding method to the madness
productmarketing
PRO
21
2.9k
The Cost Of JavaScript in 2023
addyosmani
31
4.7k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
105
6.8k
StorybookのUI Testing Handbookを読んだ
zakiyama
15
4.9k
The Art of Programming - Codeland 2020
erikaheidi
48
13k
Why You Should Never Use an ORM
jnunemaker
PRO
51
8.9k
The Invisible Side of Design
smashingmag
294
50k
The Language of Interfaces
destraynor
151
23k
How to Think Like a Performance Engineer
csswizardry
4
590
Building Flexible Design Systems
yeseniaperezcruz
323
37k
The Power of CSS Pseudo Elements
geoffreycrofte
64
5.2k
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… • 今ここで話すために並行処理の勉強をしたけどまだ氷山の一角に過ぎないと感じ た。これからも備えていきたい。 • 懇親会では是非声をかけてください。