Connection Draining とは
ELB には Connection Draining という機能がある.2014年3月に追加された機能で,現在新規に ELB を作成するとデフォルトで有効になっている(300秒).ただし,2014年3月時点で既に稼働していた ELB に関しては無効になっているため注意が必要.
簡単に表現すると,インスタンスを ELB から deregister したタイミングで実行中だったリクエストを切断せずに継続できる機能と言える.Connection Draining が無効になっていると,deregister したタイミングで切断されてしまう場合があって,デプロイなど ELB を操作するときにクライアントに 5xx が返ってしまう.
- Register or deregister EC2 instances for your Classic Load Balancer - Elastic Load Balancing
- Configure connection draining for your Classic Load Balancer - Elastic Load Balancing
検証してみた
手元にあった PHP 環境で検証してみた.検証の内容を簡単に書くと,長めのリクエストを要求するのと同時に ELB から deregister して,レスポンスが返ってくるかどうかを確認した.スクリプトは PHP で60秒 sleep する感じで雑に書いた.
ちなみに,環境によって nginx や php-fpm あたりにリクエストのタイムアウト設定があって,そもそも返ってこないという場合がありえるため,そこは適宜変えてもらえれば.今回は php-fpm の request_terminate_timeout
を長めに変更した.
<?php set_time_limit(0); echo "START\n"; echo " sleep 60 second\n"; sleep(60); echo "END\n";
Connection Draining 無効の場合
504 が返ってきた.Connection Draining が無効になっているため,deregister のタイミングで実行中だったリクエストが切断された.
$ curl http://example.com/sample.php --verbose (中略) < HTTP/1.1 504 GATEWAY_TIMEOUT < Content-Length: 0 < Connection: keep-alive <
Connection Draining 有効(300秒)の場合
ちゃんと60秒後にレスポンスが返ってきた.素晴らしい.
$ curl http://example.com/sample.php --verbose (中略) < HTTP/1.1 200 OK < Content-Type: text/html; charset=utf-8 < Date: Wed, 18 May 2016 06:58:26 GMT < Server: nginx < Content-Length: 28 < Connection: keep-alive < START sleep 60 second END
ちょっとした疑問
ドキュメントに書いてある通り,AWS CLI で Connection Draining を変更する場合は aws elb modify-load-balancer-attributes
で実行できるけど,aws elb describe-load-balancers
で確認することはできなかった.awscli に自分でパッチを当てると確認できるようになるらしいけど,そこまで頑張る気にならなくて諦めた.最新の AWS CLI 1.10.30 でも確認できなくて,ちょっと残念だ.
$ aws --version aws-cli/1.10.30 Python/2.7.10 Darwin/15.4.0 botocore/1.4.20
まとめ
Connection Draining は ELB に register されたインスタンスに対する Graceful Stop 的な機能と言えるし,基本的には有効にしておくべきだと感じた.デフォルトの300秒に関しては,そのままでも良いし,アプリケーションのタイムアウト設定を考慮してもう少し減らしても良いとは思う.