みなさん、障害対応してますか?
今回はインフラをある程度経験していれば、なんとなく当たりがつくような、サイトにアクセス出来ない時のパターンをいくつか紹介します。
パターンを知っているだけで調査のあたりの付け方が早くなるので、いつかきっと役に立つ日がくるでしょう。
インフラ: AWS
Webアプリケーション: Rails
Webサーバ: Nginx
アプリケーションサーバ: Unicorn or Puma
調査のキモ
まず最初に調査のキモについて。
ここだけ押さえておけば大体なんとかなる、きっと。
ログを見ること
エラーログはシステムのダイイングメッセージ。
ログに全ての答えがあります。
まずはWebサーバ、アプリケーション、各ミドルウェアのログを良く見ましょう。
どこまでは正常に動作して、どこでエラーが発生したのかの原因を切り分けやすくなります。
HTTPステータスを見ること
chromeのdevtoolなどを使って、どんなHTTPステータスが帰ってきているのか確認しましょう。
ここにも重要な情報が隠れています。
アクセスできないという場合のHTTPステータスは404なのか、504なのかによって、対応が変わってきます。
単純化すること
httpアクセスするのであれば、curlコマンド
DBアクセスするのであれば、mysql-client
を使うことで問題がどこにあるのかの切り分けがやりやすくなります。
他にも色々あるかと思いますが、アプリケーションを介さずに、実行できる処理は原因の切り分けをやりやすくなリますね。
アクセス元のIPが重要な場合もあるので、どこでコマンド実行をするかも大事。
Webサイトに繋がらないパターンについて
ここからいろんなパターンを紹介していきたいと思います。
- よくあるやつ
- 501 timeout、応答が長すぎます...
- 502 bad gateway
- 503
- その他エラー
よくあるパターン
Webサーバ(Nginx、Apache等)が起動していない
起動しましょう。
起動しているかどうかの確認は service nginx status
とかで確認するとたまにPIDファイルだけ生き残ってプロセスが死んだ場合に嘘つくのでpsコマンドでちゃんとプロセスが起動しているかを確認する方が確実です。
ps aux | grep nginx
意図せず落ちてしまっていた場合は、Webサーバのログ、もしくは /var/log/messages
などのシステムログを見ると落ちた原因がわかるかもしれません。
セキュリティグループで許可されていない
AWSを使う場合、ポートごとのアクセス制限にセキュリティグループを使うことになると思いますが、セキュリティグループの設定をしくじってアクセスできない、っていうこともよくあります。
80と443は解放されていたけど、DBで使うポートやredisで使うポートなどもあるので、アプリケーションのログでどこに接続できていないエラーをチェックしてセキュリティグループの設定を見直しましょう。
よくわからないから、とりあえず全解放とかダメですよ
ACLで許可されていない
AWS ACL(Access Control List)をいじることはあまりないかと思うのですが、ここで設定をミスっているとハマります。
VPC > セキュリティ > ネットワークACL
から設定できます
セキュリティグループと同じように、ポート番号とソースIPを指定してアクセス許可をコントロールできるので、セキュリティポリシーに合わせて適切に設定しておきましょう。
504 Gateway Timeout
timeoutで接続できないこともあります。
ブラウザ側で応答長すぎと怒られることもあるかと思いますが、ここで紹介するエラーは、サーバには一応到達しているパターンです。
Webサーバに設定されているtimeout時間を超えてしまっている
Nginx側で設定しているtimeoutの時間を超えてしまった場合はtimeoutエラーの画面になります。
この場合はどこかに重たい処理が潜んでいるので、それをどうにかしなければならないのですが、これはインフラの話から少々外れてしまうのでここでは特に追求しません。
とりあえずお茶を濁すのであればtimeout時間を伸ばすことで解決できます。
Nginxで設定できるtimeoutの項目いっぱいあるのですが、Nginx + Unicornの構成であれば
proxy_read_timeout
に設定は注意しておきましょう。
参考: https://qiita.com/syou007/items/3e2d410bbe65a364b603
アプリケーションサーバのtimeout
UnicornとかPumaで設定するtimeout時間です
アプリケーションサーバでエラーになるとNginx側でエラーログが出力されます。
エラーメッセージ
2018/11/29 18:35:34 [error] 9294#0: *147 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 172.30.0.119, server: xxxx.xxxx.xxxx, request: "GET / HTTP/1.1", upstream: "http://unix:///var/www/xxxx.xxxx.xxxx/current/tmp/sockets/puma.sock/", host: "172.30.0.233"
timeout時間の設定方法
Unicorn
timeout 30
Puma
worker_timeout 30
ロードバランサーのtimeout
ロードバランサーにもtimeout設定があります。
デフォルト60秒なので、これをこえる設定をNginxやUnicornでしてもロードバランサー側も変えておかないと意味ないですね。
まあ、60秒超える時点でどうなんだっていうのはありますが...
ec2 > ロードバランサー > 属性 > 属性の編集
から変更ができます。
設定しているリバースプロキシ先にアクセスできない
Nginxでリバースプロキシ設定をして、他のサーバの処理を委ねることができます。
このリバプロ先のサーバが上であげたような現象でアクセスできなければ、結果サイトの表示ができないです。
リバプロをしているかどうかは、ログなどからはパッと見でわかりずらいのでハマりやすい。
リバースプロキシ設定の例
/etc/nginx/conf.d/proxy.conf
/example
にアクセスしたら、https://proxy.example.com
にリクエストします
location ~ ^/example {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://proxy.example.com;
}
Nginxの名前解決に注意
プロキシ設定をするときにNginxは最初に起動して名前解決をしたものをずっと保持し続けるため、サーバのIPが変わったりしてしまった場合にエラーになってしまうことがあります。
これはハマります。
502 bad gateway
アプリケーションサーバ側でエラーになると、このエラーが出たりします
2018/11/30 10:19:39 [error] 3241#0: *1592 connect() to unix:///var/www/xxx.xxx.xxx.xxx/current/tmp/sockets/puma.sock failed (111: Connection refused) while connecting to upstream, client: xxx.xx.x.xx, server: xxx.xxx.xxx.xxx, request: "GET / HTTP/1.1", upstream: "http://unix:///var/www/xxx.xxx.xxx.xxx/current/tmp/sockets/puma.sock:/", host: "xxx.x.x.xx"
アプリケーションサーバのプロセスが起動していない(unicornなど)
起動しましょう。
これもpsコマンドで起動しているかどうかをちゃんと見ます
ps aux | grep unicorn
こちらもWebサーバ(Nginxなど)と同じで、意図せず落ちてしまっていた場合は、Unicornのログ、もしくは /var/log/messages
などのシステムログを見ると落ちた原因がわかるかもしれません。
メモリ不足で落ちることなんかもあります。
ロードバランサーに紐づいているインスタンスが間違っている
たまにボケて全然関係ないロードバランサーにインスタンスを紐づけてしまうことがあります。
ロードバランサーの名前とかを適当につけているとよくあります。
ちゃんと合っているか確認しておきましょう。
Classic Load Balancerでヘルスチェックで失敗している
これから新しくロードバランサーを立てるのであればALBを基本使うと思うので、もうあまりこの現象になることはなさそうですが
昔のロードバランサーはヘルスチェックがちゃんと通っていないインスタンスにはアクセスができないようになっていました。
じゃALBはどうなっているんだというと
正常なターゲットが含まれているアベイラビリティーゾーンがない場合、ロードバランサーノードはすべてのターゲットにリクエストをルーティングします。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/target-group-health-checks.html
なので、ヘルスチェックがエラーになっていてもアクセスはできます。
とはいえ、ちゃんとヘルスチェックは設定しておきましょう。
503エラー
Webサーバの接続数が上限を超えている
Apache: max_clients
Nginx: worker_connections
Webサーバの設定接続数を超えてアクセスがあると503エラーになります。
この場合はちゃんとしたアクセスか、そうでないアクセス(botとか)かで対応方法が変わります。
アクセスログを見てIPアドレスが、妙に国外からのアクセスが多いとかであればbotの可能性が高いです。
ちゃんとしたアクセス
これが増えているのであれば、Webサーバの設定値をあげるか、サーバ台数を増やしましょう。
botとか
不要なアクセスであれば、ブロックしたいです
できればWAFなどを使ってブロックするのが好ましいでしょう。
お手軽にやるのであればセキュリティグループで該当のIPアドレスをブロックするのが早いです。
WAFの機能紹介はこちらを見てみてください
https://tech.basicinc.jp/articles/144
間違ってGoogleのクローラをブロックすると検索結果に表示されなくなってしまうので注意
サーバ設定間違っているパターン
VirtualHostの設定が間違っている
NginxやApacheで VirtualHostの設定をするところがあるのですが、そこをミスっている可能性あります。
server {
listen 80;
server_name example.com; ← ここ!
}
DNSの向き先が合っていない
そんな馬鹿なことあるか、っていう感じですが...
ここを間違っていると他で色々調べていることが全部無駄になっちゃいます。
サーバのアクセスログ等を見てアクセスが来てなかったら、ここも疑いましょう。
DNSがどこで設定されているかよくわからない?
そんな時は whois
コマンドを使って確認することができます
whois <ドメイン名>
すると Name Serverの欄がきっとあると思います。
そこに書かれているサーバがDNSサーバです。
Name Server: xxxxxxxxxxxxxxxxxx
Name Server: xxxxxxxxxxxxxxxxxx
Name Server: xxxxxxxxxxxxxxxxxx
Name Server: xxxxxxxxxxxxxxxxxx
xx-xx.AWSDNS-xx.xxx
というのがあれば AWS Route53
を使ってます。
DBアクセスできないパターン
DBサーバの状況によって対応方法が分かれます。
DBサーバの状況を確認するにはクライアントソフトを使って、アプリケーションを介さずに接続の確認をした方が原因を切り分けやすいです。
MySQLであれば mysql-client
を直接コマンド叩いてつなげて確認してみよう、ということですね。
とりあえず以下はMySQLの話です
そもそもリモート接続できるようになっていない
mysql-client
で接続できない状態ですね。
- ポートが開放されていること(セキュリティグループ)
- リモート接続ユーザーが登録されていること
- bind-address が設定されていること
この3つをチェック
リモート接続できるユーザの確認
mysql> select user, host, password from mysql.user;
+------------------+-----------------+-------------------------------------------+
| user | host | password |
+------------------+-----------------+-------------------------------------------+
| root | localhost | |
| root | ip-xxx-xx-x-xxx | |
| root | 127.0.0.1 | |
| root | ::1 | |
| | localhost | |
| | ip-xxx-xx-x-xxx | |
| db-user-name | xxx.xx.x.% | xxxxxx |
+------------------+-----------------+-------------------------------------------+
7 rows in set (0.00 sec)
登録されていければgrantコマンドで登録
GRANT ALL PRIVILEGES ON *.* TO mydb-user@"192.168.%" IDENTIFIED BY 'password' WITH GRANT OPTION;
bind-address の確認
設定ファイルのbind-addressで確認できます。
bind-address 192.168.0.1
やり方は調べるといくらでも出てくるかと思いますが、参考記事をどうぞ
https://support.plesk.com/hc/ja/articles/213904365-MySQL-%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%82%B5%E3%83%BC%E3%83%90%E3%81%B8%E3%81%AE%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E6%9C%89%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF
DBサーバの負荷が高く接続できない
サーバのリソース状況(CPU、メモリ)を確認して見ましょう。
RDSであれば該当のRDSインスタンスを選択すれば見れます。
ここでCPU使用率が高くなってしまっていればDBに負荷がかかっています。
あとは実際に問題となっているであろう、実行されているクエリを確認して見ます。
show full processlist
実行にめっちゃ時間かかっていそうなのがあればkill
なんかいっぱいクエリがある場合は、こちらをどうぞ
MySQLで処理に長時間かかっている複数クエリをまとめて殺す方法
DBの最大接続数を超えている
Webサーバと一緒でDBも最大接続数を持ってます。
最大接続数を確認
mysql> SHOW GLOBAL VARIABLES like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
今の接続数
mysql> SHOW STATUS like 'Threads_connected';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 4 |
+-------------------+-------+
変更
[mysqld]
max_connections=300
他には単純にDB接続数を減らすために、アプリ側でキャッシュを作成するなどしてDBアクセスを減らしていきましょう。
テーブルロックがかかっている
バッチ処理などでうっかりやってしまう可能性があるのですが、トランザクションをかけてテーブルを更新すると、commitするまでロックがかかります。
そうするとロックがかかったテーブルを別で更新しようとすると、ロック待ちでタイムアウトしちゃいます
mysql> begin;
mysql> update sample set updated_at=CURRENT_TIMESTAMP where id=1
こうするとほかからsampleテーブルを更新できなくなってしまう。
外部サービスからデータが取得できずエラー
APIなどを使って外部からデータを取得して、それを表示するようなWebサイトの場合、APIで正しくデータが取れない場合にエラーになることもあります(アプリケーションの作りによります)
サーバのリソース状況を見ていても気づきにくいタイプのエラーなので、アプリケーションのログをよく見る必要がありますね。
その他のサイト表示されないパターンについて
その他って言っても幅広いのですが、よくあるやつの紹介です。
複数サーバのうち調子が悪いサーバがある
何回かリロードした時に表示できたり、表示されなかったりする場合はアクセスするサーバによって違う可能性があります。
ディスク容量が100%
ディスク容量が100%の場合の挙動がどうなるのかはなんとも言えないのですが、バッチが動かなかったり、Webサーバ再起動したら起動に失敗したり、ファイルのダウンロードができなかったりとか...いろいろです。
確認方法
[root@ip-172-30-0-233 log]# df -h
ファイルシス サイズ 使用 残り 使用% マウント位置
devtmpfs 2.0G 56K 2.0G 1% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
/dev/xvda1 12G 6.3G 5.4G 54% /
inodeが枯渇
キャッシュを大量につくっていると起こる可能性があります。
こうなると容量が空いていてもファイルが何もつくれなくなってしまいます。
余計なファイルを消しましょう。
確認方法
[root@ip-172-30-0-233 log]# df -i
ファイルシス Iノード I使用 I残り I使用% マウント位置
devtmpfs 503720 438 503282 1% /dev
tmpfs 505961 1 505960 1% /dev/shm
/dev/xvda1 786432 504596 281836 65% /
最後に
なんでもそうなのですが、インフラも経験をどれだけするかが大きいです。
障害が発生した場合はどうしても最速で対応をする必要があるので、わかっている人、得意な人が対応をしてしまうので、苦手意識がある人はどうしても一歩引いて見てしまいがちです。
ただシステム障害は(ちょっと言い方あれかもしれませんが...)インフラについて学べる最高の機会です!是非積極的に関与をしていきましょう。
あとは障害対応するときは、できる限りチャットなどで実況中継をするようにして他の人が何をやっているのか分かるようにしておくと他の人が関わりやすくなるのでおススメです。
この辺のインフラ障害に対しての取り組み方は
システム障害と僕達はいかにして戦えば良いのか、障害対応について考えた
こちらにまとまっているので、是非読んで見てください。