← 一覧に戻る

baseballnext-operation

GitHub ↗ 最終push: 2026/5/9 19:37

WIP(現在進行中)

Work In Progress

このプロジェクトで現在進行中の作業と、過去のスナップショットを記録する。

現在の状況

目標: RDS 統合プロジェクトは 完了。残作業は別件改善+スナップショット整理。

進捗:

  • 2026-05-09 に baseballnext RDS を footballnext RDS(db.t4g.small)へ別データベースとして統合完了
  • 旧 baseballnext RDS は同日削除済み
  • アプリ/cron は新 RDS 側で書き込み・読み取りとも正常動作確認済み
  • 月額 約 $15〜19(約 2,200〜2,800円)削減見込み(micro インスタンス+EBS 20GB+Public IP)
  • 5/16 17:00 に dev-timer #16 で「保険スナップショット削除可否確認」リマインダー登録済み

残っているスナップショット(保険):

  • baseballnext-pre-cleanup-20260429-1323(cleanup 直前)
  • baseballnext-pre-micro-20260501-1540(micro 化直前)
  • baseballnext-pre-merge-20260509-1832(統合直前)
  • 削除時の最終スナップショット
  • 5/16 までは保険として残し、その時点で問題なければ削除

次にやること(優先度順):

  1. 5/16 のリマインダー発火 → スナップショット削除判断
  2. 別件改善:
    • app/Config/core.phpdebug=20(本番ではデバッグ出力を抑制)
    • app/Config/database.php の認証情報を環境変数化(過去履歴に残った旧 baseballnext 接続情報のローテーションも視野)
    • RDS SG 0.0.0.0/0:3306 を必要最小に絞る
  3. EC2 nano 2台 → 1台化(保留中、コスト効果 月 約 $9.5)

詰まっていること・未決事項:

  • 特になし

運用メモ(更新版):

  • 現在の RDS 接続先: footballnext.ckdbljv81o1g.ap-northeast-1.rds.amazonaws.com(DB名 baseballnext
  • master user は ichirokisanuki(特権操作はこちら)、アプリ用は baseballnext@%(baseballnext DB のみ)
  • footballnext RDS は実は multi-tenant(footballnext, machiga, schulte, kowai, sp_world, search_article, tmp, baseballnext が同居)
  • VPC 内アクセス: cron EC2 (52.194.87.168) 経由で SSH トンネル
    • 13306 → baseballnext.:3306(旧、削除済みなので不要)
    • 13307 → footballnext.:3306(現役)
  • master 権限が必要なメンテ操作は cron EC2 上で Docker mysql:8.4 経由で実行する方式が確立(AL1 の mysql 5.5 client では新仕様非対応)
  • 退避テーブル old_articles / old_article_each_view_relations は cleanup 後に件数が 1,000件規模に縮小されている

過去のWIPアーカイブ

2026-05-01 17:30 時点のスナップショット

目標: RDS micro 化は完了済み、articles 自動退避ジョブも実装済み。安定運用の見守り+別件改善フェーズ。

進捗:

  • RDS インスタンスクラス: db.t4g.micro で運用中(2026-05-01 15:50 切替完了)。1時間後の観察で完全安定を確認。
  • articles 自動退避ジョブ実装済み:
    • CronController::archiveOldArticles() を追加(baseballnext-server リポ側)
    • cron.txt0 3 * * * /cron/archiveOldArticles を追加
    • 1回 1000件 / 5年境界で日次に古い articles を old_articles / old_aevr へ退避
    • 本番 crontab への反映はユーザ側で実施(コードのデプロイも同様)
  • 事前のクリーンアップ+micro 化+自動退避ジョブで、当面のメモリ/ディスク逼迫リスクは概ね解消。

次にやること:

  1. 自動退避ジョブの本番デプロイ&動作確認
  2. 数日〜1週間スパンで micro 安定運用の見守り
  3. 別件改善: core.php debug、database.php 認証情報、SG最小化

詰まっていること・未決事項:

  • micro の innodb_buffer_pool_size が事前予想 768MB ではなく 256MB で割り当てられた理由は未調査(実害は出ていないので優先度低)。

2026-04-29 14:30 時点のスナップショット

目標: RDS baseballnext を db.t4g.small → db.t4g.micro へグレードダウンできるか判断する。

進捗:

  • performance_schema 有効化済み(2026-04-29 13:07 RDS再起動完了)。Performance Insights 系メトリクスが蓄積中。
  • 5/1 13:09 に dev-timer #8 でリマインダー登録済み。
  • micro 化を待たずにできる DB クリーンアップを先行で実施(2026-04-29 13:20〜14:30):
    • 遺物テーブル4本DROP、FULLTEXT 2本DROP
    • articles から5年以前のレコード(150万行)を old_articles へ退避
    • 関連 article_each_view_relations(343万行)を old_article_each_view_relations へ退避
    • OPTIMIZE TABLE 実行
    • 結果: 現役テーブル 2,225MB → 958MB(−57%)、articles インデックスが 1,237MB → 475MB に縮小
  • articles インデックスが micro (buffer pool 約768MB) に十分乗る規模になったので、移行成功の見込みが大きく上がった。

次にやること:

  1. 5/1 リマインダー発火 → Performance Insights / FreeableMemory / バッファプールヒット率の改善を確認
  2. 効果が見えたら micro へインスタンスクラス変更(pending-reboot or apply-immediately)
  3. 別件として database.php の認証情報管理改善、core.php の debug 設定見直し

2026-04-29 13:14 時点のスナップショット

目標: RDS baseballnext を db.t4g.small → db.t4g.micro へグレードダウンできるか判断する。

進捗:

  • 直近7日のCloudWatchメトリクスは取得済み。CPU/IO/接続数は micro でも余裕あり、唯一 FreeableMemory(min 54MB)だけが論点。
  • パラメータグループ general-mysql84 の主要メモリ設定は DBInstanceClassMemory 基準の動的式なので、micro へ落とせば自動でスケールダウンする(buffer pool は約768MB、max_connections は約85になる見込み)。
  • performance_schema0→1 に有効化済み(2026-04-29 13:07 RDS再起動完了、in-sync 確認済み)。今からPerformance Insights系メトリクスが蓄積され始める。
  • 5/1 13:09 に dev-timer #8 でリマインダー登録済み。

次にやること:

  1. 5/1 のリマインダー発火後、buffer cache hit ratio などのメトリクスを再収集
  2. それで判断材料が足りなければ、② MySQL に直接接続してバッファプール内訳・テーブルサイズを実測(接続経路:cron EC2 経由のSSHトンネルが第一候補)
  3. *_backup* / temp_* / test_* テーブル・未使用インデックスの整理(micro 移行と並行でディスク削減)

ROADMAP(計画)

ロードマップ

今週

  • 5/16 17:00 リマインダー発火後、保険スナップショット 4個(pre-cleanup / pre-micro / pre-merge / 最終)の削除可否判断
  • baseballnext RDS を footballnext RDS へ統合(2026-05-09 完了)
  • 旧 baseballnext RDS 削除(2026-05-09 完了、ユーザが Console から実施)

今月

  • app/Config/database.php の認証情報を環境変数 / Secrets 管理へ移行(過去履歴に残った旧 baseballnext 接続情報のローテーションも視野)
  • app/Config/core.phpdebug を本番では 0
  • RDS の SG(3306 が 0.0.0.0/0 に開いている件)を最小化
  • EC2 nano 2台 → 1台化(保留中、コスト効果 月 約 $9.5)

今四半期

  • cron 設計の見直し(毎分curl 12〜13本の集中起動 → ジョブキュー or 適切な分散へ)
  • CakePHP 旧バージョンの保守性評価(移行 or 現状維持の方針決定)
  • 5年経過した articles の自動退避ジョブ実装(CronController::archiveOldArticles + cron.txt、2026-05-01 完了。本番デプロイはユーザ側)

いつか

  • old_articles / old_article_each_view_relations の取り扱い再検討(現状約1,000件まで縮小済み、参照しないと確信できれば DROP)
  • EC2 → Lightsail 移行(multi-purpose-lightsail-server1 相乗り or 専用 Lightsail 新設)

DECISIONS(意思決定)

意思決定記録

このプロジェクトで下した重要な意思決定を記録する。 最新が上に来る。


2026-05-09: baseballnext RDS を footballnext RDS に統合し、別データベース (baseballnext DB) として同居させる

背景: baseballnext RDS は cleanup 後でも独立インスタンス(db.t4g.micro)で月 $13+α かかっていた。footballnext RDS(db.t4g.small)はメトリクス上余裕があり、既に他サービス(machiga, schulte, kowai, sp_world, search_article 等)も同居する multi-tenant 状態だった。

決定: baseballnext RDS を削除し、footballnext RDS に baseballnext データベース+同名ユーザを作成、データを取り込み統合した。アプリは database.php の host のみ書き換えで切替(ユーザ名・パスワード・DB名は据え置き)。

理由:

  • 月額削減 約 $15〜19(micro インスタンス+EBS+Public IP分)
  • footballnext は実測で余裕あり(CPU avg 5%、buffer pool 1GB に対しワーキングセット収まる)
  • 別データベースとして同居なら、テーブル名衝突や AUTO_INCREMENT 衝突を考慮不要
  • アプリ側変更が host 1行で済むのが最大の利点(rollback も host を戻すだけ)

2026-05-09: メンテ操作は cron EC2 上で Docker mysql:8.4 経由で実行する

背景: 当初は cron EC2 (Amazon Linux 1) に yum install mysql でインストールした client (5.5) で MySQL 8.4 サーバを操作しようとしたが、mysqldump の出力に新仕様(GTID、tablespaces 等)が含まれ動作しなかった。EOL OS で 8.x の RPM も入手困難。

決定: cron EC2 に Docker をインストールして公式 mysql:8.4 イメージを使い、docker run --rm --network host mysql:8.4 ... でコマンドを実行する方式を運用標準とする。

理由:

  • バージョン互換性問題が一発で解消(公式イメージの client/dump がサーバと完全一致)
  • cron EC2 のホストOS環境を汚さない(docker pull のみ)
  • VPC 内通信なので速度面でもローカル経由より有利
  • 将来サーバが 8.5/9.x に上がっても、image タグを変えるだけで追従可能

2026-05-01: 5年より古い articles の自動退避ジョブは CakePHP Controller + cron 方式で実装する

背景: 一度きりの大規模アーカイブ移送が完了したが、以後も articles が再度膨らまないよう、5年経過した記事を継続的に old_articles へ退避する仕組みが必要。

決定: CakePHP の CronController::archiveOldArticles() として実装し、cron.txt0 3 * * * curl http://bnext.thomsonsapp.com/cron/archiveOldArticles を追加する。1回最大 1000件 / 日次で実行する。

理由:

  • 既存のすべての cron ジョブが「localhost への curl で CakePHP Controller を叩く」方式で統一されており、運用ノウハウもこのパターンに集約されている
  • Console Shell コマンドや独立PHPスクリプトを採用すると、デプロイ・実行ユーザー・ログ集約が分散する
  • 1日に動く件数は概算 1,300件/日 程度なので、1000件/日 + 必要なら手動再叩きで十分追従できる
  • 5年スライドで退避するので、articles のサイズが今後再度膨らむのを防げる

2026-05-01: RDS インスタンスクラスを db.t4g.small → db.t4g.micro へダウングレードする

背景: 当初の目標。事前のクリーンアップ(遺物テーブル削除・5年以前 articles の退避・FULLTEXT 削除・OPTIMIZE)で articles インデックスが 1.2GB → 475MB に縮小。CloudWatch メトリクスでも cleanup 後に FreeableMemory min が 52MB → 78MB へ改善し、micro で耐えられる見込みが立った。

決定: apply-immediately で即時クラス変更。事前にスナップショット (baseballnext-pre-micro-20260501-1540) を取得して、ダウンタイム発生(実測 約6分)を許容して進める。

理由:

  • メトリクス上、CPU/IO/接続数すべてに余裕があり、micro の制約値に届かない
  • 個人開発のため数分のダウンタイムは許容範囲
  • スナップショットで即時リストア可能、ロールバックリスクも低い
  • 1時間後の観察で FreeableMemory 90-110MB / ReadIOPS 1-2 と完全安定を確認 → 判断は妥当だった

2026-04-29: 5年以上前の articles を old_articles に退避する(削除はしない)

背景: articles が240万行 / 1.9GB(うちインデックス 1.2GB)で buffer pool 1GB に収まらず、メモリ逼迫の主因になっていた。完全削除はリスクが高い。

決定: date < '2021-04-29' かつ date != '0000-00-00' の 1,502,414 行を old_articles テーブルに退避し、articles 側からは削除する。old_articles のインデックスは PRIMARY + date のみ。退避テーブル自体は当面 DROP しない(メモリ削減効果ゼロでディスク代だけだから安心料として保持)。

理由:

  • 退避による副次効果として OPTIMIZE 後 articles のインデックスが 1,237MB → 475MB に縮小し、micro の buffer pool(約768MB想定)に余裕で収まる規模になる
  • 完全削除しないのは、将来「やはり古い記事を参照したい」となったときの保険
  • 退避先のインデックスを最小化したのは、退避庫として日付検索だけ可能にすれば十分だから

2026-04-29: article_each_view_relations の旧記事関連レコードも old_article_each_view_relations に退避する

背景: articles から旧データを削除しようとしたら article_each_view_relations.article_id の FK 制約 (ON DELETE RESTRICT) で阻まれた。article_each_view_relations 側は 588万行 / 324MB あり、コードを確認すると view_id は articles.id ではなく画面種別ID(VIEW_TOP, VIEW_WADAI 等の値域 0〜16)と判明。

決定: 旧 articles に紐づく article_each_view_relations のレコード(343万行)を old_article_each_view_relations に退避し、本テーブルからは削除する。インデックスは PRIMARY のみ。

理由:

  • 単純削除でも整合性は保たれるが、old_articles を残す方針と揃えて「念のための退避」を選択
  • 退避庫としての検索ニーズはほぼないので index は最小限
  • 結果として article_each_view_relations は 324MB → 203MB(−37%)に縮小

2026-04-29: schema.sql よりも実DBを正とする(schema.sql は更新する)

背景: schema.sql ベースの静的解析で「冗長な複合インデックス候補」「del インデックス」などを抽出したが、実DBには既に存在しないものがあった(schema.sql が古い)。

決定: 解析・運用は実DBに対して行うことを基本とする。schema.sql は将来再ダンプして更新する(現状は参考情報扱い)。

理由:

  • 実DBが現実なので、ダンプの古さに引っ張られて誤った判断(「これを消そう」とALTERしようとして失敗)を避ける
  • DB 構造変更の作業ログを別途 DEVLOG.md に残しておけば、schema.sql のメンテナンス頻度は高くなくてもよい

2026-04-29: RDS micro 移行判断のため performance_schema を有効化する

背景: RDS baseballnext を db.t4g.small → db.t4g.micro にダウングレードできるか検討中。CloudWatch 標準メトリクスでは CPU/IO/接続数は十分余裕があると判明したが、FreeableMemory が最小 54MB まで下がる瞬間があり、micro (1GB) でバッファプールが約768MBに縮小したときワーキングセットが収まるかを判断する材料が必要。Performance Insights 系のヒット率指標を見たいが、performance_schema=0 のため取得できなかった。

決定: パラメータグループ general-mysql84performance_schema01 に変更し、RDSを再起動する。再起動タイミングは即時。

理由:

  • 2〜3日メトリクスを蓄積すれば、ワーキングセットの実サイズが定量的に判断できる
  • 再起動のダウンタイムは約30秒見込みで、cron が空振りする程度の影響に留まる(実測も約30秒)
  • 代替案として MySQL に直接接続して information_schema.innodb_buffer_pool_stats などを見る手もあるが、継続的な指標取得には Performance Insights 系のほうが扱いやすい

2026-04-29: ネストした Git リポジトリ(baseballnext-server, baseballnext-ios)は本リポでは管理しない

背景: プロジェクトルート配下の baseballnext-server/baseballnext-ios/ はそれぞれ独立した Git リポジトリで、コミット履歴も別管理。本リポ baseballnext-operation は運用用のメタリポという位置付け。

決定: .gitignorebaseballnext-server/baseballnext-ios/ を追加し、本リポでは追跡しない。

理由:

  • 本リポの目的はあくまで「運用」(cron.txt、schema.sql、開発メモなど)であり、各ソースリポのコードを二重管理する意義がない
  • submodule 化はコミット履歴の同期が煩雑になるので避ける
  • 各リポは個別に push される運用が既に成立している

DEVLOG(作業ログ)

開発日誌

このプロジェクトでの作業を時系列で記録する。 最新のエントリが上に来る。


2026-05-09

18:00 - baseballnext RDS を footballnext RDS へ統合し、旧 RDS を削除

やったこと:

  • 事前調査
    • EC2 nano 2台 (bn-20190320-1/-2) は ALB taki 配下。cron は別EC2 で動いておりWeb専用。CPU avg 1.5%、リクエスト数 1秒1未満で1台化可能と判明(実行は保留)
    • footballnext RDS は db.t4g.small / 145テーブル / 合計約4.5GB(システム領域込みで実使用14GB)
    • footballnext RDS は実は multi-tenant(footballnext, machiga, schulte, kowai, sp_world, search_article, tmp 等が同居)
  • 統合準備
    • 両RDSのスナップショット取得(baseballnext-pre-merge-20260509-1832 / footballnext-pre-merge-20260509-1832
    • footballnext RDS に master user (ichirokisanuki) で baseballnext データベース+同名ユーザを作成。アプリは host のみ変更で切替できるよう、ユーザ名・パスワード・DB名は元 baseballnext と同一に揃えた
    • cron EC2 (Amazon Linux 1, mysql 5.5 入り) では MySQL 8.4 サーバとの互換性が不安だったため Docker をインストールして mysql:8.4 イメージ経由で操作する方式に切替
  • データ移行(cron EC2 上で Docker 経由)
    • mysqldump --single-transaction --set-gtid-purged=OFF --no-tablespacesichirokisanuki で実行
    • 所要 4分06秒で90テーブル全転送完了
    • 整合性確認: articles 894,904行 / aevr 2,454,842行など、両RDSで完全一致
  • 切替&動作確認
    • ユーザ側で baseballnext-server/app/Config/database.php の host を footballnext.<...> に変更してデプロイ
    • cron 再開後、新 RDS 側のテーブル件数(articles, api_logs, aevr)が増加していることを確認 → アプリと cron が新側を見ていることを確認
    • 旧 baseballnext RDS の DatabaseConnections が直近7分間 0 で固定 → 安全に停止可能と判断
  • 旧 baseballnext RDS 削除(ユーザが Console から最終スナップショットを取得しつつ削除)
  • dev-timer #16 を 2026-05-16 17:00 にセット(baseballnext 関連の保険スナップショット 4個の削除可否確認用)

詰まったこと / 気づき:

  • 1回目の dump 失敗: baseballnext@% ユーザに RELOAD / FLUSH_TABLES 権限がなく --single-transaction の前段で失敗。これらは GLOBAL 権限なので個別DBには付与不可。
  • 2回目の dump 失敗: --skip-lock-tables だけにしても、PROCESS / SUPER / SYSTEM_VARIABLES_ADMIN 権限不足で別エラー。
  • → master user (ichirokisanuki) で dump|import を実行することで全て解決
  • AL1 の mysql 5.5 client を MySQL 8.4 サーバに使うのはリスクあり(新しい構文非対応)。Docker + 公式 mysql:8.4 イメージを使うことで互換性問題を回避できた
  • footballnext RDS の innodb_buffer_pool_size = 1.0 GB(small なら 1.5GB の予想値より小さめ)。multi-tenant で複数DBを共有しているのに、ピーク負荷でも問題なく動いている
  • 移行直前に確認した old_articles 件数が 1,041 と前回の 1,502,414 から大幅に減っていた。私の作業範囲外で TRUNCATE / DROP+CREATE 等が起きたと推測(容量削減のためユーザ判断と思われる)

次回やること:

  • 5/16 のリマインダー発火後、保険スナップショット 4個(pre-cleanup / pre-micro / pre-merge / 最終)の削除可否判断
  • 別件改善: core.phpdebug=20database.php の認証情報を環境変数化、RDS SG 0.0.0.0/0:3306 の最小化
  • EC2 nano 1台化(保留中)

2026-05-01

17:30 - articles 自動退避ジョブの実装

やったこと:

  • 5年より古い articles を old_articles へ日次で退避するジョブを実装
  • 実装方式は既存 cron 設計(localhost への curl で CakePHP Controller を叩く)に揃えた
  • baseballnext-server/app/Controller/CronController.phparchiveOldArticles() メソッドを追加(baseballnext-server は別リポ。本リポでは git 追跡されない
    • id 昇順で最大 1000件、Article.date < NOW() - INTERVAL 5 YEAR かつ date != '0000-00-00 00:00:00'
    • 4ステップを getDataSource()->begin()/commit()/rollback() で1トランザクション化(articles → old_articles INSERT、aevr → old_aevr INSERT、aevr DELETE、articles DELETE)
    • 失敗時は trace() でログを残しつつ例外を再 throw
    • var $usesArticleEachViewRelation を追加
  • cron.txt に1行追加: 0 3 * * * curl http://bnext.thomsonsapp.com/cron/archiveOldArticles(メンテナンス系セクション)
  • 実 crontab の管理場所はこちらでは特定できず(cron EC2 は7channel用、BN Web 2台は SSH 不可)。ユーザ側で本番 crontab に反映する運用。

気づき:

  • 5年前境界をスライドして退避するため、1日に動く件数は「5年前のその日の分」 = 概算 1,300件/日で済む。バッチ1000件 + 必要なら手動で再叩きで十分追従できる
  • 退避先テーブル(old_articles / old_aevr)は事前に作成済みでインデックスも最小化されているため、INSERT コストは軽い
  • 自動退避が安定して回れば、articles のサイズが今後5年後に再度膨らむのを防げる

次回やること:

  • 反映後、1日目に curl で手動叩きして動作確認、件数が articles → old_articles へ +1000/-1000 シフトするか
  • micro 安定運用の見守りも継続

15:30 - RDS micro 化実行と動作確認

やったこと:

  • 5/1 リマインダー発火後、cleanup 前後のメトリクス比較
    • FreeableMemory min: 52MB → 78MB(+50%)、avg 113→134MB
    • WriteIOPS max: 84→17(−80%)、ReadIOPS max: 246→86
    • CPU max: 12.7%→7.1%
    • BurstBalance min は一時的に 61% に落ちていたが avg/median は 97/99% に回復済み(OPTIMIZE 起因の一過性消費)
  • schema.sql を実DB から再ダンプ(mysqldump 標準形式に置換)。テーブル数 92→90、現状の正しい構造を反映してコミット (46f76be)
  • RDS スナップショット取得 (baseballnext-pre-micro-20260501-1540、所要 約3分)
  • インスタンスクラスを db.t4g.small → db.t4g.micro に変更(apply-immediately)
    • 受付 15:45:06 → modifying → micro へ切り替わり 15:48:59 → configuring-enhanced-monitoring → available 15:50:46
    • 所要時間 約5分40秒、実ダウンタイムは1〜2分程度
  • micro 化直後のパラメータ確認
    • innodb_buffer_pool_size = 256 MB(事前予想の 768MB より大幅に小さい)
    • max_connections = 60(事前予想 85 より少なめ)
    • performance_schema = 1(維持)
  • dev-timer #10 を1時間後(16:54)にセットして観察
  • 1時間後(17:00頃)のメトリクスで完全安定を確認
    • FreeableMemory: 90〜110MB で安定(一時 88MB が最低)
    • ReadIOPS: 1〜2 で完全に落ち着く(buffer pool 256MB でもホットセットが収まっている)
    • CPU avg 3.85%、max 5%(small時と同等)
    • BurstBalance: 99% フラット維持
    • CPUCreditBalance: 0 → 7.06 と回復中(micro の baseline 利用率を下回っているため自動回復)

決めたこと:

  • db.t4g.small → db.t4g.micro へグレードダウン(DECISIONS.md に記録)

気づき:

  • 実際の buffer pool は事前計算値(DBInstanceClassMemory*3/4= 768MB)の3分の1の 256MB しか割り当てられなかった。RDS 側で innodb_buffer_pool_chunk_size × instances の制約や、OS/レプリケーション分のメモリ確保のために自動で縮められている可能性。にもかかわらず ReadIOPS が 1〜2 で安定しているのは、cleanup でホットワーキングセットが 256MB 以下に収まる規模になったため。
  • RDS インスタンスクラス変更時はダウンタイムが必ず発生するが、modify 受付 → 切替 → 再起動 → 利用可能まで全部含めて約6分。cron が一時的に空振りする程度で実質的影響は軽微。
  • micro 化後、CPUCreditBalance はリセットされて 0 から始まる。回復速度はベースライン消費量との差分次第。

次回やること:

  • 数日〜1週間スパンで micro 安定運用を確認(FreeableMemory が下がり続けないか、ReadIOPS の高止まりがないか、CPUCreditBalance が満タン側に推移するか)
  • 別件改善: app/Config/core.phpdebug=20app/Config/database.php の認証情報環境変数化、RDS SG 0.0.0.0/0:3306 の最小化

2026-04-29

13:20 - articles アーカイブ移送と DB クリーンアップ

やったこと:

  • スキーマ静的解析(schema.sql ベース)
    • 遺物テーブル候補: *_backup* × 3、temp_* × 1、test_* × 3
    • 冗長な複合インデックス候補2件、FULLTEXT 2本(articles.title, movies.title)を抽出
    • コード参照確認: バックアップ系4本は参照ゼロ。test 系は Test* Modelで使用されており残す方針。MATCH AGAINST は0件で FULLTEXT は実質未使用。
    • 実DBに接続したところ、schema.sql は古く、del / team_id(単独)/ article_view_position(単独)の冗長インデックスは既に削除済みと判明
  • RDSスナップショット取得: baseballnext-pre-cleanup-20260429-1323(所要 約2分37秒)
  • MySQL 接続経路の確立: ローカル → cron EC2 (52.194.87.168) SSHトンネル → RDS:3306。cron EC2 側に mysql clientがなかったためトンネル方式採用。ローカル mysql client は /opt/homebrew/opt/mysql-client/bin/mysql
  • Phase 1: 遺物テーブル4本を DROP(article_sites_backup20141012, keywords_backup, pushes_backup, temp_new_article_rss_sites、合計 約0.5MB、テーブル数 92→88)
  • articles アーカイブ移送(最大の改善)
    • old_articlesLIKE articles で構造コピー → 13本のうち余計な11本を DROP し、PRIMARY + date のみ残した
    • FK 制約発覚: article_each_view_relations.article_idarticles.idON DELETE RESTRICT で参照(588万行 / 324MB)
    • view_id はコード調査の結果、VIEW_TOP VIEW_WADAI 等の画面種別ID(値域0〜16)で articles の id 参照ではないと判明
    • 対応として old_article_each_view_relations も同様に作成(PRIMARY のみ)し、関連レコードも退避することに
    • 4ステップ・トランザクション・id幅50000のバッチで全48バッチ実行(所要 約14.5分)
      • articles: 240万行 → 89.6万行、退避 1,502,414行
      • article_each_view_relations: 588.6万行 → 245.8万行、退避 3,428,436行
      • 整合性 OK(差分5〜12件は移送中に cron で追加された新規分)
  • Phase 2: FULLTEXT 削除(articles.title, movies.title、所要 1〜2秒、オンラインDDL)
  • OPTIMIZE TABLE 実行
    • articles: 1,901MB → 755MB(−60%、index 1,237→475MB)
    • article_each_view_relations: 324MB → 203MB(−37%)
    • old_articles: index 68→24MB(data はキャリブレーション差で見かけ上微増)
    • old_article_each_view_relations: 微増(一括INSERTで既にコンパクトだったため)
  • 現役テーブル合計 2,225MB → 958MB(−57%)articles インデックスが micro の buffer pool(約768MB想定)に十分乗る規模に

詰まったこと / 気づき:

  • 1回目のバッチ移送スクリプトでバッククォートのエスケープが効かず `date` がコマンド置換として実行されていた → SQLテンプレを sed 置換方式に変更して解消
  • 2回目は zsh の printf %d に mysql の Warning 行(mysql: [Warning] Using a password ...)が混入してエラー → stderr を一時ファイルに分離して解消
  • SSH トンネルが OPTIMIZE 中に2回切断 → ServerAliveInterval=15, ServerAliveCountMax=20, TCPKeepAlive=yes 強化版で再接続
  • information_schema.tables のサイズはキャッシュされる。最新値を見るには同じセッションで SET SESSION information_schema_stats_expiry = 0; が必要
  • information_schema.innodb_buffer_pool_statsPROCESS 権限が必要で、baseballnext ユーザでは取得不可(CloudWatch 経由で見るしかない)

次回やること:

  • 5/1 13:09 の dev-timer リマインダー発火後、Performance Insights / FreeableMemory / バッファプールヒット率の改善幅を確認
  • 効果が確認できれば db.t4g.micro へダウングレード
  • 別件の改善: database.php の認証情報を環境変数化、core.phpdebug を本番 0 に

12:50 - プロジェクト解析と RDS micro 移行検討の着手

やったこと:

  • プロジェクト全体構造の把握
    • iOSアプリ(baseballnext-ios/、Swift+ObjC、CocoaPods で広告SDK多数)
    • PHPバックエンド(baseballnext-server/、CakePHP 旧バージョン、Controller 59 / Model 77、AWS CodeDeploy で配備)
    • 1分ごとに 12〜13ジョブ+20分毎 3ジョブを4秒ずらしで起動する cron.txt
    • スキーマ 92テーブル(InnoDB主体、utf8mb3が大半、一部 latin1)
    • baseballnext-server / baseballnext-ios はそれぞれ独立した Git リポがネストしている状態
  • RDS の現状把握(thomson-ik プロファイル / ap-northeast-1)
    • インスタンス: baseballnext (db.t4g.small, MySQL 8.4.8, gp2 20GB, Single-AZ, ap-northeast-1c, 2018-12-26 作成)
    • パラメータグループ: general-mysql84
  • CloudWatch メトリクス取得(直近7日 / 1h period / 168データポイント)
    • CPUUtilization: avg 3.87% / max 12.72% / p95 8.24%
    • FreeableMemory: avg 113MB / max 153MB / min 54MB
    • DatabaseConnections: avg 0.06 / max 5
    • ReadIOPS: avg 0.81 / max 246(ほぼ0、ワーキングセットがバッファプール内に収まっている示唆)
    • WriteIOPS: avg 9.36 / max 83.6
    • CPUCreditBalance: 576 で常時満タン(バーストクレジット未消費)
    • BurstBalance: 99-100%
    • FreeStorageSpace: 約11.7GB空き(20GB中 約8GB使用)
  • パラメータグループ確認
    • innodb_buffer_pool_size = {DBInstanceClassMemory*3/4} 動的式(user設定)
    • max_connections = {DBInstanceClassMemory/12582880} 動的式(system)
    • performance_schema = 0(無効)← micro 判断のために有効化することに
    • 他のメモリ系は概ね engine-default
  • performance_schema の有効化を実施
    • パラメータグループ更新(0→1, ApplyMethod=pending-reboot)
    • RDS 再起動(ダウンタイム実測 約30秒、13:06:48 rebooting → 13:07:35 available)
    • インスタンスの ParameterApplyStatus が in-sync であることを確認
  • dev-timer 登録: #8 2026-05-01 13:09 に「performance_schema 有効化後のメトリクス確認」(baseballnext-operation)
  • .gitignore にネストリポを追加(baseballnext-server/, baseballnext-ios/

気づき:

  • ReadIOPS ほぼ0/CPU余裕/クレジット満タンで、CPU・IO観点では micro へ落とせる余地が大きそう
  • 唯一の論点は FreeableMemory 最小 54MB という瞬間値。micro (1GB) でバッファプールが約768MBに自動縮小したとき、ワーキングセットが収まるかが要確認
  • performance_schema=0 だったので、Performance Insights 由来のヒット率系メトリクスは今回取れていない。有効化済みなので 2〜3日後に判断材料が揃う
  • database.php に本番DBの平文認証情報がコミットされている(別件のセキュリティ課題)
  • core.phpdebug=2 のままになっている(本番では本来0)

次回やること:

  • 5/1 のリマインダー発火後、Performance Insights / バッファプール系メトリクスを再収集し micro 移行を判断
  • 並行で進められるなら ② バッファプール内訳・テーブルサイズの実測(要MySQL接続経路)、③ バックアップ系・未使用インデックスの静的洗い出し

最近のコミット

README

baseballnext-operation

概要

(記入予定)

セットアップ

(記入予定)

使い方

(記入予定)