2015年6月23日火曜日

ELB + Nginxでアクセス元IPアドレスを取得できるようにする

followtheseinstructions balancing https://www.flickr.com/photos/followtheseinstructions/6871361948/in/photolist-btcwvJ-kLNmB-pEqkEV-9LdVCR-e6ptdo-4KHT6F-ipytp-qtnMTQ-7Jv54j-rDRPnV-aJrjqD-TpXTt-4YGqj2-8VqoLR-66jA7n-713w4e-9RnAYq-mBmNr-fXPtKt-9DTPjg-jAgTSf-5Z3R3b-4J6sJx-7HXvnz-9herYu-a1rJqP-MuHLf-9M2hY-kZWKN-dhk9hV-8ooruK-oBvk1y-8PTEaE-6kcWZN-9mBnuR-fpd7mC-5G9EW-9qK22M-a1vKe3-FAfU4-jCn6m5-dgCPD8-9sqRoJ-8VsFMt-nw2A7-78mWWw-8FGGDL-7J2sqS-6s863B-8Vtr59
Module ngx_http_realip_module
http://nginx.org/en/docs/http/ngx_http_realip_module.html

ELBを使ったときに、EC2ではアクセス元のIPアドレスがELBのIPアドレスとなります。
このとき、ELBはヘッダー情報 X-Forwarded-For にクライアントのIPアドレス格納して情報をEC2に渡すので、これをNginxモジュールを利用して、リアルIPとして扱うように設定をすることができます。

以下、設定方法です。

現在のアクセス元のIPアドレスを確認。
確認のために phpinfo() のファイルを開いてみます。
これは、ELBのIPアドレスになっています。
# curl -s http://test-247271050.ap-northeast-1.elb.amazonaws.com/ | grep REMOTE_ADDR
_SERVER["REMOTE_ADDR"] 172.31.6.30
Nginx設定ファイルの http ディレクティブもしくは、server ディレクティブに追記。 ser_real_ip_from にELBのIPアドレスを設定します。VPCならばELBのサブネット・ネットワークアドレス(10.0.0.0/8)を指定します。
set_real_ip_from 172.31.0.0/12;
real_ip_header  X-Forwarded-For;
Nginxをリスタート
# /etc/init.d/nginx restart
REMOTE_ADDRを確認。
# curl -s http://test-247271050.ap-northeast-1.elb.amazonaws.com/ | grep REMOTE_ADDR
_SERVER["REMOTE_ADDR"] 52.69.60.48
クライアントのIPアドレスになりました。

Passengerのインストール時にNginxのモジュールを追加する方法

Gilles Klein morback.jpg https://www.flickr.com/photos/gilles_itzkovitchklein/113465270/in/photolist-dEnXug-dvAaeK-bNaXdV-aBT9uo-aA8brF-94bhss-89ebqc-7HtXwj-tQGxu-67QN3h-67QMjo-67LwnX-66XpqH-5Wkyfs-52zqHk-52c9gv-4UtYhS-4UpJfZ-4UtSoh-4UpBGT-4rLhSg-4kVHg4-4kVHen-4kZKwh-4kZKvf-4kZKu5-4kZKtu-4kZKsL-4kVH8M-4kZKqY-4kVH78-4kVH5V-BpNi9-BpJfY-8Bfix3-fHvZzN-5wa6hd-jp97fU-7UFAt9-3ggX9r-dvA9Ga-8S42MH-8S76vj-dvAW7R-55XBWP-8S76tQ-jp7hvp-b2xgL-nBowA6-7SQswu
http://wiki.nginx.org/HttpHeadersMoreModule#more_set_headers
Nginxのモジュール more_set_headers を使いたかったのですが。Passenger を使っている場合にはどのようにモジュールを追加したら良いのか解らなかったので調べました。
more_set_headersが必要なシーンはどんなときでしょう?以下の記事を参照してみましょう。
nginxで任意のHTTPヘッダーを追加したい場合にはadd_headerディレクティブを用いますが、add_headerディレクティブは追加しようとしたフィールド名が重複するHTTPヘッダーが既に用意されていた場合には既にある物に「,」区切りで連結してしまいます。たとえば強制的に出力するContent-Typeを変更するためにadd_header Content-Type text/css;のようにしてもContent-Type: text/html, text/cssといった形の不正なHTTPヘッダーが出力されてしまいます。
解決方法は簡単でHTTP Headers More Moduleのmore_set_headersディレクティブをつかえばすぐです。使い方も簡単でadd_headerディレクティブをつかっている箇所をそのままmore_set_headers "Content-Type: text/css";と置きかえれば良いだけです。
http://memo.overknee.info/post/20308520977

このように、クロスドメインな環境を設定したい時に使ったりするNginxモジュールです。
more_set_headers 'Access-Control-Allow-Origin: *';
以下。セットアップ方法です。

passengerがインストールされているか確認します。
$ gem list | grep passenger 
もし、なかったらインストールします。
$ gem install passenger
作業ディレクトリに移動。
$ cd /usr/local/src
Nginxを用意。
$ wget http://nginx.org/download/nginx-1.8.0.tar.gz
$ tar -zxf nginx-1.8.0.tar.gz
Passengerをインストール。
$ wget https://github.com/openresty/headers-more-nginx-module/archive/v0.26.tar.gz
$ tar xvfz v0.26.tar.gz
$ passenger-install-nginx-module 

 2. No: I want to customize my Nginx installation. (for advanced users)
2 # 2を選択

Where is your Nginx source code located?
Please specify the directory: /usr/local/src/nginx-1.8.0 # Nginxのディレクトリを指定

Extra arguments to pass to configure script: --add-module=/usr/local/src/headers-more-nginx-module-0.26 # モジュールのディレクトリを指定
インストールされたNginxを確認します。
# /opt/nginx/sbin/nginx -V
nginx version: nginx/1.8.0
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/opt/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --with-cc-opt=-Wno-error --with-pcre=/tmp/passenger.l7zbkj/pcre-8.34 --add-module=/usr/lib/ruby/gems/2.0.0/gems/passenger-5.0.7/ext/nginx --add-module=/usr/local/src/headers-more-nginx-module-0.26
headers-more-nginx-module-0.26 の文字が見えます。
あとは、このバイナリをいつも使っているNginxと置き換えればOKです。

2015年6月22日月曜日

Amazon Redshiftのバキュームに必要な時間


縦軸が分(minutes)、横軸がテーブルのレコード数です。

Table count minutes
25000 1
130000 1
41000000 7
400000000 65
670000000 210
2600000000 730
3000000000 1200
4800000000 4680

Amazon Redshiftのインスタンスタイプはds1.xlargeです。
数億分のデータをためた場合、どのくらいの時間でバキュームできるかを測ってみました。
バキューム実行コマンドは VACUUM FULL table_name; です。
(実際に使っているテーブルにバキュームをかけようとしているので、継続的にデータのインサートを行いながらの計測になります。そのためどんな環境で行っても同じ結果になるわけではないとおもいます。その点注意をお願いします。)
結果、1億程度ならば数分でバキューム完了しますが、10億を超えたあたりから実行時間が伸び、30億を超えるとほぼ1日がかりという時間が必要になりました。

まとめ
レコード数が大量になるにつれてバキューム実行時間が増えることがわかりました。
今回のバキューム中にはAmazon Redshiftのレスポンスが悪くなる現象は、とくにみられませんでした(すごい)、ですが、更に大量のデータを扱うときにはどうなるかわかりません。あらかじめテストしておくと良いでしょう。
すぐに数億のデータが溜まるようなテーブルを扱うときには。月ごと、日ごとのテーブルを用意して一つ一つのテーブルのサイズを小さく保つという運用をしたほうが、より少ない時間でバキュームができるので、パフォーマンスを維持できるとおもいます。

参考文献
テーブルのバキューム処理 - Amazon Redshift
http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/t_Reclaiming_storage_space202.html
VACUUM - Amazon Redshift
http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_VACUUM_command.html
Analyzeの必要性とvacuumの落とし穴
http://www.slideshare.net/motonobufukao/analyzevacuum
Amazon Redshift Useful SQL: VACUUM処理が必要なテーブルを洗い出す | Developers.IO
http://dev.classmethod.jp/cloud/aws/amazon-redshift-useful-sql-require-tables-to-vacuum/