実際にあったお話を供養させます。
何が原因だったのかを推測しながら読んでもらえるとポストモーテム冥利に尽きます。
経緯
混入
- 画像コメントの文字数の上限を50文字→100文字へ増やしたいという要望が来ました。
- 対応者は下記のようなDDLで対応することにしました。
-- テーブルはシャーディングされている
ALTER TABLE `table_1` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
ALTER TABLE `table_2` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
-- たくさんある… たくさん…
ALTER TABLE `table_100` CHANGE `image_comment` `image_comment` varchar(100) DEFAULT NULL;
- 私はDBAのような役回りを担っており、「テスト環境でも動作確認して、問題ない」と判断しました。
- そうしてアップデート当日を迎え、上記のDDLを流しました。
- 無事に画像コメントの文字数上限が増えたことを本番環境で確認し、家路についたのです。
発覚
- 翌朝、いつもどおり出社して仕事をし始める私。
- しばらくすると上記の対応をしたスタッフがやってきて言うのです。
- 「なんか画像のコメントが文字化けしてるみたいなんですよね…」
- 「……?!」
調査
- そんな馬鹿な… という思いを捨てきれず調査開始
- 文字化けが発生しているという
table_60
を確認し始める… - 数分後、私は衝撃の事実に気付くのです。
「うわぁあ!!」と飛び上がって驚いたのは後にも先にもこのときくらいです。
ここまで
-
対象のテーブルはシャーディングされている
- 私が入社する前からたくさんあります
-
文字数を増やす対応をしただけなのに文字化けした…
-
VARCHAR 型で文字化けに関わるオプションといえば?
-
ちなみに変更したカラムの Before です
-
image_comment varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
-
-
テスト環境でも本番環境でも確認したのに…
- その「確認」は漏れてない?
答えに入る前に
今年のアドベントカレンダーは本番環境でやらかしちゃった人 Advent Calendar 2019 を要チェックしてます。
こういうやらかし系の共有は本当にありがたいです。
死屍累々のポストモーテム会…(゚A゚;)ゴクリ
惨劇はなぜおこってしまったのか
-- 文字化けしてないテーブル
CREATE TABLE `table_1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
-- カラム省略
`image_comment` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;
-- 文字化けしてるテーブル
CREATE TABLE `table_60` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
-- カラム省略
`image_comment` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=DYNAMIC;
あ!やせいのlatin1
があらわれた!
何故か一部のテーブルだけ CHARSET=utf8 COLLATE=utf8_unicode_ci
ではなかったのです!!
なんでかわかりませんが、昔からそうだったようです…
つまりこうなります
元々入ってた文字データ(CHARSET=utf8 COLLATE=utf8_unicode_ci
)が、カラムの型変更のタイミングで文字セットを指定しなかったため、テーブルのデフォルトCHARSET=latin1 COLLATE=latin1_swedish_ci
になる。
- するとどうなる?
- 文字が化ける
- するとどうなる?
- メンテが始まる
二度と惨劇を起こさないためにどうしたのか
- シャーディングされているテーブルに齟齬がないかの確認
- これは事件後に対応しました
- あなたの現場のシャーディングは、大丈夫ですか?
- 全テーブルでのデバッグ
- 登録済みのデータが無事か、全テーブルからいくつかサンプルでレコードを取ってくるようなデバッグをすればよかったです
- VATCHAR型, TEXT型の変更時には
CHARACTER SET utf8 COLLATE utf8_unicode_ci
あるいはCHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
を入れる- これは今でもトラウマなのでチェックします
ひとこと
ポストモーテムを書くのも読むのもトラブルシューティング力を高めるきっかけになるかと思います!
みなさんももっと恥を忍んでさらけ出しましょう!