あると便利なマラソン用ジャッジ環境について
まえがき
(当ブログに掲載された内容によって生じた損害等の一切の責任を負いかねますので、ご了承ください。)
これは Competitive Programming Advent Calendar 2018 18日目の記事です
topcoder marathon matchやchokudai contest等のマラソン系コンテストに取り組む上で、
- テスト環境を作るのが面倒
- 大量のテストケースでプログラムを動かして結果を見たいけど、ローカルのパソコンが可哀想だからあんまりやりたくない
- プログラムのスコアをコメント付きでうまいこと管理したい
- パラメータ調整を手動でやるのが辛い
等々の課題があります。プログラムのスコアはジャッジに投げることで管理すればええやんという気持ちもありますが、 例えばtopcoderの場合は一度提出してから2時間は間を空けないといけなかったりするので、もっと手軽に投げれる環境が あればそれに越したことはないよね! あと開発経験積みたいね!
ということで作った時の苦労・嵌った罠とかいろいろ書いておくので、自分用ジャッジ環境を作成したい人の 参考になればとっても嬉しい😀
先人たちの作成したジャッジ環境との違い
偉大な先人様によって、ジャッジ環境の構築に関しては既に色々記事が出てます
今回は自分用のジャッジサーバーということで、多分差別化はできているはず。
アプリについて
自分しか使わないということで実現方法は何でもよいですが、何かしらのアプリケーションを作らなければなりません。競プロerは競技プログラミングでしかプログラミングをしたことがない(とても失礼な偏見ですが、昔は自分もそうだった)ので、何かしら勉強する必要があります。Webアプリはいろんな言語でいろんなフレームワークが出ているし,簡単なものを作るだけなら難しくないのでそれを勉強するのが良いのかなと思います。Rubyならrails、JavaならSpringやplayframework、PythonならDjango等々いろいろありますが、自分の使いやすい言語なら何でも良いと思います。
構成
自分はこんな感じの構成でジャッジ環境を作りました。
ジャッジサーバーは手軽にスケールできるようにAWSを使っていて,EC2がそれにあたります。 S3はクラウドストレージで、主に提出したソースコードを管理していますが、自分しか使わないのでローカルのデータベースに直接入れてしまっても良いような気がしています。 Webサーバーもクラウドに上げてしまったほうが便利といえば便利ですが、お金の問題が発生するというのと、自分用の環境なら必要なときにだけ起動させておけばよいのでWebサーバーはローカルでいつも動かしてます。 クラウドを構築する上で、他人にジャッジサーバーを勝手に使われてはいけない等の基本的なセキュリティは意識しないといけないですが、不特定多数の人に開かれたジャッジ 環境で意識しないといけない攻撃(悪意のあるコードの実行・fork爆弾等)は考慮しなくて良いのでかなり楽です。
AWSについて
秒単位で課金できるので、ジャッジが投げられたときにAWS EC2を必要な台数だけ起動し、計算が終わって ジャッジキューが空になったら停止することで、必要最低限の費用でジャッジ環境を動かすことができます。 普通のジャッジサーバーはコンテスト中常時動かす必要がある(と勝手に思っています)が、こういったちょこまかとした 制御をすることでびっくりするほどお金がかからないです。
AWSの強みは安い以外にも簡単にスケールできるというメリットがあります。例えば、1ケース10秒かかるものを600ケースくらい 処理したいというときに、単純計算だと6000秒 = 100分かかります。こういった場合、例えばEC2を20台起動して分散処理 させれば5分で終わらせることができます(強い)。お金は秒単位課金なので、1台処理とn台処理ではあまり変わりません。
費用
(間違ってるかもしれないのでご指摘お願いします) 例えば全体で1時間かかる計算をn台のEC2インスタンス(t2.micro, 8GBのストレージ, オハイオ州)で分散処理した場合、 がかかります。0.0116はEC2を1時間走らせたときにかかる費用で、 右側の項はEC2インスタンスのストレージに対してかかる費用です。 日本円に換算すると約1.5円。実質無料。
アカウントを新規で開設してから1年間は月750時間分の起動時間が無料になったり、学生の場合は年間で 40$もらえたりして、実質じゃなくて本当に無料になる。 (実際には起動するためのオーバーヘッドや、S3へコードを保存したりする場合にはもう少しかかります)
1.5円(実質無料)で1時間弱を買うのは、人によって感じ方は違うと思いますが、自分はとてもお得だと思います。
実装について
EC2インスタンスの作成・起動・停止・削除
EC2インスタンスの作成・起動・停止・削除はとても簡単です。
Javaの場合だとAWS SDK for Java docs.aws.amazon.com
というのが配布されていて、それを使うと起動はこんな感じでできます。
AmazonEC2 ec2 = AmazonEC2ClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("アクセスキー", "シークレットキー"))) .withRegion("リージョン") .build(); StartInstancesRequest request = new StartInstancesRequest().withInstanceIds("起動したいインスタンスのID"); ec2.startInstances(request);
簡単!
StartInstancesRequestの代わりにStopInstancesRequestを指定してあげれば停止もほぼ同様のコードで実現できます。
注意として、アクセスキー・シークレットキーをハードコーディングして、Github等のパブリックリポジトリに入れてはいけません(それはそう)。盗まれてやりたい放題されるわけですが、Github上でこれらのキーを収集するBotが動いているらしく、短時間の公開でも抜かれてしまうみたいです。
嵌った罠
AWSを使ったジャッジ環境の構築は比較的簡単に実現できますが、自分の考えていた挙動をしなくなったことがあったので、それについて書き残しておきます。
EC2インスタンスには制約がある
EC2インスタンスを作成したら、そのインスタンス上で計算をやりたい放題できるかというとそんなことはなく、CPUクレジットと呼ばれるもので制限がかかります。
要約をすると、
- 各インスタンスの種類に応じて一定時間ごとに一定のCPUクレジットが貰える。
- インスタンスはこのCPUクレジットを消費しながら動作する(CPU使用率に応じて使用するCPUクレジットが変化する)。
- 貰えるCPUクレジットと消費するCPUクレジットが均衡するCPU使用率をベースラインパフォーマンスという。
- ベースラインパフォーマンス以上のパフォーマンス(バーストパフォーマンス)を出すときには、蓄積されたCPUクレジットを消費しながら計算を行う。
- t2インスタンスは停止するとCPUクレジットを失効する
これが何を意味しているかというと、お金をかけたくないのでこまめにインスタンスを停止したいが、そうするとCPUクレジットがなくなってしまい、ベースラインパフォーマンスでの計算しかできなくなります。
これが非常に厄介で、t2.microのベースラインパフォーマンスはとても貧弱なので計算が全然終わりません。自分で計算をしたほうが早いくらいです。
これを解決する方法として、こんな機能があります。
バーストパフォーマンスを出したいが、CPUクレジット残高が足りていないとき、CPUクレジットの前借りのようなことをする制度です。
これを使うといい感じにパフォーマンスが出ます。が、CPUクレジットの前借りをするので、当然その分を 返さなければならず、余分なお金が発生します。
24時間あたりの平均使用率がベースラインを超えると料金が発生するので、EC2インスタンスの台数を増やして1台あたりの使用時間を極力へらすことで、このコストを無視できるっぽいです*1。 頻繁にジャッジを動かすなどをしてベースラインを超えた場合、1vCPU時間あたり0.05USDかかってくるので、1時間の計算を5分くらいで終わらせるためにかかるジャッジコストが7円くらいになります。
おわりに
https://research.preferred.jp/2018/12/optuna-release/
これはみんなが自分用のジャッジ環境を建てる時代が来ますね、間違いない(?)。
ゲームAIコンテスト用のジャッジサーバー作りたくなってきたぞ(???)
— たこし (@takoshiiiiiiiii) May 29, 2018
お金が溜まってセキュリティも万全にできたらやりたいね
19日目は
kmjp_pcさん→
kirika_compさん→「整数論テクニック集の続きを書きます。」
です!
*1:本当かどうか自信がない