続・Web系の自分が想像と障害で学んだバッチ処理・設計の基本

バッチ処理というのがそれ単体で勉強するのが難しく勉強しようとすると何に手を付けるべきかさっぱりわからないということは、先日のブログで述べたとおり。 自分が経験の中で得てきた知見は正しいのかどうか、世間の人に見てもらいたかったというのが書いた動機。 そして、新たな視点や指摘をゲットしてより不測の事態を考慮できている最高なバッチを作りたいという目的があったわけだ。

で、いろいろな意見をもらったのだけどその中で特に辛いと感じたのはこれ。

読んでいると 「俺達は障害でつらい思いをしてるし当然先人達も障害でつらい思いをしているはずだ。 なのに、なにゆえ未だに知識が体系化されてカジュアルに学べない上にそれを知っているだけで飯が食えるとまで言える状況なのか。 そんなの間違ってる、俺達がそれを体系化していくべきなのではないか…!」 みたいな熱めの感情が当然湧くわけだ。

ちなみにそのコメントを読んだボスの感想はこれ。

ボスは主戦場がJSの人だからね〜。

それはさておき、書くべきだった(事故った経験があるのにまとめ忘れていた)ものや抜けていた視点というのもいくつかあったので、それらについても想像力を巡らせてノウハウとしてまとめておくことにしましょう。

テクニック

実行中の進捗状況を確認できるようにする

データのインポート処理、エクスポート処理、集計処理、なんであれ時間のかかるバッチ処理というものは時に異常に時間がかかることがある。 たとえば出社したらアラートが飛んでおり日時バッチがさっぱり終わっていないことがわかったとしよう。 障害なのはわかったが遅延の状況を知りたいということがある。

軽度の遅延であり、すでに90%ほど終わっているのか。(よかった、待てば終わるのでその間に障害報告書を書こう) あるいはまだ10%しか終わっていないし1%進捗するのにO(n2)で時間がかかるようになっているのか。(残念、終わる見込みはない。ジョブをkillして対策を練るプロジェクトチームを結成しよう。 ソルジャーではないそのあたりでまごついている人に状況を説明し、障害報告書を書いてもらおう)

実行する処理のフェイズやデータ量に対して何%まで処理が進んでいるのかをログにつどつど記録しておけば、障害時にそれを元に判断を下せる。 不幸にもログがなくて判断するための材料がない場合は、モニターと上司と同僚の顔を交互に見つめて誰か声を発するのを待つぐらいしかできない。

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

実行中の進捗状況を確認できるようにする、を加えて欲しい

2016/02/18 17:18
b.hatena.ne.jp

異常データ、異常動作のアラート

バッチ処理というのはコマンド起動であれ、デーモンであれ、運用時の監視やアラート設定から漏れてしまうことが多い。 そして監視設定から抜けてしまうと、これはユーザーのインタラクションに直接紐付かない場合、誰も気が付かないまま時が過ぎてしまうことがある。 「このマイナー機能の月次処理なんですが、ここ数ヶ月レポートが更新されていないのですが」 みたいな問い合わせが来たりする。当然俺達はマヌケでありこの集計は冪等に実装されていないので直近1ヶ月の集計しかできない。障害報告書だ。

なので、異常データが来たり、異常動作が来た時は速やかにアラートメールなりなんなりで運用管理者に知らせないといけないし、 「実行されているべき時間帯にきちんと正常起動して正常終了した」ということをログから監視できるようにしたうえで、監視を設定してもらう必要がある。

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

異常動作したときのあらーとも欲しいかなぁ? どれだけ事前に網羅したつもりになっても予期せぬでーたが飛んでくるし,気づくの遅くなるとその分めんどくなるのです(ーωー;【みかん

2016/02/18 12:42
b.hatena.ne.jp

Dry Runオプションの用意

バッチ処理を実装する際は「処理対象範囲を引数で指定可能にする」ようにしたほうがよいと書いた。 では、実際に障害発生時にバッチを再実行しようという時、あなたはオペミス無しに一発で実行できるだろうか? 引数として与える対象日時を計算しているときに同僚が「障害報告書の雛形どこにある?」とか聞いてくるわけなので、当然計算はミスっている。

いざ、本番で再集計を実行しよう。という直前に、Dry Run オプションで対象処理範囲や本番データに影響を及ぼさない範囲で一部の処理を実行してオペレーションの妥当性を確認できるというのはバッチ処理にとってとっても重要なことなので余裕があれば ぜひとも実装しよう。

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

dry-runあると助かる

2016/02/18 10:15
b.hatena.ne.jp

リカバリー手順を用意する。リカバリー可能な実装にする

「可能であれば冪等に実装する」に似ているが、ちょっと意味が違う。 バッチ処理はマスタなどの重要なデータ変更に直結している部分なので、当然ながら慎重にならなければいけない部分だ。

失敗時に「マスタデータ全部壊れましたワァ。戻りませんワァ」とか言ってると、こういう場合は障害報告書だけでは済まない。 ボスがボスのボスと雁首揃えて顧客に謝罪と迅速な対応と恒久対策の約束をし、ちょっと無理な要件とかもねじ込まれて帰ってくることになる。

と、いうわけでバッチ処理の実行前にマスタ情報などを別の場所にコピーして、バッチ処理が壊れていた時にもリカバリーできるようにしておくと良い。 そして、コピーするときはコピーした時の引数や時刻情報も付与して何世代か保持しておくとより安心だ。 壊れているバッチを二回実行して、コピーに壊れたマスタ情報しか残ってなかったとかよく聞くでしょう?

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

バッチ処理、マスタ更新とかデータに直結する部分だから、実行怖い印象ある。失敗時のリカバーの方法は考えておかないと。

2016/02/18 17:09
b.hatena.ne.jp
Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

現場の経験がまとまってる / バッチ処理開始時にマテリアライズドビューでデータのスナップショットを用意しておくと良さげ

2016/02/18 11:37
b.hatena.ne.jp

開発・テスト時と本番時の環境差分を最小にしておく

これはもうバッチに限らないですね。 バッチ特有の事情としては本番では連携データの転送用ネットワークが別回線だとかいろいろ揃えようにも揃えられないみたいな話はあるんですが iptables を使うだとかいろいろなツールを駆使し、サーバーの構成からネットワークまで差分を最小にした状態でテストしたいものです。 最近はIaaSの時代になって比較的そういうのやりやすくなっていいですね。

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

障害起こった時に対応しやすいように融通効かせる設計にするとかログ出力を考えとくしかないのかな。 あとテスト環境と本番環境のディレクトリ構成は常に同じにしておくとかそういうのも大事です。環境差分怖い。

2016/02/18 12:32
b.hatena.ne.jp

ワーキングディレクトリの扱い方

バッチ処理を行うとき、ファイルシステムであれ、RDBMSであれ一時的なデータ領域が必要になる。 オーケー、 /tmp/batchTmp をワーキングディレクトリにしよう。ここを使ってくれ。 みたいなルールにすると、当然 hoge.csv がかち合うことになり、毎時バッチAとBのデータが混ざってつらいことになる。 一時ファイル名なり、一時テーブル名なりにデータが混濁しないようにぶつからない名前空間を作ってやる必要がある。 「処理対象範囲を引数で指定可能にする」で指定したパラメータをパス名に含めてやるといいですね。 あと、一時ファイルや一時テーブルを名前がぶつからないようにしたからといって同一ディレクトリ or 同一スキーマに置くのも避けたほうが良い。 大量のテーブルやファイルがひとつの名前空間に置かれるとだいたい辛いことになるので。

ネタ元(ワーキングディレクトリの件だけ)

ちょっと消化できなかった指摘

並列実行する分散バッチなら終了判定とその集計

分散バッチはProductionでの経験がないのでちょっとまだノウハウがありません。

ネタ元

ロックファイルについて

制御ファイルのロック掴んで残りっぱなし問題は、実際よく聞くんだけどそういうケースを自動でなんとかしちゃうのもなんか怖いので良い答えを持っていない。 RDBMSに制御データも持つというのがひとつの答えなのかなぁ。

ネタ元

Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

よくあるトラブル対策としてまとまってる。あとは制御用ファイル置いとくとエラーで死んだときに残りっぱなしになる問題はあるな。

2016/02/18 11:19
b.hatena.ne.jp
Web系の自分が想像と障害で学んだバッチ処理・設計の基本 - コンポツさん

ロックファイル周りは処理が異常終了して解放されず、毎回手作業が発生するトラブルには遭遇したな。ロック解放処理を終了時のハンドラ登録する、サーバ再起動時に強制クリアする、で対応した

2016/02/18 09:11
b.hatena.ne.jp

いろいろ書いたけれど

バッチ処理は楽しい!

  • 事前条件と事後条件が明らかであり、テストがしやすい。
  • クソみたいに長いSQLを書いて障害を起こして、それを別のクソみたいに長いSQLに書き換えて数百倍のパフォーマンスを得るという最高の体験ができる。
  • 大量のデータを扱うことが多いので、単純にワクワクするし、レポート画面がとか出ると価値っぽいものを感じる。
  • 実装しているとインクレディブル・マシーンを思い出す。

つまり、障害を起こさないバッチ処理がかければ最高なんだ。 バッチ処理の知見を体系的にまとめて最高の人生を送ろう。