現在プリンシプルでは、業務に関わるデータをBigQueryに転送したり、様々なシステムのログデータの記録などの目的で多くのバッチプログラムが実行されています。
1日に実行されるジョブの数は200以上に渡っています。またそのバッチの中には、高頻度で実行されるジョブであったり、短時間のあいだに複数のジョブを実行する必要のあるものも存在します。例えば、Web広告のレポートデータをAPIで取得しBigQueryに転送するバッチがあります。このバッチは、前日の数値が取得可能になってから業務が始まるまでの間にすべての広告アカウントのデータを取得する必要があるため、「短時間で一度にたくさんのジョブを実行する」必要がある性質のバッチ・プログラムです。また、自社のSalesforce(営業支援ツール; 主に商談管理で利用)のデータもBigQueryに転送しており、常に最新の商談データをTableauで見れるように、10分に1回のバッチ実行を行っており、「高頻度で実行する」ジョブの1つです。

このブログでは、そんなプリンシプルで、どのようにバッチ運用を行っているかを紹介したいと思います。

基盤となるバッチ処理プログラム

基盤となるバッチ処理のプログラムには、RubyまたはEmbulkを使い実装を行っています。Embulkのプラグインが存在し、実行速度に問題がないものについては、Embulkで処理を書きます(例: プリンシプルの過去ブログ記事「Embulkを使ってGoogle アナリティクスのデータをBigQueryに転送する方法」。一方で、Embulkのプラグインそのものが存在しないケースや、プラグインが存在しても実行速度に問題があり、実際の運用上現実的ではないものについてはRubyを使って実装を行い、最終的にRakeタスクの形でバッチを実行しています。

また、場合によってはEmbulkのプラグインそのものを開発するケースもあります。Yahooプロモーション広告のEmbulkプラグインについては、既存のものがなかったため開発を行い、Github上に公開しています(Github: https://github.com/principle-c/embulk-input-yahoo_ads/ )。

バッチ実行基盤

プリンシプルにおけるバッチの実行基盤には「Jenkins」を用いています。バッチで実行するジョブ数が少なかったころは、サーバー上でcronコマンドを使ってジョブの実行を行っていましたが、ジョブ数が増えるにしたがって、cronでの運用には限界がきていたため、実行基盤をJenkinsに移行しました。

cronでバッチの実行を行っていたころは、バッチが何らかの理由により失敗したケースでは、そのデータを利用している側の人がエンジニアに依頼し、cronの再実行を行ってもらう必要がありました。しかし、Web UIを持ったバッチ実行基盤である「Jenkins」に移行したことにより、バッチが失敗したときは、データの利用者自身がJenkinsのWeb UIからリトライすることができるようになりました。これにより、非エンジニアでも自身でジョブの再実行をすることができるようになりました。

また、バッチの実行時に、毎回最新のバッチ処理プログラムをGitから取得するようにしているため、バッチ処理プログラムに変更があっても、常に最新のプログラムが実行されるようになっています。

バッチサーバー構成

バッチサーバーは、Google CloudのCompute Engine(以下、GCE)のインスタンスを立てて運用しています。また、ここではJenkinsのマスター・スレーブ機能を有効に活用するために、1台のJenkinsマスター用インスタンスと、5台のJenkinsスレーブ用インスタンスを利用しています。

マスター用インスタンスは、JenkinsのWeb UIそのものをホスティングしたり、ある程度の数のジョブをさばけるようにスペックの高いマシンを利用しています。一方で、スレーブ用インスタンスは、スペックの低いマシンを複数台利用することで、スケールアウトするような設計にしています。

また、スレーブ用インスタンスは、通常時は停止状態になっています。Jenkinsの待機ジョブの数が一定数を上回ったときに自動でインスタンスが起動され、Jenkinsの待機ジョブを実行します。そして、待機ジョブがなくなったタイミングでJenkinsから切り離しインスタンスがシャットダウンするようにしています。

このように、マスター・スレーブ構成でかつ、スレーブ用マシンは必要なときのみ起動するようなサーバー構成を採用したことで、特定の時間帯にジョブが多く発生してもそれらを短時間で捌くことができています。また、将来ジョブの数が増加していったとしても、Google Cloud上でスレーブ・インスタンスのクローンを作成し、Jenkinsのスレーブとして投入することで、相当数のジョブを捌くことが可能な構成になっています。

まとめ

今回は、社内で動かすバッチが増えるタイミングで上記のような仕組みを構築しました。その仕組みは、

  1. ベースとなるジョブのプログラム本体は、RubyまたはEmbulkにて実装
  2. ジョブの実行基盤として、Web UIを持ったJenkinsを採用
  3. ジョブを実行するバッチサーバー構成に、Google Cloud Computingを利用し、複数のインスタンスで並行実行が可能な状態を実現

となっています。

これにより今後のプリンシプル社内でのバッチ・プログラムの開発と実行がスムーズにできるようになりました。

プリンシプルでは、このバッチ実行基盤を用いて、クライアント様の様々なデータをBigQueryなどのDWH(データウェアハウス)に統合し、Tableauで可視化する仕事を請け負ってます。プリンシプルの仕事に興味のある方はぜひお問合わせください。

お気軽にご質問、ご相談ください

山田良太

テクノロジー開発室長。チーフテクノロジーマネージャー。10年以上のプログラミング経験を活かして、Webマーケティングのテクノロジー領域(APIを使ったシステム開発や、タグ実装など)を中心に取り組む。

関連ブログ