一般的なバッチ処理とは

一般的に、バッチ処理とは「まとめて一括処理する」ことを指す。
データベースやファイルから大量のレコードを読み込み、処理し、書き出す処理であることが多い。
バッチ処理には以下の特徴があり、オンライン処理と比較して、応答性より処理スループットを優先した処理方式である。

バッチ処理の特徴
  • データを一定の量でまとめて処理する。

  • 処理に一定の順序がある。

  • スケジュールに従って実行・管理される。

次にバッチ処理を利用する主な目的を以下に示す。

スループットの向上

データをまとめて処理することで、処理のスループットを向上できる。
ファイルやデータベースは、1件ごとにデータを入出力せず、一定件数にまとめることで、I/O待ちのオーバヘッドが劇的に少なくなり効率的である。 1件ごとのI/O待ちは微々たるものでも、大量データを処理する場合はその累積が致命的な遅延となる。

応答性の確保

オンライン処理の応答性を確保するため、即時処理を行う必要がない処理をバッチ処理に切り出す。
たとえば、すぐに処理結果が必要でない場合、オンライン処理で受付まで処理を行い、裏でバッチ処理を行う構成がある。 このような処理方式は、ディレードバッチディレードオンラインなどと呼ばれる。

時間やイベントへの対応

特定の時間やイベントに応じた処理は、バッチ処理として実装することが素直と言える。
たとえば、業務要件により1ヶ月分のデータを翌月第1週の週末に集計する、システム運用ルールに則って週末日曜の午前2時に1週間分の業務データをバックアップする、などである。

外部システムとの連携上の制約

ファイルなど外部システムとのインターフェースが制約となるために、バッチ処理を利用することもある。
外部システムから送付されてきたファイルは、一定期間のデータをまとめたものになる。 これを取り込む処理は、オンライン処理よりもバッチ処理が向いている。

バッチ処理を実現するには、さまざまな技術要素を組み合わせることが一般的である。ここでは、主要な技術を紹介する。

ジョブスケジューラ

バッチ処理の1実行単位をジョブと呼ぶ。これを管理するためのミドルウェアである。
バッチシステムにおいて、ジョブが数個であることは稀であり、通常は数百、ときには数千にいたる場合もある。 そのため、ジョブの関連を定義し、実行スケジュールを管理する専用の仕組みが不可欠になる。

シェルスクリプト

ジョブを実現する方法の1つ。OSやミドルウェアなどに実装されているコマンドを組み合わせて1つの処理を実現する。
手軽に実装できる反面、複雑なビジネスロジックを記述するには不向きであるため、ファイルのコピー・バックアップ・テーブルクリアなど主にシンプルな処理に用いる。 また、別のプログラミング言語で実装した処理を実行する際に、起動前の設定や実行後の処理だけをシェルスクリプトが担うことも多い。

プログラミング言語

ジョブを実現する方法の1つ。シェルスクリプトよりも構造化されたコードを記述でき、開発生産性・メンテナンス性・品質などを確保するのに有利である。 そのため、比較的複雑なロジックになりやすいファイルやデータベースのデータを加工するようなビジネスロジックの実装によく使われる。

バッチ処理に求められる要件

業務処理を実現するために、バッチ処理に求められる要件には以下のようなものがある。

  • 性能向上

    • 一定量のデータをまとめて処理できる。

    • ジョブを並列/多重に実行できる。

  • 異常発生時のリカバリ

    • 再実行(手動/スケジュール)ができる。

    • 再処理した時に、処理済レコードのスキップして、未処理部分だけを処理できる。

  • 多様な起動方式

    • 同期実行ができる。

    • 非同期実行ができる。

      • 実行契機としては、DBポーリング、HTTPリクエスト、などがある。

  • さまざまな入出力インターフェース

    • データベース

    • ファイル

      • CSVやTSVなどの可変長

      • 固定長

      • XML

上記の要件について具体的な内容を以下に示す。

大量データを一定のリソースで効率よく処理できる(性能向上)

大量のデータをまとめて処理することで処理時間を短縮する。このとき重要なのは、 「一定のリソースで」 の部分である。
100万件でも1億件でも、一定のCPUやメモリの使用で処理でき、件数に応じて緩やかにかつリニアに処理時間が延びるのが理想である。 まとめて処理するには、一定件数ごとにトランザクションを開始・終了させ、まとめてI/O入出力しすることで、 使用するリソースを平準化させる仕組みが必要となる。
それでも処理しきれない膨大なデータを相手にする場合は、一歩進んでハードウェアリソースを限界まで使い切る仕組みも追加で必要になる。 処理対象データを件数やグループで分割して、複数プロセス・複数スレッドによって多重処理する。 さらに推し進めて複数マシンによる分散処理をすることもある。 リソースを限界まで使い切る際には、I/Oを限りなく低減することがきわめて重要になる。

可能な限り処理を継続する(異常発生時のリカバリ)

大量データを処理するにあたって、入力データが異常な場合や、システム自体に異常が発生した場合の防御策を考えておく必要がある。
大量データは必然的に処理し終わるまでに長時間かかるが、エラー発生後に復旧までの時間が長期化すると、システム運用に大きな影響を及ぼしてしまう。
たとえば、1000万件のデータを処理する場合を考える。999万件目でエラーになり、それまでの処理をすべてやり直すとしたら、 運用スケジュールに影響が出てしまうことは明白である。
このような影響を抑えるために、バッチ処理ならではの処理継続性が重要となる。これにはエラーデータをスキップしながら次のデータを処理する仕組み、 処理をリスタートする仕組み、可能な限り自動復旧を試みる仕組み、などが必要となる。また、1つのジョブを極力シンプルなつくりにし、再実行を容易にすることも重要である。

実行契機に応じて柔軟に実行できる(多様な起動方式)

時刻を契機とする場合、オンラインや外部システムとの連携を契機とした場合など、さまざまな実行契機に対応するの仕組みが必要になる。 同期実行ではジョブスケジューラから定時になったら処理を起動する、 非同期実行ではプロセスを常駐させておきイベントに応じて随時バッチ処理を行う、というような 様々な仕組みが一般的に知られている。

さまざまな入出力インターフェースを扱える(さまざまな入出力インターフェース)

オンラインや外部システムと連携するということは、データベースはもちろん、CSV/XMLといったさまざまなフォーマットのファイルを扱えることが重要となる。 さらに、それぞれの入出力形式を透過的に扱える仕組みがあると実装しやすくなり、複数フォーマットへの対応も迅速に行なえるようになる。

バッチ処理で考慮する原則と注意点

バッチ処理システムを構築する際に考慮すべき重要な原則、および、いくつかの一般的な考慮事項を示す。

  • 単一のバッチ処理は可能な限り簡素化し、複雑な論理構造を避ける。

  • 処理とデータは物理的に近い場所におく(処理を実行する場所にデータを保存する)。

  • システムリソース(特にI/O)の利用を最小限にし、できるだけインメモリで多くの操作を実行する。

  • また、不要な物理I/Oを避けるため、アプリケーションのI/O(SQLなど)を見直す。

  • 複数のジョブで同じ処理を繰り返さない。

    • たとえば、集計処理とレポート処理がある場合に、レポート処理で集計処理を再度することは避ける。

  • 常にデータの整合性に関しては最悪の事態を想定する。十分なチェックとデータの整合性を維持するために、データの検証を行う。

  • バックアップについて十分に検討する。特にシステムが年中無休で実行されている場合は、バックアップの難易度が高くなる。