baseballnext-operation
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 までは保険として残し、その時点で問題なければ削除
次にやること(優先度順):
- 5/16 のリマインダー発火 → スナップショット削除判断
- 別件改善:
app/Config/core.phpのdebug=2→0(本番ではデバッグ出力を抑制)app/Config/database.phpの認証情報を環境変数化(過去履歴に残った旧 baseballnext 接続情報のローテーションも視野)- RDS SG
0.0.0.0/0:3306を必要最小に絞る
- 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.txtに0 3 * * * /cron/archiveOldArticlesを追加- 1回 1000件 / 5年境界で日次に古い articles を
old_articles/old_aevrへ退避 - 本番 crontab への反映はユーザ側で実施(コードのデプロイも同様)
- 事前のクリーンアップ+micro 化+自動退避ジョブで、当面のメモリ/ディスク逼迫リスクは概ね解消。
次にやること:
- 自動退避ジョブの本番デプロイ&動作確認
- 数日〜1週間スパンで micro 安定運用の見守り
- 別件改善: 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) に十分乗る規模になったので、移行成功の見込みが大きく上がった。
次にやること:
- 5/1 リマインダー発火 → Performance Insights / FreeableMemory / バッファプールヒット率の改善を確認
- 効果が見えたら micro へインスタンスクラス変更(pending-reboot or apply-immediately)
- 別件として
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_schemaを0→1に有効化済み(2026-04-29 13:07 RDS再起動完了、in-sync 確認済み)。今からPerformance Insights系メトリクスが蓄積され始める。- 5/1 13:09 に dev-timer #8 でリマインダー登録済み。
次にやること:
- 5/1 のリマインダー発火後、buffer cache hit ratio などのメトリクスを再収集
- それで判断材料が足りなければ、② MySQL に直接接続してバッファプール内訳・テーブルサイズを実測(接続経路:cron EC2 経由のSSHトンネルが第一候補)
- ③
*_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.phpのdebugを本番では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.txt に 0 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-mysql84 の performance_schema を 0 → 1 に変更し、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 は運用用のメタリポという位置付け。
決定: .gitignore に baseballnext-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 等が同居)
- EC2 nano 2台 (
- 統合準備
- 両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イメージ経由で操作する方式に切替
- 両RDSのスナップショット取得(
- データ移行(cron EC2 上で Docker 経由)
mysqldump --single-transaction --set-gtid-purged=OFF --no-tablespacesをichirokisanukiで実行- 所要 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.5client を 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.phpのdebug=2→0、database.phpの認証情報を環境変数化、RDS SG0.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.php に
archiveOldArticles()メソッドを追加(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 $usesにArticleEachViewRelationを追加
- id 昇順で最大 1000件、
- 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.phpのdebug=2→0、app/Config/database.phpの認証情報環境変数化、RDS SG0.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_articlesをLIKE articlesで構造コピー → 13本のうち余計な11本を DROP し、PRIMARY+dateのみ残した- FK 制約発覚:
article_each_view_relations.article_idがarticles.idをON DELETE RESTRICTで参照(588万行 / 324MB) view_idはコード調査の結果、VIEW_TOPVIEW_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_statsはPROCESS権限が必要で、baseballnextユーザでは取得不可(CloudWatch 経由で見るしかない)
次回やること:
- 5/1 13:09 の dev-timer リマインダー発火後、Performance Insights / FreeableMemory / バッファプールヒット率の改善幅を確認
- 効果が確認できれば db.t4g.micro へダウングレード
- 別件の改善:
database.phpの認証情報を環境変数化、core.phpのdebugを本番 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 リポがネストしている状態
- iOSアプリ(
- 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 登録:
#82026-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.phpでdebug=2のままになっている(本番では本来0)
次回やること:
- 5/1 のリマインダー発火後、Performance Insights / バッファプール系メトリクスを再収集し micro 移行を判断
- 並行で進められるなら ② バッファプール内訳・テーブルサイズの実測(要MySQL接続経路)、③ バックアップ系・未使用インデックスの静的洗い出し
最近のコミット
- 0f8d574 .devnotes 更新(baseballnext → footballnext RDS 統合完了の記録) 2026/5/9
- e124426 .devnotes 更新と articles 自動退避 cron 追加 2026/5/1
- 77d8b23 .devnotes 更新(RDS micro 化完了の記録) 2026/5/1
- 46f76be schema.sql を実DBから再ダンプ 2026/4/29
- 934bcd8 .devnotes 更新(articles アーカイブ移送と DB クリーンアップの記録) 2026/4/29
- 10f5b7c .devnotes 初回更新と運用ファイルの取り込み 2026/4/29
- 47d256c Initial commit 2026/4/29
README
baseballnext-operation
概要
(記入予定)
セットアップ
(記入予定)
使い方
(記入予定)