ParseがRubyからGoへ移行,信頼性が大きく向上

Parseはスケーラビリティを向上させるため,APIを含むサービスの一部をRuby on RailsからGoに移行した。同社のエンジニアであるCharity Majors氏が詳しく説明している。これによって信頼性とデプロイメント時間が著しく改善された。

Parseは2011年,Ruby on Railsのプロジェクトとしてスタートした。この選択によって,Parseの最初のバージョンを少人数の技術者グループで短期間に実装することができた,とMajors氏は言う。しかしながら,Parseが拡張されるにつれて,アーキテクチャ上の問題がいくつか現れた。

  • コードベースの拡大に伴い,デプロイメントやロールバックに要する時間が増加した。さらに,ParseのHTTPサーバであるUnicornの再起動が正常にできなくなった。その結果,モンキーパッチ(monkeypatching)に頼る部分が次第に大きくなった。
  • Railsの“要求毎に1プロセス”というモデルが,APIトラフィックとアプリ数の増大につれて“崩壊”を始めた。実際に,時間を要するリクエストを数多く受信した場合,Railsのワーカプールサイズの自動拡張機能が追いつかず,ワーカプールが簡単に溢れてしまう現象が発生していた。さらに,これらワーカの多くは,単に外部サービスの完了を待っている状態だった。

このような問題から,Parseのエンジニアたちは,Railsの“要求毎に1プロセス”モデルを離れて,真の非同期モデルに移行する必要性を認識するに至った。Rubyのgemsの大部分には非同期性がなく,またスレッドセーフでないことも多いことから,Rubyはこのような処理に適さないと考えた彼らは,別の言語を選択することにした。選択肢として彼らが検討したのは次のものだ。

  • JRuby,これは除外された。JVMには大規模な並行処理を扱う能力があるものの,Rubyの非同期ライブラリサポートに問題があることには変わりないからだ。
  • C++,他の言語に比較して生産性が低いこと,HTTPリクエストの処理や非同期操作などをサポートするライブラリのないことなどを理由として,これも除外された。
  • C#,非同期/Await Asyncモデルには非常によい選択肢だと考えられたが,“LinuxにおけるC#開発は主流になり得ないと思われた”ため,除外された。
  • Go,非同期操作をネイティブにサポートしていること,MongoDBのサポートが最高レベルであること,コルーチンのサポートなどから,最終的に最もよい選択肢であると考えられた。

Parseの技術者たちが,自分たちのEventMachineをGoで実装して,簡単なテストを行ったところ,ノード当たりの接続数で25万~150万という結果が得られた。この結果をもとに彼らは,コアAPIを含むすべてのサービスをひとつずつ,下位互換性を確保しながら書き直す作業に着手したのだ。

プロセスの終了時には努力に見合う結果が得られた,とMajors氏は述べている。

  • Parseの“信頼性が著しく向上した”。
  • 稼働するデータベース数の減少により,APIの脆弱化に歯止めがかかった。
  • テストスイート全体の統合実行に要する時間が,25分から2分にまで短縮できた。
  • APIサーバ全体のデプロイ時間が,30分から3分に短縮された。
  • APIサーバの正常な再起動が最終的に実現できた。