S3 で公開しているバケットをバックエンドに nginx モジュール ngx_small_light を利用して画像をリサイズする方法をメモ
http://d.hatena.ne.jp/akishin999/20130619/ にローカルの画像を対象にした画像変換手順が書かれているので、そこに S3 バックエンドを追記しただけとも言える。
ngx_small_light について
- github で公開 https://github.com/cubicdaiya/ngx_small_light
- pixiv の中の人が開発した nginx モジュール
- Apache 向け mod_small_light の nginx 移植 https://code.google.com/p/smalllight/
- 画像変換エンジンは ImageMagick/Imlib2/GD から選択可能
構成
client ↔ nginx(1.4.4) ↔ S3 という構成で考える
インストール
今回は画像変換を ImageMagick と GD と imlib2 に対応させる。
nginx は EC2(Amazon Linux) 上に構築
基本的な手順は github の wiki にまとまっている https://github.com/cubicdaiya/ngx_small_light/wiki
コンパイルに必要なプログラムのインストール
# yum groupinstall -y "Development Tools" # yum install -y git
ngx_small_light 系パッケージのインストール
# yum install -y pcre-devel zlib-devel openssl-devel gd-devel # yum install -y ImageMagick ImageMagick-devel # yum install http://dl.fedoraproject.org/pub/epel/6/x86_64/imlib2-1.4.2-5.el6.x86_64.rpm \ http://dl.fedoraproject.org/pub/epel/6/x86_64/imlib2-devel-1.4.2-5.el6.x86_64.rpm or # yum install http://pkgs.repoforge.org/imlib2/imlib2-1.4.4-1.el6.rf.x86_64.rpm http://pkgs.repoforge.org/imlib2/imlib2-devel-1.4.4-1.el6.rf.x86_64.rpm
nginx のコンパイル
nginx は動的モジュールや ABI には対応していないので、 ngx_small_light と一緒に nginx をコンパイルし直す必要がある。
nginx 本体をダウンロード # wget http://nginx.org/download/nginx-1.4.4.tar.gz # tar zxfv nginx-1.4.4.tar.gz # cd nginx-1.4.4 ngx_small_light をダウンロード # git clone https://github.com/cubicdaiya/ngx_small_light.git # cd ngx_small_light/ # ./setup --with-imlib2 --with-gd # enable ImageMagick and Imlib2 and GD config is generated. # ngx_small_light=`pwd` # cd .. # ./configure --with-pcre --add-module=$ngx_small_light --user=nginx --group=nginx ... Configuration summary + using system PCRE library + OpenSSL library is not used + md5: using system crypto library + sha1: using system crypto library + using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" # make # make install ... test -d '/usr/local/nginx/logs' || mkdir -p '/usr/local/nginx/logs' test -d '/usr/local/nginx/html' || cp -R html '/usr/local/nginx' test -d '/usr/local/nginx/logs' || mkdir -p '/usr/local/nginx/logs' make[1]: Leaving directory `/root/src/nginx-1.4.4'
/usr/local/nginx
以下にインストールされる
デーモン管理の設定
# wget -O /etc/init.d/nginx 'http://wiki.nginx.org/index.php?title=RedHatNginxInitScript&action=raw&anchor=nginx' # chmod +x /etc/init.d/nginx # vi /etc/init.d/nginx nginx や NGINX_CONF_FILE のあたりを修正 # chkconfig --add nginx # chkconfig --list nginx nginx 0:off 1:off 2:off 3:off 4:off 5:off 6:off # service nginx configtest nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful # service nginx start Starting nginx: [ OK ]
S3 の設定
前提として、S3 でウェブサイトをホストする。
やり方は次のドキュメントを参照
http://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html
S3 のエンドポイントは「バケット名.リージョン.amazonaws.com」となる。
ngx_small_light の設定
http://ec2.host/resize/w/image-width/h/image-height/S3.path
という URL でアクセスすると
- S3 上でパス S3.path にある画像が
- 横幅 image-width
- 高さ image-height
の画像にリサイズされるようにする。
/usr/local/nginx/conf/nginx.conf の
server { listen 80; server_name localhost; }
のブロックに以下の設定を追加
# ngx_small_light を有効にする small_light on; # ngx_small_light 用の URL を組み立てる location ~ ^/resize/w/(.+)/h/(.+)/(.+)$ { set $width $1; set $height $2; set $file $3; # 画像変換エンジンを指定。デフォルトは "imagemagick"。インストールしていれば "gd" や "imlib2" も指定可能 set $engine "imagemagick"; proxy_pass http://127.0.0.1/small_light(dw=$width,dh=$height,e=$engine)/images/$file; } location ~ small_light[^/]*/(.+)$ { set $file $1; rewrite ^ /$file; } # /images 以下の URL を S3 にリバースプロキシさせる # /images/foo.png は s3://bucketname/foo.png に対応 location /images/ { proxy_pass http://bucket-name.s3-website-ap-northeast-1.amazonaws.com/; }
参考にした http://d.hatena.ne.jp/akishin999/20130619/ にある実質的な設定の違いは、最後に S3 へのリバースプロキシ設定を追加しただけ。
使ってみる
$ curl -D - -i -o /tmp/test.png http://ec2-dummy.region.compute.amazonaws.com/resize/w/400/h/400/test.png % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0HTTP/1.1 200 OK Server: nginx/1.4.4 Date: Sat, 11 Jan 2014 14:02:42 GMT Content-Type: image/png Content-Length: 7955 Connection: keep-alive x-amz-id-2: AzbEZ8/8kDYqlxPVVc5K1PRjp3gk1Jbt7iJg/CeMrIjnHEtJqkGbG6xxwi/eX6v4 x-amz-request-id: A2D3EB8202C3EEF0 Last-Modified: Sat, 11 Jan 2014 11:35:34 GMT ETag: "a1a4809d472e0d6de560f870a87cf923" 100 7955 100 7955 0 0 24497 0 --:--:-- --:--:-- --:--:-- 24552
ブラウザで上記 URL にアクセスすると、リサイズされた画像を確認できる。
ベンチマーク
- 2500px x 1712px の JPEG 画像を 400px x 400px にリサイズ。
- 画像変換は ImageMagick と GD と imlib2 で比較。
- ab を使って4並列で100リクエストし、処理時間を計測。
ab でリクエスト
$ sudo yum install httpd-tools
で ab をインストールする。
nginx.conf
の small_light(dw=$width,dh=$height,e=$engine)
で e(engine) に “imagemagick” または “gd” または “imlib2” を設定し ab でリクエストを実行
$ ab -n 100 -c 4 -g im.tsv http://ec2-dummy.region.compute.amazonaws.com/resize/w/400/h/400/test.jpg
ImageMagick
Concurrency Level: 4 Time taken for tests: 270.511 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 9036700 bytes HTML transferred: 9002000 bytes Requests per second: 0.37 [#/sec] (mean) Time per request: 10820.440 [ms] (mean) Time per request: 2705.110 [ms] (mean, across all concurrent requests) Transfer rate: 32.62 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.3 0 2 Processing: 2511 10710 7523.7 7895 33207 Waiting: 2510 10709 7523.8 7895 33206 Total: 2511 10710 7523.7 7895 33207 Percentage of the requests served within a certain time (ms) 50% 7895 66% 9909 75% 12924 80% 17394 90% 24913 95% 28355 98% 32746 99% 33207 100% 33207 (longest request)
GD
Concurrency Level: 4 Time taken for tests: 114.975 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 11608400 bytes HTML transferred: 11573600 bytes Requests per second: 0.87 [#/sec] (mean) Time per request: 4599.014 [ms] (mean) Time per request: 1149.754 [ms] (mean, across all concurrent requests) Transfer rate: 98.60 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 1 Processing: 1807 4442 1961.1 4075 13837 Waiting: 1807 4441 1961.1 4075 13837 Total: 1807 4442 1961.1 4076 13837 Percentage of the requests served within a certain time (ms) 50% 4076 66% 4861 75% 5250 80% 5662 90% 6608 95% 8301 98% 11413 99% 13837 100% 13837 (longest request)
imlib2
Concurrency Level: 4 Time taken for tests: 105.709 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 3775900 bytes HTML transferred: 3741200 bytes Requests per second: 0.95 [#/sec] (mean) Time per request: 4228.350 [ms] (mean) Time per request: 1057.088 [ms] (mean, across all concurrent requests) Transfer rate: 34.88 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 1 Processing: 1581 4146 2323.3 3533 15179 Waiting: 1580 4146 2323.3 3533 15179 Total: 1581 4146 2323.3 3533 15179 Percentage of the requests served within a certain time (ms) 50% 3533 66% 4399 75% 5280 80% 5612 90% 6624 95% 9106 98% 11103 99% 15179 100% 15179 (longest request)
gnuplot でリクエスト処理時間をプロット
ab のベンチマーク結果を imagemagick 向けは imagemagick.tsv, gd 向けは gd.tst 、imlib2 向けは imlib2.tsv に出力し、次の URL を参考に gnuplot で可視化。
http://www.kutukupret.com/2011/05/10/graphing-apachebench-results-using-gnuplot/
画質や CPU 使用率やメモリ使用量などを無視して単純に処理時間だけをみると、ImageMagick より GD と imlib2 のほうがかなりはやい。
GD と imlib2 では imlib2 がわずかにまさる
利用した gnuplot スクリプトは以下
# http://www.kutukupret.com/2011/05/10/graphing-apachebench-results-using-gnuplot/ | |
# collect data | |
# $ ab -n 100 -c 4 -g imagemagick.tsv url | |
# $ ab -n 100 -c 4 -g gd.tsv url | |
# $ ab -n 100 -c 4 -g imlib2.tsv url | |
# plot data | |
# $ gnuplot template.p | |
# output as png image | |
set terminal png | |
# save file to "benchmark.png" | |
set output "benchmark.png" | |
# graph a title | |
#set title "ab -n 100 -c 4" | |
set title "nginx ngx_small_light(ImageMagick vs gd vs imlib2)" | |
# nicer aspect ratio for image size | |
set size 1,0.7 | |
# y-axis grid | |
set grid y | |
# x-axis label | |
set xlabel "request" | |
# y-axis label | |
set ylabel "response time (ms)" | |
# plot data from "gd.tsv" and "imagemagick.tsv" and "mlib2.tsv" using column 9 with smooth sbezier lines | |
plot "gd.tsv" using 9 smooth sbezier with lines title "gd:", \ | |
"imagemagick.tsv" using 9 smooth sbezier with lines title "imagemagick:", \ | |
"imlib2.tsv" using 9 smooth sbezier with lines title "imlib2:" |
Amazon Linux と同じコンパイルオプションを指定
Amazon Linux の yum パッケージでインストールされる nginx と同じオプションでコンパイルするには次の gist のようにする
$ sudo yum install -y libunwind perl-ExtUtils-Embed gperftools gperftools-libs gperftools-devel libxslt libxslt-devel GeoIP GeoIP-devel | |
$ ./configure \ | |
--add-module=./ngx_small_light \ | |
--prefix=/usr/share/nginx \ | |
--sbin-path=/usr/sbin/nginx \ | |
--conf-path=/etc/nginx/nginx.conf \ | |
--error-log-path=/var/log/nginx/error.log \ | |
--http-log-path=/var/log/nginx/access.log \ | |
--http-client-body-temp-path=/var/lib/nginx/tmp/client_body \ | |
--http-proxy-temp-path=/var/lib/nginx/tmp/proxy \ | |
--http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi \ | |
--http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi \ | |
--http-scgi-temp-path=/var/lib/nginx/tmp/scgi \ | |
--pid-path=/var/run/nginx.pid \ | |
--lock-path=/var/lock/subsys/nginx \ | |
--user=nginx \ | |
--group=nginx \ | |
--with-file-aio \ | |
--with-ipv6 \ | |
--with-http_ssl_module \ | |
--with-http_spdy_module \ | |
--with-http_realip_module \ | |
--with-http_addition_module \ | |
--with-http_xslt_module \ | |
--with-http_image_filter_module \ | |
--with-http_geoip_module \ | |
--with-http_sub_module \ | |
--with-http_dav_module \ | |
--with-http_flv_module \ | |
--with-http_mp4_module \ | |
--with-http_gunzip_module \ | |
--with-http_gzip_static_module \ | |
--with-http_random_index_module \ | |
--with-http_secure_link_module \ | |
--with-http_degradation_module \ | |
--with-http_stub_status_module \ | |
--with-http_perl_module \ | |
--with-mail \ | |
--with-mail_ssl_module \ | |
--with-pcre \ | |
--with-google_perftools_module \ | |
--with-debug \ | |
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' \ | |
--with-ld-opt=' -Wl,-E' |
$ nginx -V
のオプションを復元してコンパイルまで確認しただけで、細かい動作確認はしていない
ngx_small_light 以外の nginx 系動的な画像変換
nginx 標準の HttpImageFilterModule だけでリサイズ(2011/12 当時)
- 手順
http://cloudrop.jp/labs/nginx_image_filter - HttpImageFilterModule モジュールのマニュアル
http://nginx.org/en/docs/http/ngx_http_image_filter_module.html
OpenResty+Lua/ImageMagickで画像変換
- 手順
http://leafo.net/posts/creating_an_image_server.html - HackerNews
https://news.ycombinator.com/item?id=6419064 - ソースコード
https://github.com/leafo/magick
See Also
- 画像ライブラリGrappyの作成と、ImageMagick, GDとの比較
http://www.cyberagent.co.jp/recruit/techreport/report/id=7850 - 発表資料