Slide 1

Slide 1 text

2019.12.18 Wed. 1
 Tech Talk vol.2 Backend Engineer ~マイクロサービスの冪等性 ~ バッチ処理と冪等性 kaznishi

Slide 2

Slide 2 text

自己紹介
 ● kaznishi
 ● Twitter: @kaznishi1246
 ● Backend Engineer
 ● Code Payment Team
 ● 2018年11月入社
 
 15% 35% 50% 2

Slide 3

Slide 3 text

自己紹介
 ● 担当しているマイクロサービス
 ○ 加盟店精算 ○ 補助金接続 ○ 加盟店レポート ● いずれもバッチ処理がメイン!
 
 15% 35% 50% 3

Slide 4

Slide 4 text

バッチ処理の紹介
 4

Slide 5

Slide 5 text

加盟店精算の様々なバッチ処理
 5 会計 精算 決済 銀行 残高 会計データ取り込み処理 (毎日) ※会計サービスにリクエストを送って取得するのではなく、 
  会計サービスがストレージ(GCS)にファイルとして 
  吐き出したものを取り込み 


Slide 6

Slide 6 text

加盟店精算の様々なバッチ処理
 6 会計 精算 決済 銀行 残高 会計データ中間集計処理 (毎日)

Slide 7

Slide 7 text

加盟店精算の様々なバッチ処理
 7 会計 精算 決済 銀行 残高 精算金額集計(締め)処理(月2回)

Slide 8

Slide 8 text

加盟店精算の様々なバッチ処理
 8 会計 精算 決済 銀行 残高 入金指示処理(月2回)

Slide 9

Slide 9 text

バッチ処理と冪等性
 今回のテーマ 9

Slide 10

Slide 10 text

冪等性
 ● ある操作を1回実行しても、複数回実行しても、同じ結果になる
 ● 冪等性がある処理の例
 ○ 「ある変数の値を x に更新する」 ○ 何回実行しようが結果は x 
 10 process x
 x
 x


Slide 11

Slide 11 text

冪等性
 ● ある操作を1回実行しても、複数回実行しても、同じ結果になる
 ● 冪等性がない処理の例
 ○ 「ある変数の値を 現在値 + x に更新する」 ○ 実行のたびに違う値に更新される 
 11 process 初期値 + x
 初期値 + 2x
 初期値 + 3x


Slide 12

Slide 12 text

バッチ処理を冪等に作るモチベーション
 ● バッチ処理設計の重要な考慮事項の一つが「回復可能か」
 ○ 「バッチ処理の採用と設計を考えてみよう」 (https://tech.mercari.com/entry/2019/02/27/112650) より ● バッチ処理は様々な理由によって失敗する
 ● 失敗したときのリカバリー容易性は非常に大事
 ● 冪等に作ることで、原因除去後に単純なリトライで回復可能に
 
 12 recovery

Slide 13

Slide 13 text

何回実行されても大丈夫な
 バッチ処理を作る
 13

Slide 14

Slide 14 text

方針は大きく2種類
 ● 処理済み含めてやり直すパターン
 ● 一度処理したものをスキップするパターン
 14

Slide 15

Slide 15 text

処理済み含めてやり直すパターン
 ● バッチ処理が実行されるたびに全部の処理をやり直す
 ● バッチ処理の個々のステップが冪等である前提が必要
 ● 他マイクロサービス(or外部サービス)にもリクエストを送る処理の場合は リクエスト先にも冪等性が必要
 ● 条件分岐を細かく考える必要がない
 ● 再実行には時間がかかる
 15

Slide 16

Slide 16 text

一度処理したものをスキップするパターン
 ● ステータス等で条件分岐し、処理済みのものをスキップする
 ● 未処理のものだけを対象とするため、所要時間が短くて済む
 ○ (未処理かどうかを判別するステップは必要だが) ● 実装は条件分岐で複雑になりがち
 16

Slide 17

Slide 17 text

どちらで実装している?
 ● どちらのパターンも存在している
 ● 要件によって選択
 ● ステート管理が必要なものについては自ずと「一度処理したものをス キップするパターン」になるのではないかと
 ● 中間集計など単純にレコードを生成するような処理かつ、全部やり直し ても大丈夫なぐらい時間的制約が緩いものは「処理済み含めてやり直 すパターン」により実装している
 ○ もちろんレコードが重複して生成されないように適切なユニークキーを定義しておく前提 17

Slide 18

Slide 18 text

一度処理したものをスキップするパターンでの実装
 ● バッチが失敗したときに中途半端状態が生じないように実装を気をつけ る
 ● 処理の再開地点以外の状態で落ちていることがないように。DBのトラン ザクション機能などを使って防ぎましょう
 18 トランザクションの単位 
 再開地点


Slide 19

Slide 19 text

一度処理したものをスキップするパターンでの実装
 ● ステップの中に他サービスへのリクエスト処理が含まれている場合はど うすればいいか?
 ○ 他サービスにリクエストを送ったあとにリクエスト済みステータスに DB更新するようなケースを想定 ○ DB更新でエラーが発生したら? ○ 他サービスにキャンセルリクエストを送る? ○ 他サービスが冪等に作られているならば、もう一度同じリクエストを 送るのは問題ないと考え、キャンセルせずにそのままリトライして解 消する 19

Slide 20

Slide 20 text

その他の取り組み
 20

Slide 21

Slide 21 text

1. バッチを回す前の確認
 ● バッチ処理が処理する材料データは揃っているか?
 ● 前段バッチが異常なく終了していることを確認しよう
 ● バッチ履歴管理テーブルを作り、正常に終了したことを記録
 ● 後段のバッチ起動時に前段が終わっているかの確認を行っている
 21

Slide 22

Slide 22 text

1. バッチを回す前の確認
 ● 前段の処理が別のマイクロサービスの場合は難しい
 ● チーム間でどうやって前段の処理を知らせるか調整が必要
 ● 加盟店精算の会計データ取り込み処理の場合
 ○ 前段は会計システムのGCSへのデータエクスポート処理 ○ エクスポート処理終了時に指定名(export.done)の空ファイルを設 置してもらっている ○ データ取り込み処理開始時にexport.doneが存在していない場合 はまだ前段が終わっていないとみなす 22

Slide 23

Slide 23 text

2. バッチが複数回処理された想定のテストを書く
 ● 作ったバッチ処理、冪等になっていますか?
 ● 下記のようなテストコードを書いて保証
 ○ 正常にバッチが回った状態に再度バッチ処理を実行する ○ 途中でバッチがコケた状態に再度バッチ処理を実行する 23

Slide 24

Slide 24 text

まとめ
 24

Slide 25

Slide 25 text

まとめ
 ● 回復可能性を高めるためにバッチ処理を冪等に作ろう ● 何回バッチを実行しても結果が変わらないように処理を作る ● 処理済み含めてやり直す or 処理済みのものをスキップするように作る ● 中途半端状態を作らないように設計しよう ● 前段のバッチ処理が成功しているかを確認しよう ● テストコードで冪等になっていることを保証しよう 25