MongoDBからPostgresへ

注: このブログ記事は、私の MongoDB to Postgres (2024-03-06)Sequelize vs. Prisma (2023-05-25) を統合したものです。元のブログは削除され、これら2つが本質的に同じ内容・情報を含んでいたため、このブログがその代わりとなりました。移行は 2023年3月初旬 に始まり、切り替えは 2023年11月中旬 に行われ、古いMongoDBシステムの全インスタンスは 2024年1月初旬 に完全に停止されました。

はじめに

eBayで働いていた間、私は自分のキャリアの中で最も技術的に難しい問題に直面しました。それは、Storage Management System(STMS)をMongoDBからPostgresへ移行することでした。これは単なるデータベースの置き換えではなく、eBayのデータセンター全体で毎分150万件以上のメトリクスを取り込みつつ、ゼロダウンタイムと既存機能のほぼすべての維持を求められる、重要システムの完全なアーキテクチャ変革でした。

STMSとは何か?

Storage Management System(STMS)は、eBayのService & Storage Infrastructure(SSI)チームのための重要な社内ツールとして機能しています。これはeBayのデータセンター全体のデバイスを監視・管理し、エンジニアが次のことを行えるようにします。

  • 数十台のアレイ、スイッチ、ホスト、ディスクグループ、クラスタからのメトリクスを監視する
  • スイッチとアレイのアラート対応を行う
  • ホスト割り当てのような高度なタスクを完了する
  • 他のeBay社内サービスのリアルタイムデータにアクセスする

STMSは、eBayの3つのデータセンターにまたがる70以上のアレイ、60台のスイッチ、1100台のホスト、900のディスクグループ、200のクラスタを管理しています。eBayのインフラにおける重要な役割を考えると、ダウンタイムや機能喪失は、会社の中核サービスや事業運営に直接影響します。

課題

なぜ移行が必要だったのか

MongoDBからPostgresへの移行の決定は、軽率に下されたものではありませんでした。MongoDBは当初STMSにうまく機能していましたが、データ関係の複雑化と、より高度なクエリ機能の必要性により、Postgresのほうがこのユースケースに対する長期的な解決策として適していると判断されました。

この問題が難しかった理由

この移行の複雑さはいくつかの根本的な課題に由来していました。

1. データベースの根本的な違い
MongoDBとPostgresは根本的に異なるデータベースです。MongoDBはドキュメントベースのデータベース(NoSQL)であり、データはファイルキャビネットの中の書類のように、コレクションにJSONとして保存されます。Postgresはリレーショナルデータベース(SQL)であり、データはスプレッドシートのように、テーブル内の行として保存されます。

2. コードベースのアーキテクチャ
STMSのバックエンド全体は、データをJSONとして処理・管理するように構築されており、データベース操作にはMongoDBと専用に互換性のあるパッケージを使用していました。これは、単にデータベースを変えるだけでなく、アプリケーション全体がデータを扱う方法を再構築する必要があることを意味していました。

3. ゼロダウンタイム要件
社内ツールとしてSTMSが非常に重要であるため、移行中にダウンタイムは一切許されませんでした。システムは、全工程を通じて毎分150万件超のメトリクスを提供し続ける必要がありました。

4. 厳しいタイムラインと限られた経験
移行は数か月以内に完了しなければならず、当初は明確な実行計画もありませんでした。私も同僚も、NoSQLからSQLデータベースへ大規模なレガシーコードベースを移行した経験はなく、私はPostgresの実務経験も限られていました。

5. 規模と複雑さ
この移行では、36個のMongoDBコレクションを74個のPostgresテーブルへ変換する必要があり、関係性、インデックス、クエリ最適化を慎重に考慮しなければなりませんでした。

適切なORMの選定: Sequelize vs Prisma

最初の主要な決定の一つは、ORM(Object-Relational Mapping)ツールを選ぶことでした。私たちのコードベースはすでにMongoDB向けにMongooseを使うよう設計されていたため、ORMを使うことが最もスムーズな移行経路を提供すると考えられました。

要件分析

プロジェクトのニーズを慎重に分析した結果、私はあらゆるORMソリューションに必要な基本条件を定めました。

  • JavaScriptパッケージであること(コードの大半はJavaScriptで書かれていたため)
  • Postgresとその主要機能のほとんどをサポートすること
  • パフォーマンスが少なくともMongooseと同等、またはそれ以上であること
  • オープンソースで保守されていること

候補

広範な調査の結果、私はSequelizeとPrismaという2つの主要候補に絞り込みました。Postgres用にDockerを使って包括的なテスト環境を構築し、私たちの最大かつ最も複雑なデータセットをドキュメント構造からテーブル構造へ変換しました。

テスト手法

各ORMについて、重要な操作全般でパフォーマンスを測定しました。

  • エントリ作成にかかる時間
  • エントリ更新にかかる時間
  • ネストされたエントリ(リレーションとJSONキー・バリュー)の更新にかかる時間
  • エントリ削除にかかる時間
  • エントリのクエリ/取得にかかる時間

結論: Sequelize

2023年5月15日頃、私はSequelizeが私たちのユースケースに適したORMだと判断しました。その理由は次のとおりです。

Sequelizeの利点:

  • 真にオープンソースであり、資金提供を受けたスタートアップによって保守されていない
  • Postgresの機能の大部分をサポートしていた
  • より優れたパフォーマンス、特にPrismaと比較した場合
  • 10年以上の開発歴を持つ成熟したエコシステム
  • JavaScriptクラスを使った柔軟なモデル/スキーマ表現
  • Regexを含む複雑な結合とフィルタリングオプションのサポート

パフォーマンス結果:

私のテストでは、SequelizeはPrismaを大きく上回りました。巨大データセットのエントリに対しては次のような結果でした。

  • Sequelize: 1エントリあたり約2.26秒
  • Prisma: 1エントリあたり約11.21秒

私たちのユースケースでは、PrismaはSequelizeより約5倍遅かったです。さらに、最大データセットから1件削除するのにPrismaはほぼ4分かかり、これは私たちの要件には受け入れられませんでした。

Sequelizeの課題:

  • より複雑で肥大化したモデル表現(Mongooseの564行に対して262行)
  • 場合によっては分かりにくい構文
  • データベース移行の複雑さ
  • Prismaと比べて包括的ではないドキュメント

SequelizeとPrismaの長所・短所の比較

私がSequelizeを選んだ理由をより明確にするため、評価時に両ORMについてまとめた詳細な長所・短所を共有したいと思います。2023年5月15日時点で、スキーマ表現とコミュニティサポートの観点でどのように比較されるかも確認しました。この深掘りは私の選択を確かなものにしてくれましたし、同じような判断に迫られている人にも役立つことを願っています。

Sequelizeの長所:

  • sync()関数があり、テーブルを自動で作成・管理してくれるため、多くの手作業を省ける。
  • ネストされたデータの複雑な結合を扱える。これはSTMSの構造にとって非常に重要だった。
  • Regexを含む幅広いフィルタリングオプションをサポートし、クエリに柔軟性を与える。
  • モデル/スキーマ表現はクラスを用いた生のJavaScriptで行われ、個別のニーズに合わせて高度にカスタマイズできる。
  • 複数の読み取り接続のサポートを含め、データベース接続をシームレスに扱える。
  • 仕組みを掘り下げたいときのために、Raw SQLクエリをサポートしている。
  • 2023年5月15日時点のコミュニティ統計: NPMでは14日前に更新され、週間ダウンロード数は1,505,835件。GitHubでは昨日更新され、Forkが4.2k、Starが27.9k。10年以上にわたりMITライセンスでオープンソースとして続いているので、このまま続くと確信している。

Sequelizeの短所:

  • モデル/スキーマ表現が非常に複雑で肥大化しやすい。例えば、大規模データセットのMongoose表現は約262行(空白込み)だったのに対し、同じデータセットはSequelizeでは564行に膨れ上がった。
  • 構文が特定の状況で分かりにくく複雑になり、時々作業速度が落ちた。
  • データベースの移行や編集は面倒。sequelize-cliが移行スクリプトを生成してくれても、やはり扱いにくい。ただし、これは多くのORMに共通する悩みの種だと感じている。
  • ドキュメントはあまり良くないが、改善はしている。幸いなことに、ChatGPTのようなツールはSequelizeの長い歴史のおかげでかなり理解しており、その隙間を埋める助けになった。
  • Prismaほど型に厳密ではないため、いくつかのプロジェクトでは問題を引き起こす可能性がある。
  • TypeScriptサポートが限定的であり、これはSTMSでは問題ではなかったが、他の人にとっては決定的な欠点になり得る。

Prismaの長所:

  • 独自のスキーマ言語を使うため、モデル作成がよりきれいで簡潔になる。比較すると、大規模データセットではMongooseが262行必要だったのに対し、Prismaは221行で済んだ。
  • データベース作成と移行を簡略化するCLIツールが付属しており、完全ではないにせよ、これまで見たORMの中では最も優れていた。
  • Raw SQLクエリをサポートし、必要なときに柔軟性を提供する。
  • コード構文はSequelizeと比べて分かりやすくシンプルで、学習しやすい。
  • クライアントを通じてNode.jsとTypeScript用のクエリビルダーを自動生成するのは、うれしい工夫である。
  • 優れた、整ったドキュメントを備えている。ChatGPTはPrismaに関しては最新ではないが、公式ドキュメントがそれを補っていたことが多かった。
  • 2023年5月15日時点のコミュニティ統計: NPMでは6日前に更新され、週間ダウンロード数は1,344,705件。GitHubでは3時間前に更新され、Forkが1.1k、Starが31.3k。

Prismaの短所:

  • Postgres向けのRegexフィルタリングをサポートしていない。ただし、“contains”、“includes”、“startsWith"のような代替手段はある。
  • テストではパフォーマンスが大きな問題だった。大規模データセットのエントリ作成は、Sequelizeの2.26秒に対してPrismaでは約11.21秒かかり、およそ5倍遅かった。
  • 大規模データセットから1件を削除するのにほぼ4分かかり、私たちのニーズにとっては致命的だった。
  • 複雑な3層にまたがるリレーションデータセットで公平に比較しても、削除処理ではSequelizeのほうが大幅に高速だった。
  • Prismaは5,650万ドルの資金調達を受けたスタートアップに支えられている。主要なORMコードはApache-2.0のもとでオープンソースだが、MongoDBで起きたことのように、将来的なライセンス変更の可能性には警戒している。

これらの詳細な比較によって、特にパフォーマンスと長期的な信頼性の面で、SequelizeがSTMSのニーズによりよく合っていることが明らかになりました。ただし、このように分解して説明することで、同じ選択に悩んでいる他の人にも役立つかもしれないと考えました。

移行プロセス

データ構造の変換

MongoDB のドキュメント構造から Postgres のリレーショナル構造へ変換するには、慎重な計画が必要でした。私は以下を行う必要がありました。

  1. 関係の分析: MongoDB のドキュメント同士がどのように関連しているかを特定し、適切な外部キー関係を設計する
  2. データの正規化: 必要に応じて、ネストされたドキュメントを個別のテーブルに分解する
  3. JSON 機能の保持: 真に非構造化で柔軟性を維持する必要があるデータには JSONB 列を使用する
  4. インデックスの設計: クエリ性能のために適切なインデックスを作成する

カスタムソリューション

この移行では、いくつかのカスタムソリューションを開発する必要がありました。

1. データ移行スクリプト
私は、以下を行う包括的なスクリプトを作成しました。

  • MongoDB コレクションからデータを抽出する
  • ドキュメント構造をリレーショナル形式に変換する
  • 適切な関係を伴ってデータを Postgres テーブルに取り込む

2. API 互換レイヤー
ゼロダウンタイムを維持するために、私は互換レイヤーを構築し、以下を可能にしました。

  • 移行状況に応じて、MongoDB または Postgres のいずれかにリクエストを振り分ける
  • 移行期間中のデータ整合性を確保する
  • フォールバック機構を提供する

3. カスタムミドルウェア
MongoDB と Postgres が特定の操作を処理する方法の違いを扱うためのミドルウェアを開発し、既存の API エンドポイントが変更なしで動作し続けるようにしました。

技術的課題の克服

複雑な関係の扱い

最大の課題の一つは、MongoDB の埋め込みドキュメントを Postgres のリレーションへ変換することでした。たとえば、1 つの MongoDB ドキュメントには次のような内容が含まれている場合があります。

  • 基本プロパティ
  • 関連エンティティを表すネストされたオブジェクト
  • 埋め込みドキュメントの配列

これを慎重に分解して、以下のようにする必要がありました。

  • 主エンティティ用の主要テーブル
  • 多対多関係用の中間テーブル
  • 一対多関連用の外部キー関係

クエリ最適化

MongoDB のクエリパターンは、SQL に直接は変換できません。私は以下を行う必要がありました。

  • 複雑な集約パイプラインを SQL の JOIN に書き換える
  • 新しいクエリパターンに合わせてインデックスを最適化する
  • クエリ性能が MongoDB の性能と同等か、それ以上になるようにする

データ整合性

移行中のデータ整合性を確保するには、以下が必要でした。

  • 包括的な検証スクリプト
  • ロールバック手順
  • 移行期間中のリアルタイムデータ同期

結果と影響

MongoDB から Postgres への STMS の移行は、ほぼすべての機能と機能性を維持しつつ、ゼロダウンタイムで無事に完了しました。その結果は期待を上回るものでした。

パフォーマンス向上:

  • 複雑なリレーショナルクエリのクエリ性能が向上した
  • データの一貫性と整合性が改善した
  • ストレージ利用効率が向上した

運用上の利点:

  • 監視およびデバッグ機能が強化された
  • eBay の既存の SQL ベースのツールとの統合が改善された
  • バックアップおよび復旧手順が改善された

チームへの影響:

  • リレーショナルデータベースに関するチームの知識が向上した
  • 将来のデータベース移行のためのパターンが確立された
  • 再利用可能なツールとプロセスが作成された

身につけた技術スキル

このプロジェクトによって、私の技術的専門性は大きく広がりました。

データベース技術:

  • Postgres の機能と最適化に関する深い理解
  • SQL クエリの最適化とパフォーマンスチューニング
  • データベース設計パターンと正規化
  • プライマリ・スタンバイのデータベース構成

開発ツール:

  • Sequelize ORM とクエリ構築
  • データベース移行戦略
  • パフォーマンステスト手法
  • データ検証と整合性チェック

アーキテクチャパターン:

  • ゼロダウンタイム移行戦略
  • API 互換レイヤー
  • データベース抽象化パターン
  • 監視およびアラートシステム

個人的・職業的成長

この移行プロジェクトは、私のキャリア成長にとって大きな転機でした。私は未知の領域に踏み込み、以下が求められました。

リーダーシップスキル:

  • 事前経験なしで複雑な技術プロジェクトを率いること
  • 圧力下で重要なアーキテクチャ上の意思決定を行うこと
  • 複数のチームや利害関係者と調整すること

問題解決能力:

  • 複雑な問題を管理可能な要素に分解すること
  • 前例のない課題に対して創造的な解決策を開発すること
  • 複数の競合する要件や制約のバランスを取ること

コミュニケーションとチームワーク:

  • 技術的でない利害関係者に技術的概念を説明すること
  • 将来参照できるようにプロセスと判断を文書化すること
  • 新しい技術やパターンについてチームメンバーを指導すること

学んだ教訓

技術的な教訓

  1. データベース選定は重要: NoSQL と SQL のどちらを選ぶかは、具体的なユースケースと長期的要件に基づくべきである
  2. パフォーマンステストは重要: 理論上の利点が、実世界での性能向上に必ずしもつながるとは限らない
  3. 移行計画: 複雑な移行には、包括的な計画とテストが不可欠である
  4. ツールへの投資: 適切なツールを最初に構築しておくことで、大幅な時間節約とエラー削減につながる

プロジェクト管理の教訓

  1. 利害関係者とのコミュニケーション: 定期的な अपडेटと明確なコミュニケーションが誤解を防ぐ
  2. リスク管理: フォールバック計画とロールバック手順を用意することが不可欠である
  3. タイムライン管理: 予期しない課題や学習曲線のためのバッファ時間を確保する
  4. 文書化: 徹底した文書化が知識移転と将来の保守を可能にする

結論

STMS の MongoDB から Postgres への移行は、私のキャリアの中で最も難しく、かつやりがいのあった技術課題でした。それは単なる技術的専門知識だけでなく、リーダーシップ、計画性、適応力も必要としました。このプロジェクトの成功は、適切な計画、徹底したテスト、そして卓越性への取り組みによって、最も複雑な技術的課題でさえ克服できることを示しました。

この経験は、ソフトウェアエンジニアリングに対する私のアプローチを根本から変え、以下の重要性を強調しました。

  • 技術的判断を下す前に、全体の文脈と要件を理解すること
  • 適切なツールとテストに時間を投資すること
  • 複雑なプロジェクト全体を通じて明確なコミュニケーションを維持すること
  • 必要に応じて新しい技術やアプローチを学ぶ意欲を持つこと

この移行の成功は、STMS の能力を向上させただけでなく、eBay のインフラプロジェクトに継続的に役立つパターンとプロセスを確立しました。それは、未知の課題を受け入れ、それを通じて成功することが、個人的成長と職業的成長の両方にとって鍵であるという私の信念を強めました。

振り返ってみると、このプロジェクトは私のキャリアにおける転換点を示しており、解決策を実装する開発者から、複雑な技術イニシアチブを設計し率いることができるエンジニアへと私を変えました。この経験から得た自信とスキルは、ソフトウェアエンジニアリングにおける新たな課題や機会に対する私のアプローチを今も導き続けています。