Open1

【第5話】やっと終わったと思ったら絵文字ファイル名でまた失敗した話 (draft)

kamadomakamadoma

2020年8月、緊急メンテでDNS切り替え成功。
全員が「もう終わった……」と安堵した。

……2ヶ月後、静かに地獄が始まった。

この記事は以下のシリーズの一部です
シリーズ一覧を見る


発覚:切り替えから約2ヶ月後(2020年10月頃)

  • 若者向けサービスで「画像がno imageになる」クレームがポツポツ
  • 調査 → ファイル名に絵文字(例:sunset.jpg)が入っている画像だけタヒ

真の原因(最凶)

移行バッチで絵文字を力技で排除していた:

# 移行バッチの一部(当時のコード)
filename = original_filename.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
# → 絵文字は全部空文字に置換 → DBには空のfilenameが保存される
# → ActiveStorageがキー生成できず → 404 → no image画像に置き換え

さらに追い打ち:

  • filenameカラムはutf8(偽)→ そもそも絵文字保存不可
  • 絵文字入りファイルは移行時に完全にデータが消滅していた

対応(18億レコードテーブルでの絶望作業)

  1. 旧環境のバックアップから絵文字入りファイル名を救出
  2. filenameカラムをutf8utf8mb4に変更(3日間ALTER)
  3. 対象ファイルを特定 → 専用バッチで再attach(1件ずつ安全に)
-- 救出例(旧バックアップから)
SELECT old_id, original_filename 
FROM old_images_backup 
WHERE original_filename REGEXP '[x{1F300}-x{1F9FF}]';

教訓(血の文字)

  • 絵文字を「力技で潰す」のは最悪の選択
  • MySQLのutf8は偽物(utf8mb4一択)
  • 移行プロジェクトは「切り替え成功=終わり」じゃない
  • 「異常データは除外すればいい」と思ったら地獄を見る

最終話:「5年経って思うこと」


170TB・17億ファイルの画像移行で3回目の正直・2020年の全記録
第5話 完