2016-01-21

心労業務

最近やっているプロジェクトで最高に心労の高まりを感じたギョームについて書く。

v2移行時のDB構成変更に失敗。残ってしまった不要なレコードを手動で削除する

v2移行時にDB構成を結構変えた。 特に大きな変更が、論理削除から物理削除に変更した部分だった。

これ、物理削除に移行するタイミングで削除フラグが立っているレコードを削除しないといけなかったんだけどすっかり忘れてました。 この状態に気づいた時は本当に血の気が引いた。現実だと受け入れることができなかった。本当に。「はー、なんかヤバい匂いするけど多分気のせい。問題はない。」とか言い聞かせそうになっていた。

だが不幸中の幸いというやつ。実はアプリケーション全体のマスタとなる情報は別のDBにあったため、どのレコードが削除されるべきかを特定することができた。

放っておくわけにもいかないので、腹をくくってDBからゴミレコードを削除する作業を開始した。 運用さんのサポートのもと、別DBから削除されているべきレコードを抽出し、そのレコードと削除対象のレコードをIDで突き合わせながら削除を行った。

絶対にミスれないので、削除されたあとに残るべきレコード数の確認など入念にチェックした。というか、実作業は運用さんにやってもらうしかなかったので、チェックすべきものを伝えて確認してもらった。

また削除した時に予期せぬ何かが起こるとも限らないので、何か起きても問題が無いであろうレコードを選出して、最初にそれらを消して該当アプリケーションの状態を目視監視したりした。

10件程度を先行して削除し、特別問題がないことが確認できた。 全レコード削除のSQLはもう組み立ててあった。最後にもう一度削除後のレコード数があるべき件数と一致しているかを確認した。一致している。多分大丈夫だ。

運用さんに全削除を依頼する。レコードが全て消えた。 残ったレコードの数はやっぱりあるべき件数と一致している。成功した!

と、思ったのも束の間。30分後くらいだっただろうか、DBに格納されているジョブを処理するワーカがエラーを立て続けに吐き出した。 原因を深く追っている暇はなかった。しかし、切羽詰まった状況の人間の頭は常時より早く回るようだ。

どうやらエラーの原因はデッドロックであり、デッドロックが起こるタイミングというのは失敗したジョブに、「1回失敗しました。エラー内容はこれこれです」という感じで更新をかける処理だった。

つまり、失敗したジョブは何もせずそのままDBから消えてくれればいい。なお、失敗しているジョブというのは削除されているべきレコードを対象としているジョブなので、実行される必要はない。

運が良いのか悪いのかわからないが、そのジョブ管理ライブラリの設定については偶然朝に調べて知っていたので、どこをいじればよいかがすぐにわかった。これを運用さんに伝えて手動で書き換えてプロセスを再起動。

すると溜まっていたジョブは次々に失敗しつづけ、そしてこの世(DB)から去っていった。残業お疲れ様でした。 この対応でエラーは完全に収まり、不要なレコードも綺麗サッパリDBから無くなった。 まじで3日分くらい働いた感じだった。

心労業務を終えて

  • DBのロックについてもっと知っていたら良かった。削除処理はBEGIN - ROLLBACK - COMMITといったトランザクション構文を使いたかったのだが、これを使うとロックが起きて更新処理ができなくなる可能性があるようだったので利用できず。ただ運用さんもあまり知らないようだったので実は使えたかも。また、エラーとして出ていたデッドロックのエラーについてもどういう状況で起こったのかがよくわかっていない
  • 緊急事態の時の運用さんヤバい。実行が躊躇われるようなコマンドを冷静かつ迅速に実行していた
  • 使っているライブラリについてちゃんと知っておかないと、いざという時に何もできなくなるかも
  • 運用さんがいてくれて本当に良かった。この作業を1人でやっていたら、別の何かが起こっていた気がする
  • 現実を早めに受け入れる訓練をしておくと良い
  • DB構成の変更はいつもの10倍くらい慎重にやってくれ頼む > 未来の自分