FastAPI + SQLAlchemy性能改善プレイブック: 遅いAPIを計測ベースで高速化する

FastAPI + SQLAlchemy性能改善プレイブック: 遅いAPIを計測ベースで高速化する FastAPIの初期実装は非常に快適です。しかし運用フェーズに入ると、次のような症状が出てきます。 一覧APIのレスポンスが急に遅くなる 同時接続が増えるとp95が跳ねる CPUは余っているのにタイムアウトが増える DB接続数が上限に張り付く こうした問題の多くは「Pythonが遅い」のではなく、SQLAlchemyの使い方とDBアクセス設計 に起因します。 本記事では、FastAPI + SQLAlchemy + PostgreSQL構成を前提に、実際の改善手順を計測ベースで整理します。 1. 最初に測るべき指標 最適化は、体感ではなく数値で進めます。最低限、以下を可視化します。 APIのp50/p95/p99レイテンシ エンドポイント別SQL発行回数 1リクエストあたりのDB滞在時間 connection pool待ち時間 slow query件数(200ms以上など) OpenTelemetryやNew Relicを使っているなら、アプリspanとDB spanを必ず紐付けてください。これだけでボトルネック特定速度が上がります。 2. N+1問題を最優先で潰す 最も頻出するのがN+1です。例えばユーザー一覧でプロフィールを参照すると、ユーザー数分の追加クエリが発行されます。 2.1 悪い例 1 2 3 4 5 6 7 8 users = session.query(User).limit(100).all() result = [] for u in users: result.append({ "id": u.id, "name": u.name, "profile": u.profile.bio, }) 2.2 改善例(joinedload/selectinload) 1 2 3 4 5 6 7 8 from sqlalchemy.orm import selectinload users = ( session.query(User) .options(selectinload(User.profile)) .limit(100) .all() ) joinedload と selectinload はデータ量で使い分けます。 ...

March 7, 2026 · 2 min · AI2CORE 編集部

PostgreSQL PITR復旧訓練ガイド: バックアップがあるのに戻せないを防ぐ実践手順

PostgreSQL PITR復旧訓練ガイド: バックアップがあるのに戻せないを防ぐ実践手順 PostgreSQL運用で最も危険なのは「バックアップがある」という安心感です。実際の障害では、バックアップ自体より 復旧手順の不整合 で時間を失います。たとえば、WAL保管期間が足りず目標時刻に戻せない、暗号鍵が見つからず復号できない、復旧後の整合性確認が曖昧で再開判断ができない、といった問題です。 本記事では、PostgreSQLの Point-in-Time Recovery(PITR)を、机上ではなく本番レベルで回すための実装手順を解説します。pgBackRest を例にしていますが、考え方は他ツールでも共通です。 1. PITRの前提: 3つ揃わないと復旧できない PITRは次の3要素で成立します。 ベースバックアップ(フルまたは差分) WALアーカイブ(継続的) 目標時刻情報(いつまで戻すか) どれか1つでも欠けると成立しません。特に本番で多いのは「WALが途中で消えていた」ケースです。S3保存していても、ライフサイクル設定や権限変更で欠落することがあります。 2. まず決めるべきRTO/RPO 技術論の前に、業務要件を決めます。 RTO(復旧に許容される時間): 例 60分 RPO(失ってよいデータ時間): 例 5分 この2つで設計が変わります。 RPO 5分以内ならWALアーカイブ遅延監視が必須 RTO 60分以内なら復旧訓練を定期実施し、手順を自動化する必要あり 要件不明のまま「毎日バックアップ」だけ実施しても、障害時に役立たないことが多いです。 3. 推奨アーキテクチャ(単一リージョンの最小構成) DBサーバ: PostgreSQL 15/16 バックアップツール: pgBackRest 保存先: S3互換ストレージ(バージョニングON) 監視: Prometheus + Alertmanager 復旧先: 別ホスト(本番と同一ネットワーク) 重要なのは、本番DBと別ホストで実際に復旧できること を定期検証する点です。 4. 実装手順(pgBackRest) 4.1 PostgreSQL設定 postgresql.conf 例: wal_level = replica archive_mode = on archive_command = 'pgbackrest --stanza=main archive-push %p' max_wal_senders = 10 wal_compression = on archive_command は失敗時に非0を返す必要があります。ここが曖昧だとWAL欠落に気づけません。 ...

March 6, 2026 · 2 min · AI2CORE 編集部

PostgreSQL接続プール枯渇の実戦対処:再発防止までつなげる調査・改善プレイブック

PostgreSQL接続プール枯渇の実戦対処:再発防止までつなげる調査・改善プレイブック 本番障害でよくあるのが、too many clients already や remaining connection slots are reserved です。アプリ側から見ると「急にDBに繋がらない」、ユーザー側から見ると「全機能が遅い・失敗する」という最悪の体験になります。 厄介なのは、接続枯渇が「DBサーバー性能不足」だけで起こるわけではない点です。リーク、タイムアウト設定、長時間トランザクション、プールサイズ不整合など、複数要因が重なって起きます。 この記事では、接続枯渇に対して 発生時の初動 → 根本原因の特定 → 恒久対策 の順で、手順を実務レベルでまとめます。 1. まず初動:サービス継続を優先する 障害対応では、完璧な原因究明より「止血」が先です。以下を順番に実施します。 直近リリース有無を確認(機能フラグ含む) アプリの接続数・待機数・エラー率を確認 DB側で pg_stat_activity を取得 長時間実行クエリを必要に応じて停止 一時的にアプリ Pod 数を制限して雪だるま増幅を止める pg_stat_activity の基本クエリ: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT pid, usename, application_name, client_addr, state, wait_event_type, wait_event, now() - query_start AS query_duration, now() - xact_start AS xact_duration, left(query, 120) AS query_head FROM pg_stat_activity WHERE datname = current_database() ORDER BY xact_start NULLS LAST, query_start NULLS LAST; ここで見るべきは、state='idle in transaction' と異常に長い xact_duration です。これがあるとコネクションを握ったまま解放されず、枯渇の引き金になります。 ...

March 5, 2026 · 2 min · AI2CORE 編集部

PostgreSQL肥大化対策の実務:VACUUM/Autovacuum/Index再編成を止めずに回す運用プレイブック

PostgreSQL肥大化対策の実務:VACUUM/Autovacuum/Index再編成を止めずに回す運用プレイブック PostgreSQL を長期運用すると、遅かれ早かれぶつかるのが bloat(テーブル/インデックス肥大化)です。CPU やメモリを増やしても、実体は不要領域の蓄積なので、根本原因を処理しない限り性能は戻りません。 本記事では、サービス停止なしで bloat を抑える運用を目標に、Autovacuum 設計、監視、メンテ手順を実践ベースで解説します。 1. なぜ肥大化が起きるのか PostgreSQL は MVCC を採用しているため、UPDATE/DELETE で古い行バージョンが即時削除されません。不要バージョンは VACUUM で回収されますが、追いつかないと肥大化します。 肥大化が進むと以下が起こります。 同じデータ量でも I/O が増える インデックス探索が遅くなる キャッシュ効率が落ち、p95 レイテンシが悪化 自動メンテの時間がさらに伸びる(悪循環) 重要なのは、「遅くなってから対処」だと回復コストが高いという点です。 2. 最初に見るべき指標 運用でまず可視化するのは次の4つです。 n_dead_tup(死んだタプル数) last_autovacuum(最後に vacuum が走った時刻) テーブルサイズ・インデックスサイズ推移 age(relfrozenxid)(XID 消費進行) 確認クエリ例: 1 2 3 4 5 6 7 8 9 10 SELECT schemaname, relname, n_live_tup, n_dead_tup, last_autovacuum, last_vacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; XID の健全性チェック: ...

March 4, 2026 · 2 min · AI2CORE 編集部

PostgreSQLデッドロック調査プレイブック:再現・可視化・恒久対策までの実践手順

PostgreSQLデッドロック調査プレイブック:再現・可視化・恒久対策までの実践手順 本番運用で厄介なのは、エラーが「たまに」しか出ない障害です。PostgreSQL のデッドロックはその代表で、発生頻度は低くてもビジネス影響が大きいことが多いです。決済や在庫更新で発生すると、リトライが雪だるま式に増え、アプリ全体の遅延を引き起こします。 本記事では、デッドロック発生時に現場でそのまま使える手順を、初動対応・再現・恒久対策の順で整理します。 1. まず理解すべき前提 デッドロックは「どちらかが悪い」ではなく、ロック順序が循環したときに必ず起きる現象です。PostgreSQL は循環を検出すると、どちらか一方のトランザクションを強制中断します。 典型的な症状: ERROR: deadlock detected API の一部がランダムに 500 を返す リトライ実装により DB 負荷が上振れ ここで重要なのは、単純なタイムアウトと混同しないことです。タイムアウトは待ち時間超過、デッドロックは循環待ちです。対策が違います。 2. 初動でやること(5〜15分) 2-1. エラーログの採取 まず、DB 側ログに詳細を出す設定があるか確認します。 1 2 3 SHOW log_lock_waits; SHOW deadlock_timeout; SHOW log_min_error_statement; 推奨設定(本番): log_lock_waits = on deadlock_timeout = '1s' log_min_error_statement = error deadlock_timeout を短めにすることで、待ちが長引いたケースの追跡がしやすくなります。 2-2. 現在のロック状況を確認 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT a.pid, a.usename, a.application_name, a.state, a.query, l.locktype, l.mode, l.granted, a.query_start FROM pg_stat_activity a JOIN pg_locks l ON a.pid = l.pid WHERE a.datname = current_database() ORDER BY a.query_start; 見るべき点は「長く生きているトランザクション」と「granted = false が連鎖している箇所」です。 ...

March 2, 2026 · 2 min · AI2CORE 編集部

PostgreSQLインデックス最適化の現場手順:遅いクエリを再現・診断・改善する実践プレイブック

PostgreSQLインデックス最適化の現場手順:遅いクエリを再現・診断・改善する実践プレイブック 「CPUは余っているのに画面が遅い」「特定時間帯だけ API が詰まる」。この手の問題の多くは、アプリではなく SQL の実行計画に原因があります。特に PostgreSQL では、インデックス設計と統計情報の状態が性能をほぼ決めます。 本記事では、実務で使う手順に沿って、遅延クエリの改善を再現可能な形で解説します。単なる理論紹介ではなく、調査順序、判断基準、リリース時の注意点まで含めてまとめます。 まず守るべき3原則 推測でインデックスを作らない 体感で追加すると write 性能とストレージが悪化します。必ず実行計画を見てから判断します。 改善前後を数値で比較する P95、rows、shared read blocks を記録し、効果を証明します。 本番反映は CONCURRENTLY を基本にする テーブルロックで事故らないため、CREATE INDEX CONCURRENTLY を優先します。 ケース設定:注文一覧APIが遅い 次のクエリが遅いとします。 1 2 3 4 5 6 7 SELECT id, user_id, status, total_amount, created_at FROM orders WHERE tenant_id = $1 AND status IN ('paid', 'shipped') AND created_at >= NOW() - INTERVAL '30 days' ORDER BY created_at DESC LIMIT 50; データ量は orders 1.2億件、1テナントあたり数百万件。現象は「特定テナントだけ 3〜6 秒」です。 ...

February 27, 2026 · 2 min · AI2CORE 編集部

Supabaseで構築するスケーラブルなデータベース基盤

Supabaseで構築するスケーラブルなデータベース基盤 はじめに 「バックエンドの開発速度を上げたい」「認証やリアルタイム機能を手軽に実装したい」——こうした要求に応えるBaaS (Backend as a Service) は、現代のアプリケーション開発において不可欠な存在です。その代表格であるFirebaseは、多くのプロジェクトで採用され、開発者に多大な恩恵をもたらしてきました。 しかし、プロジェクトが成長し、データ構造が複雑化するにつれて、このような課題に直面したことはないでしょうか? 「Firebase (Firestore) のスキーマレスな性質が、逆にデータ整合性の維持を難しくしている…」 「複雑なデータ検索や集計を行いたいが、NoSQLのクエリでは表現力に限界がある…」 「ベンダーロックインが心配だ。将来的にインフラを移行する必要が出たときに、身動きが取れなくなるのではないか?」 「リレーショナルなデータを扱うには、Firestoreは最適とは言えないかもしれない…」 もし、あなたがこれらの課題に少しでも心当たりがあるなら、この記事はあなたのためのものです。 本記事では、「オープンソースのFirebase代替」として注目を集めるSupabaseを取り上げます。Supabaseは、単なるFirebaseのクローンではありません。その核には、40年以上の歴史と絶大な信頼性を誇るリレーショナルデータベースPostgreSQLが据えられています。 この記事を読み終える頃には、あなたはSupabaseがなぜスケーラブルで堅牢なデータベース基盤を構築するための強力な選択肢となるのか、そしてPostgreSQLの力を最大限に活用して、高速な開発と長期的な運用性を両立させる方法を深く理解できるでしょう。 なぜSupabaseが今、注目されているのか? - 背景と課題 Supabaseの魅力を理解するためには、まずBaaS市場の変遷と、既存のサービスが抱える課題を理解する必要があります。 BaaSの進化とFirebaseがもたらした革命 かつて、Webアプリケーションを開発するには、サーバーのプロビジョニング、データベースのセットアップ、APIサーバーの実装、認証システムの構築など、多くの定型的な作業が必要でした。 BaaSは、これらのバックエンド機能を汎用的なサービスとして提供することで、開発者がフロントエンドやアプリケーションのコアロジックに集中できるようにしました。中でもGoogleのFirebaseは、直感的なAPI、リアルタイムデータベース、強力な認証機能、ホスティングまでをワンストップで提供し、特にモバイルアプリやプロトタイピングの領域で圧倒的な支持を得ました。 Firebase (Firestore) が抱えるスケーラビリティの課題 Firebaseの成功は、その手軽さと開発速度にありました。しかし、プロジェクトが成長し、エンタープライズレベルの要件が求められるようになると、そのアーキテクチャに起因するいくつかの課題が顕在化します。 NoSQLデータベースの限界: Firebaseの主要なデータベースであるFirestoreは、ドキュメント指向のNoSQLデータベースです。スキーマレスであるため初期開発は迅速ですが、データ間の複雑なリレーションを扱うのが苦手です。例えば、SNSアプリケーションで「ユーザー」と「投稿」と「コメント」と「いいね」が複雑に絡み合うようなデータモデルを考えたとき、正規化されたリレーショナルデータベースであればJOIN一発で取得できるデータも、Firestoreでは複数回のクエリやデータの非正規化といった工夫が必要になり、コードの複雑化やデータ冗長性を招きます。 クエリの表現力不足: SQLのように柔軟で強力なクエリ言語を持たないため、複雑な条件での絞り込み、集計、ソートといった操作に制限があります。GROUP BYやHAVINGのような集計関数を使いたい場合、Cloud Functionsなどを駆使して自前で実装する必要があり、リアルタイム性やパフォーマンスが犠牲になることも少なくありません。 ベンダーロックインへの懸念: Firebaseは非常に優れたエコシステムですが、それはGoogle Cloud Platformに深く統合されています。一度Firebaseで大規模なシステムを構築すると、データベースの移行や、他のクラウドサービスとの連携が困難になる「ベンダーロックイン」のリスクが常に伴います。データのエクスポートは可能ですが、セキュリティルールやCloud Functionsで記述したビジネスロジックまで含めた完全な移行は、極めて困難です。 これらの課題は、「開発の初期段階では最高のツールだが、長期的にスケールさせるには不安が残る」という評価につながっていました。 RDBへの回帰とSupabaseの登場 このような背景の中、開発者コミュニティでは、データの整合性、トランザクションの信頼性、そしてSQLという標準化された強力なクエリ言語を持つリレーショナルデータベース (RDB) の価値が再評価されるようになります。 そこに登場したのがSupabaseです。Supabaseは、この流れを見事に捉えました。 「世界で最も信頼されているオープンソースRDBであるPostgreSQLを使い、Firebaseのような開発者体験を提供する」 このコンセプトが、多くの開発者の心を掴んだのです。Supabaseは、BaaSの手軽さと、RDBの堅牢性・柔軟性という、これまでトレードオフの関係にあると考えられていた2つの要素を、見事に両立させました。 SupabaseのアーキテクチャとPostgreSQLの強力な機能 Supabaseが単なるデータベースサービスではないことを理解するために、そのアーキテクチャを見ていきましょう。Supabaseは、既存の優れたオープンソースツール群をPostgreSQLを中心に統合した、いわば「バックエンドのオーケストラ」です。 +--------------------------------+ | Your Application | | (Web, Mobile, etc.) | +--------------------------------+ | | | | (SDK) | (SDK) | +------------------------+---------+---------+--------------------------+ | Supabase Platform (Hosted or Self-hosted) | | | | +-----------+ +-------------+ +-----------+ +---------+ +----------+ | | Auth | | Realtime | | Storage | | Edge | | REST API | | | (GoTrue) | | (Realtime) | | (S3-comp) | | Functions| |(PostgREST)| | +-----------+ +-------------+ +-----------+ +---------+ +----------+ | | | | | | | +-----------------+---------------+---------------+-----------+ | | | +---------------------+ | | PostgreSQL | <-- THE CORE | | (Database, RLS, | | | Functions, Exts) | | +---------------------+ +-------------------------------------------------------------------------+ PostgreSQL: すべての中心です。単なるデータストアではなく、認証情報、セキュリティポリシー、ビジネスロジック(関数)まで、すべてがここに集約されます。 GoTrue: JWTベースの認証サーバー。ユーザー管理とアクセストークン発行を担当します。ユーザー情報はPostgresのauth.usersテーブルに保存されます。 PostgREST: データベーススキーマを読み取り、自動的にRESTful APIを生成します。テーブルやビューを作成するだけで、即座に対応するAPIエンドポイントが利用可能になります。 Realtime: Postgresの論理レプリケーション機能を利用して、データベースの変更をリアルタイムにクライアントにWebSocket経由で配信します。 Storage: S3互換のオブジェクトストレージ。Postgresを使って権限管理を行います。 Edge Functions: Denoで書かれたサーバーレス関数。データベースに近い場所でカスタムロジックを実行できます。 このアーキテクチャの最大のポイントは、すべてがPostgreSQLに根ざしていることです。これにより、PostgreSQLが持つ強力な機能を最大限に活用できるのです。 ...

February 23, 2026 · 5 min · AI2CORE 編集部