MongoDBからPostgresへ
🚨 このブログ記事は、私の MongoDB to Postgres (2024-03-06) と Sequelize vs. Prisma (2023-05-25) の統合です。元の記事は削除され、両方が本質的に同じ内容/情報を含んでいたため、このブログがその代わりとなっています。移行は 2023年3月初旬 に開始され、2023年11月中旬 に切り替えが行われ、古いMongoDBシステムのすべてのインスタンスは 2024年1月初旬 に完全に停止されました。
はじめに
eBayで働いていたとき、私のキャリアで最も技術的に挑戦的な問題に直面しました。それは、ストレージ管理システム(STMS)をMongoDBからPostgresへ移行することです。これは単なるデータベースの入れ替えではなく、eBayのデータセンター全体で毎分150万件以上のメトリクスを取り込む重要なシステムの完全なアーキテクチャ変換であり、ゼロダウンタイムとほぼすべての既存機能の維持が求められました。
STMSとは?
ストレージ管理システム(STMS)は、eBayのサービス&ストレージインフラストラクチャ(SSI)チームにとって重要な内部ツールです。データセンター全体のデバイスを監視・管理し、エンジニアが以下を行えるようにします。
- 数十台のアレイ、スイッチ、ホスト、ディスクグループ、クラスターからのメトリクスを監視
- スイッチやアレイのアラートを処理
- ホスト割り当てなどの高度なタスクを実行
- 他の内部eBayサービス向けにリアルタイムデータにアクセス
STMSは、3つのeBayデータセンターにまたがって70以上のアレイ、60のスイッチ、1,100のホスト、900のディスクグループ、200のクラスターを管理しています。その重要性から、ダウンタイムや機能喪失は会社のコアサービスとビジネス運営に直接影響します。
課題
なぜ移行が必要だったのか
MongoDBからPostgresへの移行は軽く決めたものではありませんでした。MongoDBは当初STMSに適していましたが、データ関係の複雑化と高度なクエリ機能の必要性から、長期的にはPostgresの方が適切な解決策となりました。
この問題が難しかった理由
この移行が困難だったのは、以下の根本的な課題があったためです。
1. 基本的なデータベースの違い
MongoDBとPostgresは根本的に異なるデータベースです。MongoDBはドキュメント指向(NoSQL)で、データはコレクション内のJSONとして保存され、書類キャビネットの書類のようなイメージです。Postgresはリレーショナル(SQL)で、データはテーブルの行として保存され、スプレッドシートのようです。
2. コードベースのアーキテクチャ
STMSのバックエンド全体はJSONとしてデータを処理・管理するように構築されており、データベース操作にはMongoDB専用のパッケージを使用していました。したがって、単にデータベースを変えるだけでなく、アプリケーション全体のデータ処理方法を再構築する必要がありました。
3. ゼロダウンタイム要件
STMSは内部ツールとして極めて重要であるため、移行中にダウンタイムは許容できませんでした。プロセス全体を通じて、1.5百万件以上のメトリクスを毎分処理し続ける必要がありました。
4. タイトなスケジュールと経験不足
数か月以内に移行を完了しなければならず、当初は明確な実行計画がありませんでした。私も同僚もNoSQLからSQLへの大規模レガシーコードベースの移行経験がなく、Postgres自体の経験も限られていました。
5. スケールと複雑性
36のMongoDBコレクションを74のPostgresテーブルに変換する必要があり、リレーション、インデックス、クエリ最適化を慎重に検討しなければなりませんでした。
正しいORMの選択:Sequelize vs Prisma
最初の大きな決断のひとつは、ORM(オブジェクトリレーショナルマッピング)ツールを選ぶことでした。コードベースはすでにMongoDB用にMongooseを使用して設計されていたため、ORMを導入することで最もスムーズな移行パスが提供されます。
要件分析
プロジェクトのニーズを慎重に分析した結果、以下の重要基準を設定しました。
- JavaScriptパッケージであること(コードの大半がJavaScriptで書かれているため)
- Postgresとそのほとんどの機能をサポートしていること
- パフォーマンスがMongooseと同等以上であること
- オープンソースでメンテナンスされていること
候補者
徹底的な調査の結果、主に2つの候補に絞りました:Sequelize と Prisma。Dockerを使用してPostgresのテスト環境を構築し、最大かつ最も複雑なデータセットをドキュメント構造からテーブル構造へ変換しました。
テスト手法
各ORMについて、重要な操作のパフォーマンスを測定しました。
- エントリ作成時間
- エントリ更新時間
- ネストされたエントリ(リレーションやJSONキー・バリュー)の更新時間
- エントリ削除時間
- エントリ取得/クエリ時間
決定:Sequelize
2023年5月15日頃、私のユースケースではSequelizeの方が適していると判断しました。その理由は以下の通りです。
Sequelize の利点:
- 真にオープンソースで、資金提供されたスタートアップによってメンテナンスされていない
- Postgres のほとんどの機能をサポート
- 特に Prisma と比較してパフォーマンスが優れる
- 10年以上の開発実績を持つ成熟したエコシステム
- JavaScript クラスを用いた柔軟なモデル/スキーマ表現
- 正規表現を含む複雑な結合やフィルタリングオプションをサポート
パフォーマンス結果:
テストでは、Sequelize が Prisma を大きく上回りました。大規模データセットのエントリについては以下の通りです。
- Sequelize: エントリあたり約2.26秒
- Prisma: エントリあたり約11.21秒
Prisma は同ユースケースで約5倍遅く、最大データセットのエントリ1件削除に約4分かかり、要件を満たせませんでした。
Sequelize の課題:
- モデル表現がより複雑で肥大化(564行 vs Mongooseの262行)
- 特定ケースで構文が混乱しやすい
- データベースマイグレーションが複雑
- Prisma に比べてドキュメントが包括的でない
Sequelize と Prisma の長所・短所比較
以下に、評価時にまとめた両ORMの詳細な長所・短所を示します。2023年5月15日時点でのスキーマ表現やコミュニティサポートの比較も含めています。この深掘りが私の選択を確固たるものにし、同様の決断を迫られる方の参考になれば幸いです。
Sequelize の長所:
sync()
関数が自動でテーブルを作成・管理し、手作業を大幅に削減- ネストデータの複雑な結合を処理でき、STMS の構造に必須
- 正規表現を含む幅広いフィルタリングオプションをサポートし、クエリの柔軟性が高い
- モデル/スキーマはクラスベースの純粋な JavaScript で表現され、特定ニーズに高度にカスタマイズ可能
- 複数のリード接続を含むデータベース接続をシームレスに処理
- 必要に応じて生SQLクエリを実行できる
- 2023年5月15日時点のコミュニティ統計:NPM で直近14日更新、週あたり1,505,835ダウンロード;GitHub で昨日更新、フォーク4.2k、スター27.9k。MIT ライセンスで10年以上オープンソースであるため、今後も継続すると確信
Sequelize の短所:
- モデル/スキーマ表現が非常に複雑で肥大化。例として、Mongoose での大規模データセットは約262行(空白含む)だったのが、Sequelize では564行に膨らんだ
- 特定シナリオで構文が混乱しやすく、作業が遅延することがある
- データベースのマイグレーションや編集が手間。
sequelize-cli
がマイグレーションスクリプトを生成しても、依然として煩雑で、ほとんどの ORM が抱える共通の痛点 - ドキュメントが十分でないが改善中。ChatGPT が長い歴史のおかげで Sequelize に詳しく、ギャップを埋めるのに役立った
- Prisma ほど型に敏感でなく、プロジェクトによっては問題になる可能性
- TypeScript のサポートが限定的。STMS では問題にならなかったが、他のプロジェクトでは致命的になることも
Prisma の長所:
- 独自のスキーマ言語を使用し、モデル作成がよりクリーンで簡潔。比較すると、Mongoose が大規模データセットで262行だったのに対し、Prisma は221行で実現
- データベース作成とマイグレーションを簡素化する CLI ツールを提供。現時点で見た中で最も優れた ORM の一つ(完璧ではないが)
- 必要に応じて生SQLクエリをサポートし、柔軟性を確保
- コード構文がクリーンでシンプル、Sequelize に比べ学習コストが低い
- クライアントを通じて Node.js と TypeScript 用のクエリビルダーを自動生成、便利
- 優れたクリーンなドキュメント。ChatGPT の情報はやや古いが、公式ドキュメントがそれを補完
- 2023年5月15日時点のコミュニティ統計:NPM で直近6日更新、週あたり1,344,705ダウンロード;GitHub で3時間前更新、フォーク1.1k、スター31.3k
Prisma の短所:
- Postgres で正規表現フィルタリングをサポートしていないが、“contains”、“includes”、“startsWith” などの代替手段は提供
- パフォーマンスが大きな課題。大規模データセットのエントリ作成は Prisma が約11.21秒、Sequelize が約2.26秒で、約5倍遅い
- 大規模データセットの単一エントリ削除に約4分かかり、要件を満たせない
- 複雑な3層深いリレーションデータセットで公平に比較しても、削除速度は Sequelize が圧倒的に速い
- 資金調達額5650万ドルのスタートアップがバックアップ。ORM コアは Apache-2.0 のオープンソースだが、MongoDB のように将来的にライセンス変更のリスクがあると懸念
これらの詳細な比較により、Sequelize が STMS のニーズ、特にパフォーマンスと長期的信頼性に最適であることが明確になりました。同様の選択に悩む方々の参考になれば幸いです。
移行プロセス
データ構造変換
MongoDB のドキュメント構造から Postgres のリレーショナル構造への変換には綿密な計画が必要でした。私は次のことを行う必要がありました:
- Analyze Relationships: MongoDB のドキュメント同士の関係を特定し、適切な外部キー関係を設計すること
- Normalize Data: 必要に応じて入れ子になったドキュメントを別々のテーブルに分割すること
- Preserve JSON Features: 真に構造化されていないデータで柔軟性を保つ必要があるものは JSONB カラムを使用すること
- Design Indexes: クエリ性能のために適切なインデックスを作成すること
Custom Solutions
この移行にはいくつかのカスタムソリューションの開発が必要でした:
1. Data Migration Scripts
包括的なスクリプトを作成して:
- MongoDB コレクションからデータを抽出する
- ドキュメント構造をリレーショナル形式に変換する
- 適切なリレーションシップを持つ Postgres テーブルにデータをインポートする
2. API Compatibility Layer
ゼロダウンタイムを維持するために、次のことができる互換性レイヤーを構築しました:
- 移行ステータスに応じてリクエストを MongoDB または Postgres のいずれかにルーティングする
- 移行期間中のデータ整合性を確保する
- フォールバックメカニズムを提供する
3. Custom Middleware
MongoDB と Postgres が特定の操作を処理する方法の違いに対応するミドルウェアを開発し、既存の API エンドポイントが変更なしで動作し続けるようにしました。
Overcoming Technical Challenges
Handling Complex Relationships
最大の課題の一つは、MongoDB の埋め込みドキュメントを Postgres のリレーションに変換することでした。たとえば、単一の MongoDB ドキュメントには次のような内容が含まれることがあります:
- 基本的なプロパティ
- 関連エンティティを表す入れ子オブジェクト
- 埋め込みドキュメントの配列
これらは慎重に次のように分解する必要がありました:
- 主エンティティ用のプライマリテーブル
- 多対多関係用のジャンクションテーブル
- 一対多関係用の外部キーリレーションシップ
Query Optimization
MongoDB のクエリパターンは SQL に直接変換できません。私は次のことを行う必要がありました:
- 複雑な集計パイプラインを SQL のジョインに書き換える
- 新しいクエリパターンに合わせてインデックスを最適化する
- クエリ性能が MongoDB の性能を上回るか同等になるように保証する
Data Integrity
移行中のデータ整合性を確保するために必要だったこと:
- 包括的なバリデーションスクリプト
- ロールバック手順
- 移行期間中のリアルタイムデータ同期
Results & Impact
MongoDB から Postgres への STMS 移行は、ゼロダウンタイムでほぼすべての機能と機能性を維持しながら成功裏に完了しました。結果は期待を上回りました:
Performance Improvements:
- 複雑なリレーショナルクエリにおけるクエリ性能が向上した
- データの一貫性と整合性が向上した
- ストレージ利用効率が改善された
Operational Benefits:
- 監視とデバッグ機能が強化された
- eBay の既存の SQL ベースツールとの統合が向上した
- バックアップとリカバリ手順が改善された
Team Impact:
- チームのリレーショナルデータベースに関する知識が向上した
- 将来のデータベース移行のためのパターンが確立された
- 再利用可能なツールとプロセスが作成された
Technical Skills Gained
このプロジェクトにより、私の技術的専門知識は大幅に拡大しました:
Database Technologies:
- Postgres の機能と最適化に関する深い理解
- SQL クエリの最適化とパフォーマンスチューニング
- データベース設計パターンと正規化
- プライマリ‑スタンバイデータベース構成
Development Tools:
- Sequelize ORM とクエリ構築
- データベース移行戦略
- パフォーマンステスト手法
- データバリデーションと整合性チェック
Architecture Patterns:
- ゼロダウンタイム移行戦略
- API 互換性レイヤー
- データベース抽象化パターン
- 監視とアラートシステム
Personal & Professional Growth
この移行プロジェクトは、私のキャリア開発にとって変革的なものでした。未踏の領域に踏み込み、次のことが求められました:
Leadership Skills:
- 事前経験のない複雑な技術プロジェクトをリードする
- プレッシャー下で重要なアーキテクチャ決定を行う
- 複数のチームやステークホルダーと調整する
Problem-Solving Abilities:
- 複雑な問題を管理可能なコンポーネントに分解する
- 前例のない課題に対する創造的な解決策を開発する
- 複数の競合する要件と制約をバランスさせる
Communication & Teamwork:
- 非技術的ステークホルダーに技術概念を説明する
- 将来の参照のためにプロセスと決定を文書化する
- 新技術とパターンに関してチームメンバーを指導する
Lessons Learned
Technical Lessons
- Database Selection Matters: NoSQL と SQL の選択は、具体的なユースケースと長期的要件に基づくべきである
- Performance Testing is Critical: 理論的な利点が必ずしも実際のパフォーマンス向上につながるわけではない
- Migration Planning: 包括的な計画とテストは、複雑な移行に不可欠である
- Tooling Investment: 初期段階で適切なツールを構築することで、時間を大幅に節約しエラーを減らせる
Project Management Lessons
- Stakeholder Communication: 定期的な更新と明確なコミュニケーションが誤解を防止する
- Risk Management: フォールバックプランとロールバック手順を持つことが重要である
- Timeline Management: 予期せぬ課題や学習曲線のためにバッファ時間を確保する
- Documentation: 徹底した文書化が知識移転と将来の保守を可能にする
Conclusion
STMS の MongoDB から Postgres への移行は、私がキャリアで解決した中で最も挑戦的かつやりがいのある技術的問題です。技術的専門知識だけでなく、リーダーシップ、計画、適応力も必要でした。このプロジェクトの成功は、適切な計画、徹底したテスト、卓越性へのコミットメントがあれば、最も複雑な技術的課題でも克服できることを示しました。
この経験は、以下の点を強調する形で私のソフトウェアエンジニアリングへのアプローチを根本的に変えました:
- 技術的決定を下す前に、全体のコンテキストと要件を理解すること
- 適切なツールとテストに時間を投資すること
- 複雑なプロジェクト全体で明確なコミュニケーションを維持すること
- 必要に応じて新しい技術やアプローチを学ぶ意欲を持つこと
この移行の成功は STMS の能力を向上させただけでなく、eBay のインフラプロジェクト全体に利益をもたらすパターンとプロセスを確立しました。未知の課題に挑み、そこから成功を収めることが、個人とプロフェッショナルの成長に不可欠であるという信念が強化されました。
振り返ると、このプロジェクトは私のキャリアにおける転機であり、ソリューションを実装する開発者から、複雑な技術イニシアチブを設計・リードできるエンジニアへと変貌させました。この経験で得た自信とスキルは、ソフトウェアエンジニアリングにおける新たな課題や機会に取り組む際の指針となり続けています。