2018年07月27日

GCP × condor で分散計算

GCP × condor で分散計算をした記録です。

【前提】
対象とした計算は、高速道路・有料道路料金提供サービスや高速.jpで利用している、高速道路の料金計算。高速道路の料金は「最安経路」で決まるというルールがあります。日本の主要な高速道路はおよそ距離あたりいくら(例えば普通車は約24.6円/km)で決まっているのですが、中にはそうでない場所が沢山混ざっていて、例えば飛騨トンネルはちょっと割高(36.36円/km)だったり、100kmを超えると料率が低減していったり、中にはキロあたりではなくてここからここまではいくらで決まっている区間があったり(中には無料化されている区間があったり)するので、その中から「最安」の経路を探すのはなかなか難しい経路探索問題になっています。
そして、この料金データは、新しいインターができたり、新しい道路が開通したりする度に更新する必要があり、およそ月に一度、日本全国のインター約1000件の組み合わせ全100万ペアに、いくつかの割引料金を合わせて全500万ペア程度の計算を実施しています。

【これまでの状況】
さて、この沢山の計算を、これまではオンプレの計算サーバーで実施していました。現在はコア数およそ20を使って20時間程度を要していますので、400CPU時間程度かかっていることになります。しかし、そろそろこの計算サーバーも古くなってきたので、新しいマシンに置き換えたい。というより、せっかくクラウドデータ分析の仕事をしているので、この計算もクラウドに置き換えたいと思い立ちまして、今回の記事になります。

【これまでも置き換えようとしたことはあった】
実は、これまでもこの計算をクラウドに置き換えようとしたことはあったのですが、いくつかの課題(次)があって実現しませんでした。
  • 現状の計算には、ジョブスケジューラーとして condor を使っているのですが、これを他の仕組みに置き換えるのは大変。
  • 計算エンジンはC++で書かれていて、いくつかの実行形式に分かれているものを繋いで使っています。高速化にかなりチューニングしているので、これをひっくり返すのは大変。(例えばlightweight系の言語で書き直したりすると、おそらく計算時間が100倍以上になる。)
  • 計算が終わるのにある程度の時間がかかるので、ずっと監視しているわけにいかない。すると、クラウドでCPUを沢山調達してちょっと目を離すと、それなりに無駄なコストがかかってしまう。例えばCPU=128(例えばn1-standard-32を四本)などというモンスターマシンを調達して、計算を実施するのに手間取って数時間つけっぱなしにすると1時間で8ドル、前処理後処理に数時間かかったりするとそれだけで何十ドル、消し忘れて24時間たつと192ドル・・・これは痛い。
ということで、計算ができる、というところまでは試したことがあったものの、実際にクラウドに移行する迄には至っていませんでした。

【今回取り組んだ、最適な組み合わせ】
さて、このように、コスト面でちょっと難があって、というより、今までオンプレの低コストで運用し続けられていたので、実験以外ではあまりクラウド化に消極的だったのですが、先日たまたま見つけた GCP の記事で、これはいけそうだと思い、今回のクラウド移行になりました。その記事はこちら →「HTCondor による高スループット コンピューティング」。
この記事にあるアーキテクチャを少し修正して、料金計算の仕組みを作れると思いまして、取り組みを始めました。記事の図1を拝借して説明します。


この記事は、GCPの Deployment Manager を使って、この図の中にある condor の計算環境をすべて一気にデプロイし、計算を実施し、終わったらすべて削除します。Computeのインスタンスはプリエンプティブで立てるので低コスト。また、何台でも自由に設定できます。よって、この環境をデプロイし、沢山のジョブをSubmitして計算し、終わったら全部消せばよい。消し忘れてもcomputeインスタンスはプリエンプティブなのでコスト的に我慢できなくもない。(もちろん、ジョブが全て終了したら自動的に delete されるように仕込めばよい。)

一方で、現状の計算方法では、前処理、後処理がそれなりにかかり、その後にジョブ発行するので、SubmitするホストはMasterやComputeと一緒にデプロイするのではなくて、別途永続ディスクで立てておきたい。但し、そちらにはあまり大きなCPUリソースは必要ない。また、実はこの記事のサンプルでは master も compute も同じインスタンスタイプで立ち上がるのですが、計算負荷がかなり大きいのに対して、データのジョブの取り回しはさほど大きくないので、master は小さいインスタンスで十分。

そこで、修正後は次のような環境にしました。
  • Submit hostは別立てで用意し、前処理、後処理などの計算およびジョブの発行を実施する。
    • n1-standard-4 を永続ディスクで立ち上げ、condor および コンパイラと、計算環境の一式をインストール。
    • OSはContOS7を利用した。
    • condor の daemon は、MASTERとSCHEDD のみ。なお、submit hist への condor のインストールは、サンプルの中にある startup-submit.sh を参考にすると容易。
  • ネットワークはあらかじめ専用のネットワークとサブネット、ファイアウォールを作っておく。
    • 実は上の記事のサンプルでは、ネットワークとファイアウォールもデプロイ対象になっている。実は condor の環境設定で一番面倒なのはネットワークで、セキュリティをそこそこ意識しつつ、マシン間通信が筒抜けになるように設定しないとうまく動いてくれない。
    • しかし今回は、Subnet hostはこのデプロイとは別に立てるので、ネットワークもあらかじめ作っておいてその中にSubmit hostを置いておく。
  • デプロイマネージャーはmaster と compute だけをデプロイする。
    • ネットワークはあらかじめ作ってあるので、デプロイマネージャーはその中に master および compute を突っ込む。
    • このとき、想定する計算負荷によって、インスタンスタイプやノード数は適宜決める。容易に修正できるのは、デプロイマネージャーを使う利点で、計算エンジンの利用するメモリ容量に応じて(例えば、計算すべき経路が沢山あるところはハイメモリタイプで、そうでないところはスタンダードで)設定ファイルを修正すればよい。
    • まずは、master は n1-standard-4、compute は n1-standard-32、計算ノード数は3で設定した。これで96並列の計算ができる。

このように環境を作ると、作業フローは次のようになりました。

  • まず Submit host のみを立ち上げて、いろんな前処理を実施。
  • 計算エンジンによる並列計算の直前に、デプロイマネージャーから master および compute を立ち上げる。
  • master との通信が確立(*)したら(1,2分かかる)、job を submit する。
  • 計算が終わるのを待つ。もしくは放置する。
  • 計算が終わったら、デプロイマネージャーを利用して master と compute を消す。
  • Submit host で後処理を実施。最終結果をGCSに保存して終了。
  • Submit host を停止する。

これでかなり現実的な計算環境が構築できたと思います。現在は、このGCPプロジェクトのCPU数上限が128なので、96並列×4時間程度の計算になっていますが、CPU数上限を1000程度にすれば30分程で全ての計算を終わらせることができ、しかもコストはほとんど変わりません。さすがに1000並列はGCPさんに負荷を掛けすぎかなと思うので、いまのところは128程度にしておこうと思いますが、クラウド × condor の利用によって、レガシーな分散計算でも容易に環境を作れるようになりました。

【いくつか注記】

・本当は Dataflow がいい
おそらく、このような計算を実施するのにいま最も適しているソリューションは、Dataflow だと思います。が、C++で書かれているレガシーな計算エンジンををうまくラッピングして dataflow に持っていくのが難しそうだったので、今は断念しました。Cloud Functions もありだと思いますが、こちらは1ジョブあたり2GBまでしかメモリを使うことができず、この計算では最大4GB程度まで行くので、こちらも断念。そのうち、利用可能メモリがもっと大きくなったら、cloud functions にジョブを投げまくって回収するのが良さそうです。

・condor の submit - master 間の通信がうまくいかない
上の(*)で示したところ、Submit host と master との通信が確立したら、のところですが、実は現状、ただデプロイするだけではうまく通信ができず、いつまで経っても submit してあるジョブを master が読んでくれません。おそらく、submit host → master の順でマシンを立ち上げているからなのではないかと思いますが、正確なところはまだ理解していません。condor 環境を作るとき、通常は master と submit host が同じマシンだったり、master のある環境の中でsubmit host を立ち上げることが多いような気がしますが、それが逆になることで、submit host の側から master がうまく見えていないのではないかと思います。
これは、submit host の側でcondor の DAEMON をリセットしてあげるとうまく動きました。(systemctl reload を実施)ただ、もっといい方法があるんじゃないかなと思っています。

・CPU数やInner IP数は、googleに上限アップ申請が必要
これらの上限値は、最初はあまり大きくは割り当てられていないので、大規模分散計算をしたいときには上限アップ申請が必要です。1日程度で反映してくれました。CPU数上限だけ上げてもらえばいいと思っていたら、Inner IP数の上限に引っかかって二度手間になってしまいました。ただ、compute の方は、小さいインスタンスタイプを沢山立ち上げるのも、大きいインスタンスタイプで少なく立ち上げるのも、コスト的にはおそらくほぼ変わらないので、大きなインスタンスを少なく立ち上げて、IPなどの資源をあまり利用しない方がいいんじゃないかなと思います。特に、何十個もインスタンスを立ち上げると、外部IPをそれだけ食うので迷惑なんじゃないかと。(外部IPを割り当てない立ち上げ方があると思うので、そうすれば良いかも。)

【おわりに】
ということで、無事、計算環境をクラウド化することができたので、しばらく様子を見て、うまく継続運用できそうでしたら、高速道路料金計算はオンプレとはおさらばになります。
この高速道路の計算を始めたのが2008年頃ですから、それから10年くらいやってきました。1ジョブあたりの計算性能はその頃からあまり変わっていないのですが(エンジンのアルゴリズムやコードもほとんど変わっていない)、並列計算環境や、クラウド環境はまったく別次元で進化しましたね。こんなに使いやすく、また、安価になるとは思っていませんでした。当時はデータセンターで計算サーバーを何十台も借りて並べてもらったり(30CPUで一ヶ月に100万円ほどかかった記憶が・・・)、5年ほど前にはAWSのMapreduceで計算してみたりもしたのですが(当時は課金単位が1時間だったので、100CPUの計算で失敗すると100時間分の課金をされてしまった)、かかる手間と費用と時間が全く違います。高速道路料金の一回の計算にかかるGCPサーバー代はおよそ2000円。何度かやり直しても1万円。前処理や後処理も数十円。もちろん人件費が最も大きくて、情報収集や検証などでしっかりコストがかかっているのですが、サーバー代だけなら一回高々1万円で、96並列の計算環境が利用できるというのは、素晴らしい進歩だと思います。




posted by jinya at 20:07| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。