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 編集部

GitHub Actions高速化実践:Matrix戦略・依存キャッシュ・失敗切り分けの設計ガイド

GitHub Actions高速化実践:Matrix戦略・依存キャッシュ・失敗切り分けの設計ガイド GitHub Actions は便利ですが、プロジェクトが成長すると「遅い」「不安定」「原因が分かりにくい」という三重苦になりがちです。特に monorepo や複数ランタイム対応(Node/Python/Go など)では、ワークフローの設計次第で CI 時間が 2〜3 倍変わります。 本記事では、実行時間を短くしながら失敗時の調査コストも下げるために、matrix 設計・キャッシュ設計・障害時の確認順序を具体的に整理します。 1. まず「何を並列化するか」を決める Actions の高速化は、いきなりキャッシュ最適化から入るより、先にジョブ分解を決める方が効きます。原則は次の通りです。 並列化すべき: 独立テスト(OS/バージョン別、サービス別) 直列にすべき: デプロイ、DB マイグレーション、本番反映 依存を分ける: lint/typecheck/test/build を一つに詰め込まない 悪い例は、1ジョブに全部詰め込み、失敗時に最初から再実行するパターンです。良い設計では「lint は通るが test だけ失敗」のように切り分けできます。 2. matrix を作るときの実践ルール matrix は便利ですが、組み合わせ爆発で逆に遅くなることがあります。例えば os x runtime x db をすべて直積にすると、不要なジョブが大量発生します。そこで include/exclude を活用します。 1 2 3 4 5 6 7 8 9 10 11 12 strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] node: [20, 22] include: - os: ubuntu-latest node: 22 coverage: true exclude: - os: macos-latest node: 20 ポイントは次です。 ...

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

Kubernetesキャパシティ設計実践:HPA/VPA/Cluster Autoscalerを衝突させない運用術

Kubernetesキャパシティ設計実践:HPA/VPA/Cluster Autoscalerを衝突させない運用術 Kubernetes は「自動でスケールするから安心」と思われがちですが、実運用では逆です。HPA、VPA、Cluster Autoscaler(CA)の設定が噛み合わないと、スケールアウトと再スケジューリングが衝突し、レイテンシ悪化やコスト増大を引き起こします。 本記事では、3つのオートスケーリング機構を同時運用する際の設計ポイントを、障害対応目線で整理します。 1. 役割分担を明確にする まず前提として、各コンポーネントの責務を固定します。 HPA: Pod 数を短期的に増減 VPA: Pod あたりの requests/limits を中長期で最適化 CA: ノード数を増減 この役割分担が曖昧だと、同じ問題を複数レイヤーで同時に解こうとして不安定化します。特に Web/API ワークロードでは、HPA を主軸、VPA は recommendation 中心で始めるのが安全です。 2. requests/limits が崩れていると全て失敗する HPA の CPU 指標は requests 基準で計算されます。requests が不正確だと、HPA の判断もズレます。最初にやるべきは次です。 過去 2 週間の実使用量を可視化 p95 使用量を requests の初期値に設定 limits は requests の 1.5〜2 倍で開始 極端に低い requests は「見かけの高負荷」を作り、不要スケールを誘発します。逆に高すぎる requests は CA の過剰増設を招きます。 3. HPA 指標選定の実践 CPU だけで運用すると、I/O 待ちや外部 API 待ちのボトルネックを見逃します。推奨は複合指標です。 CPU Utilization(基本) メモリ使用率(リーク監視) RPS あたりレイテンシ(SLO 接続) Queue 長(非同期処理) autoscaling/v2 では複数メトリクスを扱えるため、最初から設計しておくと後で楽です。 ...

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

OpenTelemetry実践導入ガイド:ログ・メトリクス・トレース統合を90日で定着させる

OpenTelemetry実践導入ガイド:ログ・メトリクス・トレース統合を90日で定着させる 「監視は入れているのに障害原因の特定が遅い」。この状態は、たいていデータが足りないのではなく、データが分断されていることが原因です。メトリクスは見える、ログは別画面、トレースは導入途中、という構成だと、オンコールは毎回同じ調査を手作業で繰り返すことになります。 OpenTelemetry(OTel)はこの分断を減らすための共通規格です。ただし、導入に失敗するチームも少なくありません。理由は単純で、「計測の追加」だけやって「運用設計」を後回しにするからです。 本記事では、OpenTelemetry を 90 日で現場定着させるための、実務寄りの導入手順を紹介します。 1. まず決めるべき運用目標 OTel を入れる前に、次の問いに答えます。 どの障害をどれだけ早く見つけたいか どのサービスの MTTR をどれだけ下げたいか どのチームがトリアージ責任を持つか たとえば「API 5xx の原因調査を 60 分 → 15 分に短縮する」と明文化すると、必要な計測が決まります。逆に目標がないと、span を増やす作業が目的化して終わります。 2. 参照アーキテクチャ 本番で扱いやすい最小構成は次です。 アプリケーションに OTel SDK を導入 エージェント/サイドカー経由で OTel Collector に送信 Collector で加工・サンプリング・ルーティング Prometheus / Loki / Tempo(または商用基盤)へ出力 Collector を中継に置く理由は、アプリ側の再デプロイなしでルール変更できるからです。運用現場ではここが非常に効きます。 3. サービス命名規則を最初に固定する 命名規則を後で直すと、ダッシュボードとアラートが壊れます。以下は最低限のルール例です。 service.name: domain-service-env(例: billing-api-prod) deployment.environment: prod|stg|dev service.version: Git SHA または semver cloud.region: 実リージョン名 この 4 つが揃うと、障害時に「どの環境・どのバージョン」が悪いか一気に絞れます。 4. Pythonサービス計測の実装例 FastAPI を例に、最小導入手順を示します。 1 2 3 4 pip install opentelemetry-distro \ opentelemetry-exporter-otlp \ opentelemetry-instrumentation-fastapi \ opentelemetry-instrumentation-requests 起動時に auto-instrumentation を有効化します。 ...

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

Terraformドリフト検知プレイブック:本番事故を防ぐCI設計と運用手順

Terraformドリフト検知プレイブック:本番事故を防ぐCI設計と運用手順 Terraform を導入していても、運用が進むほど「実環境がいつの間にかコードとズレる」問題にぶつかります。いわゆるドリフトです。最初は小さな差分でも、放置すると本番変更時に予期せぬ差分が混ざり、障害やリリース遅延の原因になります。 本記事では、Terraform ドリフト検知を単なる terraform plan 実行で終わらせず、継続運用できる仕組みとして実装するための具体策をまとめます。対象は AWS を例にしますが、考え方は他クラウドでも共通です。 1. ドリフト検知で最初に決めるべきこと 多くのチームが失敗するのは、実装前に運用設計を決めないことです。まず以下を決めます。 どの環境をいつ検知するか(prod は毎日、stg は平日など) 検知結果をどこに通知するか(Slack/Discord/Issue) 誰がいつまでに対応するか(当番制、SLA) 「意図した手動変更」をどう扱うか(例外ラベル、期限付き) ここを決めずに CI だけ作ると、通知がノイズ化して無視されます。ドリフト検知は技術課題より運用課題です。 2. リポジトリ構成と state 分離 最小限、次のような構成を推奨します。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 infra/ modules/ vpc/ ecs/ rds/ envs/ prod/ main.tf backend.hcl variables.tf stg/ main.tf backend.hcl .github/ workflows/ terraform-drift.yml 環境ごとに backend と state を分けることが重要です。ドリフト検知ジョブが state を誤って参照すると、存在しない差分が出ます。S3 backend + DynamoDB lock を使う場合は、bucket/key/region/table の整合性を必ず固定化します。 ...

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

Redisキャッシュスタンピード対策ガイド:高負荷時にDBを守る設計と実装

Redisキャッシュスタンピード対策ガイド:高負荷時にDBを守る設計と実装 Redis を使っていても、ピークトラフィック時に DB が突然落ちることがあります。原因の多くはキャッシュスタンピードです。人気キーの TTL が同時に切れると、大量リクエストが一斉に DB へ流れ、接続プールが飽和します。 「Redis を入れたのに遅い」「ピーク時だけ 500 が増える」という現象は、このパターンで説明できることが非常に多いです。 本記事では、キャッシュスタンピードを実運用で防ぐために、設計原則・実装パターン・監視方法を順に解説します。 1. キャッシュスタンピードとは何か 典型シナリオ: 商品ランキング API が ranking:daily を Redis に 300 秒で保存 300 秒後、人気時間帯にキー期限切れ 同時に 1000 リクエストが miss 1000 回 DB 集計が走ってレイテンシ急増 このとき Redis 自体は正常でも、背後の DB が壊れます。つまり、問題はキャッシュ障害ではなく「再生成の同時実行制御」です。 2. 防御の基本は三層構え スタンピード対策は単一施策では不十分です。次の三層を組み合わせると安定します。 同時再生成の抑制(singleflight / 分散ロック) 期限切れの分散(TTL ジッター) 期限切れ後の挙動制御(stale-while-revalidate) 3. パターン1: singleflight で同時再生成を止める 同一キーの miss が同時発生しても、1 リクエストだけ再生成し、他は待つ設計です。 TypeScript 例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const inflight = new Map<string, Promise<string>>(); async function getOrCompute(key: string, ttlSec: number, compute: () => Promise<string>) { const cached = await redis.get(key); if (cached) return cached; if (!inflight.has(key)) { const p = (async () => { try { const value = await compute(); await redis.set(key, value, { EX: ttlSec }); return value; } finally { inflight.delete(key); } })(); inflight.set(key, p); } return await inflight.get(key)!; } 単一プロセスではこれで十分ですが、複数インスタンス構成では分散ロックも必要です。 ...

March 2, 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 編集部

GitHub Actions再利用ワークフロー運用設計:属人化を防ぎつつ開発速度を上げる実践ガイド

GitHub Actions再利用ワークフロー運用設計:属人化を防ぎつつ開発速度を上げる実践ガイド 複数リポジトリを運用していると、ほぼ同じ CI 設定を各リポジトリにコピーし続ける状態になりがちです。最初は早く見えますが、半年後には「どこに正解があるのかわからない」状態になります。セキュリティパッチを当てたいだけなのに 20 リポジトリを横断修正し、1つだけ取りこぼして監査で指摘される、というのは珍しくありません。 この問題に効くのが GitHub Actions の workflow_call を使った再利用ワークフローです。ただし、単に共通化するだけでは逆に運用事故が増えることがあります。重要なのは、共通化の粒度、権限境界、変更リリース方法を最初に設計することです。 本記事では、実運用で詰まりやすいポイントを中心に、導入から定着までを具体的に解説します。 1. 再利用ワークフローの基本方針 まず押さえるべき方針は次の 3 つです。 再利用ワークフローは「プラットフォーム製品」として扱う 呼び出し側(各アプリ repo)は薄く保つ 破壊的変更はバージョンを切って段階移行する 「共通化=1ファイルに全部詰め込む」ではありません。lint, test, build, deploy を1個にまとめると、対象外プロジェクトまで影響します。まずは小さく分割し、必要なものだけ組み合わせられる構造にします。 2. 推奨ディレクトリ構成 共通ワークフローを専用 repo に分離しておくと、監査や変更履歴の管理が容易になります。 1 2 3 4 5 6 7 8 9 org-ci-workflows/ .github/workflows/ ci-node.yml ci-python.yml security-scan.yml release-tag.yml docs/ onboarding.md migration-checklist.md 呼び出し側は以下のように最小化します。 ...

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

MCPサーバー本番設計ガイド:AIエージェント連携を安全・安定に運用するアーキテクチャ

MCPサーバー本番設計ガイド:AIエージェント連携を安全・安定に運用するアーキテクチャ MCP(Model Context Protocol)は、LLM と外部ツールを接続する強力な仕組みです。便利な一方で、本番運用では「権限の過剰付与」「監査不能」「障害時の暴走」が起きやすく、設計を誤ると一気にリスクが跳ね上がります。 本記事では、MCP サーバーを業務利用する前提で、安全性・可観測性・運用性を満たす設計パターンをまとめます。PoC から本番へ上げる際のチェックリストとして使える構成にしています。 1. MCP本番運用で先に決めるべきこと 最初に決めるべきは、技術スタックではなく「権限境界」です。 どのエージェントが、どのツールを使えるか 書き込み系操作(作成・更新・削除)の承認方式 外部送信(メール、投稿、通知)の監査ルール 失敗時の停止条件(fail-open か fail-closed か) ここを決めずに実装を始めると、あとから制約を入れられず、結果として運用停止になります。 2. 推奨アーキテクチャ:Control Plane と Tool Plane の分離 MCP 構成は最低でも2層に分けると安全です。 Control Plane: 認証、認可、監査、レート制御 Tool Plane: 実際のツール実行(DB、GitHub、Browser、Messaging) 2-1. なぜ分離するのか Tool 実装に認可ロジックを埋め込むと、ツール追加のたびにセキュリティ品質がブレます。Control Plane で一元化すれば、ポリシー変更時も1箇所で反映できます。 2-2. リクエストフロー例 1 2 3 4 Agent -> MCP Gateway(Control Plane) -> Policy Engine (allow/deny, scope check) -> Tool Adapter (Tool Plane) -> Audit Logger deny の場合も必ず監査ログに記録し、試行の痕跡を残します。 ...

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

Python asyncioバックプレッシャー設計:落ちない非同期バッチを作る実装パターン

Python asyncioバックプレッシャー設計:落ちない非同期バッチを作る実装パターン asyncio は速く作れる一方で、負荷が上がった瞬間に崩壊する設計を作りやすいという側面があります。特に「処理待ちが無限に積み上がる」「外部API遅延で全体が詰まる」「リトライ嵐でさらに遅くなる」は典型的です。 本記事では、非同期ワーカーを本番運用する前提で、バックプレッシャーを実装に落とす方法を解説します。単なる概念ではなく、すぐ使えるコード断片を中心に進めます。 1. なぜバックプレッシャーが必要か バックプレッシャーは「これ以上は受けない」仕組みです。これがない設計は、ピーク時に次の順で壊れます。 入力が処理速度を超える キューが無限増加してメモリ圧迫 GC増加でスループット低下 タイムアウト増加→リトライ増加 システム全体が雪崩れる つまり、受けすぎないことは性能ではなく可用性の話です。 2. 基本設計:3つの制限を必ず入れる 2-1. キュー上限(bounded queue) 1 2 3 4 import asyncio QUEUE_MAX = 1000 queue: asyncio.Queue[dict] = asyncio.Queue(maxsize=QUEUE_MAX) maxsize なしは原則禁止です。業務要件で「捨てられない」場合でも、無限キューより「受け付け停止 + 明示エラー」のほうが復旧可能です。 2-2. 同時実行数上限(semaphore) 1 2 3 4 5 6 CONCURRENCY = 20 semaphore = asyncio.Semaphore(CONCURRENCY) async def guarded_call(fn, *args, **kwargs): async with semaphore: return await fn(*args, **kwargs) CPU でも I/O でも、同時実行数に上限を持たせると遅延の尾が短くなります。 ...

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