rm /blog

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【障害記録】No.3:データ削除順序誤りによる夜間データ結果不正

自分が体験したシステム障害を紹介してトラウマを抉り返す自虐コーナー
※特定避けるため一部脚色・変更しているが、大体ほぼ実体験。

障害No障害分類No
(自分用)発生分類
アプリ/データ/ミドル/ハード案件名個人的ヤバイ度
(5段階評価)

3 B データ データ削除順序誤りによる夜間データ結果不正 ★★★★☆

 


 

 

発生日時 2011年末くらいだったかな… 解決日時 2011年中 発見者 お客さん 対応者 原因者
障害の詳細内容 これは自分が原因で引き起こした中では1・2を争うほどデカい障害だったと記憶している。
今でこそ笑い話のネタの一つだが当時はもういろいろ大変だった。

夜間バッチで、いろんなところからいろんなデータをいろんな形で集計して、
最終集計結果として大きく1つのトランザクションを作りだし、
それをエンドユーザ向けに「昨日の集計結果はこれだよ」という形で提供するサービスがあった。
(詳細は伏せさせていただくw)
「集計」にもいろいろ(本当にいろいろ)あったが、
ざっくりいうと以下のような2点に大分されたと思っている。
  1. テーブルAのデータ区分="01"を集計する
  2. テーブルAにあり、テーブルBと受注番号で紐づくデータを集計する
1.みたいなやつはわかりやすくて、
基準となるテーブルに持っている特定の区分値のデータだけを集計すればいいのだが、
2.みたいなやつは、
集計の基準になるテーブルに集計条件を持っていない(別テーブルと結合しないと集計にならない)ので
動的にテーブル結合して集計しなければいけなくなる。

で、
この「夜間バッチ」なのだが、大きく言うと以下のようなジョブ構成
(1)集計処理⇒(2)データ削除処理
になっていたのだが、
平たく言うととある理由(後述)でこの順番を逆の
(2)データ削除処理⇒(1)集計処理
に、してしまった。
これにより、本来集計対象になるべきデータが集計の手前で消えてしまい、
「集計結果がなんかおかしい」というエンドユーザからのクレームに繋がった。
しかも、指摘されるまでおよそ1ヶ月ほどこの状態が継続したのである。
そして輪をかけて最悪なのは、この集計結果が「エンドユーザに対する販促情報」になっていたこと。
この問題により、「不正な情報提供により正しい販促情報がサービス提供できなかった」とし、
いわゆる「機会損失」であるとして、社としての正式な障害報告に繋がった。
対応内容・経緯等 最初にお客さんから問い合わせを受けて、データ調査し、原因がジョブ順番変更によるものだとわかってからは、
すぐさま(2)のジョブを停止して(翌日以降動かないように変えた)暫定対処を図った。

ここで一応言い訳しておくと、
(1)集計処理⇒(2)データ削除処理

(2)データ削除処理⇒(1)集計処理
へ変更するのは、別件で、
「集計結果に集計されて欲しくないデータ分が含まれている」という指摘があったことによる。
(2)では10個くらいのテーブルを削除していて、
うち一つのテーブル(便宜上αとしておく)について、
(1)⇒(2)だと、「(1)で集計されて(2)で消える」
という構図になっていたのである。(つまりその日消えるのに集計はされてしまう)
じゃあ、(2)ごと(1)の前に持ってきちまえばいい、
という、軽い考えからこの問題に発展してしまった。
(2)で消す10個くらいのテーブルのうち、αを除く残り9個くらいのテーブルは、
「(1)で集計されて(2)で消える」で正しい仕様なのである。
(2)を、αだけではなく、丸ごと(1)の手前に移動してしまったのがダメだった。

(1)の集計処理の仕様を変えれば(αのうち、当日削除分は集計しないようにする)、
ジョブの順番変更なぞしなくてもこの「別件」は解決できただろう。
しかし、(1)の集計処理が数十個を超える大小様々なバッチ処理群により構成されるかなりカオスなジョブであるうえ、
冒頭述べたように「集計」のコアな部分は1000行を超えるうんこなコード(ほぼSQL)で書き込まれており、
「これに手を出すとヤバイことになる」という内部的な判断があったのと、
そもそもこの「別件」が要望に近い指摘だったことから「無償で出来る範囲で」という小規模対応を求められていたので、
簡単にできる「ジョブ変更」が対応の方針として採用された。

その「別件」としては、(2)⇒(1)に変更することで、
(1)の集計結果に含まれなくなる=指摘が解消される、という点に関するテストはしていて、
その点について(テスト結果やジョブの順番変更を含む)お客さんの情報システム部と共有もしていた。
そういった背景を知っているからかどうか知らないが、障害報告の場では、
情報システム部の方も一方的に俺たちベンダーを攻め立てることはなかった。
(この問題は相当ヤバイ件と思っていたので、一方的に詰られ怒鳴られ罵倒されると覚悟していたので、
 あのときの情報システム部の方の対応は少し意外だった。
 どのような背景によるものかはあれど、あの態度には少し精神的に救われた部分もある)

最終的には、一言でいえばテーブルαだけを(1)の手間で削除するようにして、他は今まで通り、というジョブ構成に変更した。
つまり
(2)’α削除処理⇒(1)集計処理⇒(2)データ削除処理
である。
本当に一言でいえばこうしただけだが、
この問題があってからはもうおっかなくて、
この状態で処理を回して本当に問題ないか?を、
本番データを使って1ヶ月ほど実際に回してみて、検証を行い、
お客さんの情報誌ステテム部・業務部門の方とも合意を経たうえで、
ではいざリリース!という流れを踏むほどだった。
この程度のちょっとしたジョブ変更にここまで慎重になったのはこれが初めての経験だった。
反省点・あとがき このテのヤバイ案件は、
正式対応そのものに非常に大がかりな体力を要するのはもちろんのこと
(実際、↑で述べたように、「ちょっとしたジョブ変更にお客さんの関連部門も全員巻き込んで1ヶ月テスト」した)
以下のような関連する作業も発生し、本当に大事になる。
  • 問題のあった期間にアクセスしてきたユーザの種類と時間の調査
  • 本来受注に繋がっていたであろうデータの種類と件数及び受注金額
そしてこれらをさばくのに、問題を起こした俺一人では手に負えなくなるので、
プロジェクトリーダーに相談のうえ、プロジェクトの他のメンバーにも協力を要請し、
他メンバーの現在作業の手を止めてまで調査・検証に協力してもらうことになる。
これにより並行して進めていた他案件のスケジュール調整等も発生するため、
(発端が障害だとそんな調整は聞きいれてくれないものだが)
まさに「プロジェクト一丸」となってこの問題の対応に追われることになる。
被害を蒙るのが問題を起こした俺一人ならともかく、
他メンバーにまで及ぶのは本当に申し訳ないと思ったものだ。
あのときはいたたまれなくなってよくタバコ吸いに行ったな…(遠い目)

ディスク容量の関係で、定期的なテーブルデータの削除は確かに必要ではあるが、
必要でない限りはそもそも削除なんかしなくてもいいというのが、
この問題を経て俺が学んだことである。
削除ほどおっかないことはない。
消さなくて済むなら消すことはない。
本当にこれに尽きる。
それでもなお消さなくてはならないときは、
消すテーブルを見ている全ての機能(画面もバッチも全部)について、
確実な検証をしてからでないとOKの判断はできない。
当たり前のように見えるが、こういう当たり前が出来ていないと大事になる。
ああ、藍坊主の「スプーン」を思い出す……
”当たり前で当たり前で大切さに気付いてなかった