Rails: データベーススキーマをダウンタイムなしで変更する(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: Managing db schema changes without downtime 原文公開日: 2018/03/22 著者: Sam Saffron — Discourseの共同創業者であり、Stack Overflowでの開発経験もあります。 後半で紹介されているgemについては先週のRailsウォッチもどうぞ。 Rails: データベーススキーマをダウンタイムなしで変更する(翻訳) Discourseのメンバーはいつも継続的開発の大ファンであり、コミットのたびにCIのテストスイートと対決しています。すべてのテスト(UI、単体、結合、スモーク)にパスすれば、自動的にコードの最新バージョンがhttps://meta.discourse.orgにデプロイされるようになっています。 私たちが継続的開発というパターンに沿って実践していることで、ソフトウェアを自分でインストールした数千人のユーザーがいつどんなときでもtests-passedバージョンに安全にアップグレードできるようになっています。 私たちは頻繁にデプロイを行っているので、デプロイ中に止まったりしないようひときわ注意を払う必要があります。アプリのデプロイ中に止まってしまうよくある原因のひとつが、データベーススキーマの変更です。 スキーマ変更に伴う問題 現在のデプロイのしくみを雑に説明すると次のような感じになります。 データベースを新しいスキーマに移行する アプリを単一のDockerイメージにバンドルする レジストリにプッシュする 古いインスタンスを止め、新しいインスタンスをpullして立ち上げる(これを繰り返す) 万が一互換性のないデータベーススキーマを作成してしまうと、古いバージョンのコードを実行している古いアプリのインスタンスが全部止まってしまうリスクが生じます。実際には数十分の停止?という形で表面化します。 これはActiveRecordにとって特に悲惨な状況です。production環境のデータベーススキーマはキャッシュされており、スキーマでカラムのリネームや削除を行う何らかの変更が生じると、たちまち影響範囲にあるモデルであらゆるクエリが効かなくなってしまい、無効なスキーマの例外がraiseされるリスクが生じます。 この問題を克服し、停止時間を最小限にとどめてスキーマ変更を安全にデプロイできるようにするために、私たちは数年がかりでさまざまなパターンを導入してきました。 マイグレーションの情報を詳しくトラッキングする ActiveRecordにはschema_migrationsという名前のテーブルが1つあります。ここには、実行されたマイグレーションに関する情報が保存されます。 残念なことに、このテーブルに保存されている情報の量は極端に制限されています。実際、次の情報ぐらいしかありません。 connection.create_table(table_name, id: false) do |t| t.string :version, version_options end このテーブルには、実行したマイグレーションの「バージョン」を保存する孤立したカラムが1つあります。 マイグレーションが実行された時刻はこのカラムに保存されない マイグレーションの実行にかかった時間はこのカラムに保存されない マイグレーションの実行時に動かしていたRailsのバージョンに関する情報が何もない この情報の少なさ(特に「いつ実行されたのか」という情報が取れないこと)のせいで、スキーマ変更をきれいに扱えるシステムの構築が困難になっています。さらに、情報が貧弱なためにマイグレーション中に発生する奇妙でわけの分からない問題のデバッグがものすごくつらくなります。 Discourseでは、Railsにモンキーパッチを適用することでマイグレーションの情報を詳しくログ出力しています(github.com: 記事では一部省略)。 module FreedomPatches module SchemaMigrationDetails … Continue reading Rails: データベーススキーマをダウンタイムなしで変更する(翻訳)