Compilifyはオンラインでコンパイラを提供するサービスだ。 Justin Rusbatch氏が始めたサービスでRoslyn CTP上で動作する。最近始まったばかりのサービスだが、既に.NETコミュニティの注目の的だ。我々はJustin Rusbatch氏に話を聞いた。
InfoQ: 自己紹介をお願いします。
Justin: Justinといいます。私はペンシルバニアにある小さな.NET専業のウェブ開発会社で働いている開発者です。夜間勤務でメインフレームのオペレータとして働いている間にC#を自習し、その後1年間、ASP.NETウェブフォームの開発を行いましたが、MVCが現れて以来、ずっとMVCでサイトの開発をしています。他の言語を学ぶのも好きです。Ruby on Rails、node.js、F#も触ったことがあります。
InfoQ: Compilifyの目的を教えてください。
Justin: Compilify (“compile-ify”と発音します)は多くのものから着想を得ました。一番影響を受けたのは、Roslyn CTPのC#インタラクティブウィンドウです。このウィンドウはREPL環境を提供し、開発中の個々のステートメントを実行し、すぐに結果を受け取ることができます。
Compilifyは.NETのコンパイラを完全にポータブルにします。また、共有と協業を推進する、高速でシンプルなインターフェイスを使ってアクセスできます。ブラウザで動作するIDEではありません。そのようなものよりシンプルなのです。IDEを立ち上げたり、新しいアイディアを試すためだけに、いちいちコンソールプロジェクトを作成する必要もありません。開発者の時間はますます貴重になっています。実際に試すことができるソリューションがない状態で、解決すべき問題について頭を悩ませるのに時間を使いすぎてしまうと、オーバーエンジニアリングに陥り、生産性が劣化します。
また、Compilifyは教育用ツールとしても利用できます。C#を学習したいけれど使ったことがない人向けです。Visual Studioをダウンロードして、インストールして、立ち上げるのはこれから学習しようとする人には敷居が高いです。実際、Visual Studioをインストールすると他の余計なアプリケーションまでインストールされてしまうので、インストールしないという開発者もいるようです。Compilifyを使えば、インストール作業なしでC#に触れられます。ブラウザのプラグインも必要ありません。
InfoQ: Compilifyの内部はどうなっているのですか。
Justin: いろいろな仕掛けが動いています!
ユーザーがコードをサーバーへ送信するとSignalRがパーシステントコネクションをひとつ開きます。ウェブサーバーは送信されたコードをオブジェクトにします。そのオブジェクトにはSignalRのコネクションIDが付加されており、Redisサーバ上の処理キューに追加されます。こうすることでウェブサーバーに他のユーザのリクエストを捌く余裕が生まれます。
バックグラウンドワーカーは難しい仕事をします。悪意のあるコードを実行しないようにするため、サンドボックスとして低い信頼レベルのAppDomainが作成され、その中でコードが実行されます。性能は調査していませんが、いままでのところ、性能を気にする必要はありません。必要なアセンブリとユーザーのコードだけがAppDomainへ読み込まれるからです。
ユーザのコードはひとつのメソッドに内包され、ひとつのコンパイルユニットへ変換され、アセンブリとして出力されます。アセンブリはサンドボックス内にロードされると、ユーザのコードを内包したメソッドが実行されます。メソッドの実行結果はシリアライズされて、バックグラウンドワーカーはこの結果を受け取ります。この処理は分離されたスレッドで実行されます。処理に時間がかかり過ぎる場合(現在の時間制限は5秒)にキャンセルできるようにするためです。ワーカーは結果を受け取ると、Pub/Subチャンネルを通じてRedisへこの結果と元のコード実行のリクエストが作成したSignalRのコネクションIDを出力します。ウェブサーバーはこの出力内容をApp_Start上のチャンネルで購読します。SignalRはこのチャンネルから受け取ったメッセージを適切なクライアントへ転送します。
設計が複雑なのは、ユーザのコードを安全に実行し、ウェブサーバーを安定化するためです。
InfoQ: このコンパイラはタインピングすると即時に応答を返します。実際にはサーバーとのラウンドトリップが発生しているにも関わらずです。どうやってこの高速な応答を実現したのですか。
Justin:タイピングが終わってから0.5秒後にユーザーのコードを検証するプロセスが走ります。エディタの内容は普通のAJAXリクエストでサーバーにポストされます。Roslynがポストされたコードのシンタックスや参照エラーをチェックします。エラーの場合はコンパイルユニットをアセンブリとして出力しません。エラーはクライアントに返され、ユーザーに表示されます。
InfoQ: このサービスを構築するのにどのくらいの時間/労力を費やしましたか。
Justin:1.5週間ぐらいでCompilifyを構築しました。まだ完成にはほど遠いです。この水曜日(4月11日)に発表したには単にコンセプトを証明するだけのものです。フィードバックが得られて、多少話題になればいいと思っていました。しかし、これほどのトラフィックを受け付けるとは思っていませんでした。
InfoQ: どのようなトラフィックを受け付けていますか。平均でどのくらいの数のウェブサーバー/ワーカーが必要ですか。
Justin: 水曜にサービスを公開してから先週一週間の内に、約20,000の流入がありました。ユーザーがコードを保存したり、検証したり、実行したりした回数は70,000です。ほとんどの流入は先週Twitter上で紹介されてから発生しました。John Gallowayのツイートによってかなりの負荷が生まれました。この時の同時セッション数は50から60でした。その後、Scott Hanselmanのツイートでセッションが3倍になり、ピーク時には170くらいになりました。私は負荷に対応するため、ウェブサーバを3台追加し、バックグラウンドワーカーを2つ追加しなければなりませんでした。
こんなにアクセスがあるとは思っていませんでした。AppHarborの皆さんが助けてくれなければ対処できなかったでしょう。彼らはしっかりと対応してくれ、負荷を低減するために必要なデータを提供してくれました。
ウェブアプリケーションとバックグラウンドワーカーの間でRedisのキューを置くことで、アプリケーションがスケールしやすくなりました。キューが溜まり始めたら、バックグラウンドワーカーを追加することができますし、フロントエンドに負荷がかかり始めたら、ウェブワーカーを追加すればいいのです。AppHarborのNew Relicアドオンを使えば、ウェブワーカーやバックグラウンドワーカーを簡単に監視できます。
InfoQ: このプロジェクトでRosylnやSignalRやRedisなどを使った経験から学んだことはなんですか。
Justin:SignalRは強力なツールです。セットアップも簡単です。しかし、どうやって使うかは考えておく必要があります。高速に動作しますので、軽量なツールのように思えます。私はページの読み込み時にSignalRのコネクションを開いて、閉じるのを忘れるという失敗をしました。David Fowlerのhttp://jabbr.netのようなチャットアプリケーションではこのような挙動は正しいです。
しかし、私の場合は正しくない実装です。コード実行のリンクがクリックされるまでクライアントにメッセージをプッシュする必要はないからです。また、クライアントにメッセージを送ったら、もうコネクションを開いておく必要はありません。必要なときにコネクションを開き、メッセージを送信したらすぐに閉じるようにしたことでサーバーの負荷は劇的に下がりました。
Compilifyはオープンソースのプロジェクトで、githubにホストされている。CompilifyはAppHarbor上で公開されている。AppHarborはこのプロジェクトのスポンサーであり、ブログ上でJustinのインタビューを公開している。