しくじりSE　～他人の失敗談から学ぼう～

※本記事は、Sekappy社内勉強会の資料として、担当エンジニアが前職で遭遇した失敗談をまとめたスライドを記事として再編集したものになります。

# はじめに
この業界に二十数年従事してきた私ですが、数々のしくじり(失敗)を経験してきました。

しかしながら、痛みを伴って得たバッドノウハウは、グッドノウハウ以上に価値はあると思っています。

そこで今回は、過去の失敗とそこから何を学んだのかをご紹介させていただきます。

# しくじり事件簿　事件1：オンプレミスからAWSへファイル移行したときに……
とある案件をやっていたときの話になります。

オンプレミス環境にある複数の大容量画像をAWSにファイル移行するというのが実際の案件内容でした。

しかし、最初に聞いていた案件内容は、**ファイル移行先で動作して定時ファイルバックアップするバッチのPerlとAWSとの連携部分をPythonで作る**という内容だったのです。
二転三転して「**このバッチがファイル移行に使えるのでは？**」となり、巻き込まれる形で移行に関わることとなりました。

ファイル移行するにあたって、移行対象となる全ファイルのファイルサイズを聞いたところ、合計で**約53TB**とめちゃくちゃ膨大。(1ファイルは大体1GB程度だったと思います)
ファイル移行元のサーバも分散している中、テスト環境でファイルバックアップバッチを使って試しに1サーバ分の転送を試してみるものの、1日待っても終わりません。

ファイル転送するデータ量が多いので時間がかかるのは解っていましたが、1日で1/3も終わっていないのは流石に何かある。

結論からいうと、AWSには I/O Credit というものがあり、猛烈にディスクへアクセスするとディスクへのI/Oに制限がかかってディスク性能が出なくなるのです。

今回の場合、HDDにファイルの通信とファイルの圧縮を並行して行ったため、ディスクへのI/Oアクセスが頻繁に行われ、I/O Credit が使われ出すとじわじわ性能が出なくなってしまったのでした。

移行先のストレージをHDDからSSDにしてしまえば、メモリへのI/Oアクセスになり I/O Credit を使用しません。しかし、ストレージをSSDにするとなればお金もかかってしまいます。

I/O Credit はディスクアクセスを行わなければ減っていくので、**I/O Credit の値をCloudWatchで監視しながら高騰してきたらバッチを止め、また０になったらバッチを再開する**という作業を繰り返して、約4日間かけて移行を終わらせました。

さて、本件では何が一番のしくじりポイントだったのでしょうか。

①　このデータ移行に巻き込まれる際、営業と話ができていなかった
②　AWSというものを詳しく理解していなかった。

今回は背景的に①はどうしようもなく、原因としては②が8割以上でした。
**特に I/O Credit というAWS固有の情報**を知らなかったのが原因といえるので、不明点がある場合には有識者や担当者様へ確認・質問するようにしましょう。

# しくじり事件簿　事件2：気付いた頃にはデータが30億レコードに
事件1とは別業種の案件をやっていたときの話になります。

お客様が指定した商品の情報を取得／蓄積／連携するという、よくありそうな(?)システムの保守を担当。

このシステムは、取得した商品の情報を**項目名と項目値で分けて持つ構造**になっており、事前にお客様が取得したい項目と突合し、取得結果にその項目がなかった場合はNULLデータとして保持していました。

その性質上、**突合項目がバラバラになる商品では取得項目が一致しない**ため、データが無尽蔵に増え続け、このテーブルが3年後には**約30億レコード**まで膨れ上がってしまったのです。

最大30億レコードあったテーブルにINDEXの設定を行っているので、データの登録・更新・削除するのに時間がかかったり、定期的に実施しているINDEXの再構築に2〜3日かかったりしました。

また、Web画面では分からないデータをお客様に見せるため、一部のテーブルに対してマテリアライズドビューを作っていたのですが、この膨れ上がったテーブルも対象にしていたばかりにデータ同期ができないというエラーが出るなど、絶望の日々が3年ほど続きました。

このままではシステムが廃止になってしまうため、以下の対策を行うことになりました。

　①　マテリアライズドビューの廃止
　②　不要なデータを登録しない
　③　不要レコードの削除

これにより、当該レコードは8000万レコードくらいまで減り、人の手をあまり介さず通常運用できるようになりました。


ここで学んだことは、

　①　データのリレーションを分けるのは良いが不要なデータを登録するような設計は決してすべきでない。
　②　トランザクションデータはマテリアライズドビューにしてはならない。
　③　巨大化しそうなデータは、事前にデータの登録日時などの項目でパーテーションの設定をする。
　④　Web画面を作る工数が惜しくてもお客様にDBを直接見せてはならない。

データのレコード件数が数千万件と聞いても、この案件と比べると大したことないと感じるようになってしまいました。

# しくじり事件簿　事件3：謎のプロセスダウンでデータ取得に失敗
これも事件2の案件をやっていたときの話になります。

商品の情報を取得するため、その情報ベンダー様から提供されたI/Fをモジュール内に組み込んで実行するのですが、一般的なWeb REST API ではなく提供しているライブラリにあるメソッドを読んでデータ取得をしていました。

テスト期間やサービスインした直後は問題なくデータ取得できていたのですが、ライブラリの改版を行った途端、データ取得するプロセスが定期的にプロセスダウンするようになりデータ取得ができなくなってしまいました。

プロセスダウンしたときにcoreファイルを出力していたので解析したところ、メモリアクセスする処理でプロセスダウンしていてたことは判ったものの、データ取得するプロセスのソースを読んでもNullPointerExceptionが起こるような使い方はしておらず、謎が深まります。

色々な対処を試してはまた発生してを繰り返して数か月、あるいは数年かかって、ようやく問題解決に至りました。

提供ライブラリのバージョンアップをする際、そのライブラリは別ディレクトリに格納していました。もちろん環境変数にそのパスを追加して書いていたのですが、実は**バージョンアップ前のライブラリがあったパスも消すことなく環境変数に残っていた**のです。

そして、バージョンアップ前のライブラリも環境変数に書かれた場所に置いたままだったので、そのライブラリを読まれることがプロセスダウンの原因と判明しました。

バージョンアップ前のライブラリ削除、および環境変数からその定義を削除することにより、プロセスダウンも発生しなくなりました。

ここで学んだことは、

　①　余計なファイルは残さない。
　②　設定している内容に不備がないことを確認する。
 
これに似たような別のしくじりになりますが、/tmp 配下に作業用ファイルを置き続けたところ、メモリ使用率が90％まで上がってシステム監視に引っかかってしまったということもありました。

バックアップを取るのは良いことですが、最大でも前回作業分ぐらいまでに留めて不要なファイルは削除しましょう。

また、定義のミスはハマりやすくて判りにくいので、クロスチェックするようにしましょう。

# しくじり事件簿　番外編：うっかりうっかり
これは私の失敗談ではなく、またまた別の案件をやっていたときに聞いたお話です。

試験フェイズで試験できるマシンが数台しかないので2交代で試験を行うのですが、夜勤帯の人が寝ぼけてスーパーユーザ(root)で作業できるターミナルからルート直下(/)で 
`rm -f *`
 というコマンドを打ったようです。
そうしたら、**跡形もなくシステムファイルもろとも消えてしまった**とのこと。

幸い、試験を実施するために使っていたマシンだったので、実利用ユーザには影響しませんでしたが、実運用のサーバでこんなコマンドを実行したら、利用ユーザに影響して損害賠償問題になってしまいます。本番作業は慎重に行いましょう。

現在ほとんどの案件では、本番作業は2人体制で作業を実行するようになっていることが多いでしょう。手順書を見ながら作業している人が実行するコマンドを一緒に確認しながら作業をしているので、こんな酷い凡ミスは起きないと思います。

余談ですが、本件で勇者級のやらかしをした人は、数日後に案件から逃げたようです。
体調が悪い場合は無理をせず、他の人に替わってもらうようにしましょう。
疲れて頭が回らないと、訳の分からないことをしがちですから。

# おわりに
いかがでしたでしょうか。

他人の失敗談を聞いてヒヤッとした方も、気を付けようと思った方もいらっしゃると思います。

失敗しても同じミスを繰り返さなければよいし、繰り返さない工夫をすればよいでしょう。

長く業界にいるSEですので、掘ればまだ失敗談はあると思います。また機会があればバッドノウハウを書かせていただければ幸いです。
お読みいただきありがとうございました。