[nginx]S3をバックエンドにngx_small_lightで画像を動的にリサイズ

nginxS3 で公開しているバケットをバックエンドに nginx モジュール ngx_small_light を利用して画像をリサイズする方法をメモ

http://d.hatena.ne.jp/akishin999/20130619/ にローカルの画像を対象にした画像変換手順が書かれているので、そこに S3 バックエンドを追記しただけとも言える。

ngx_small_light について

構成

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-toolsab をインストールする。
nginx.confsmall_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/

ngx_small_light benchmark

画質や 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:"
view raw template.p hosted with ❤ by GitHub

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'
view raw gistfile1.txt hosted with ❤ by GitHub

$ nginx -V のオプションを復元してコンパイルまで確認しただけで、細かい動作確認はしていない

ngx_small_light 以外の nginx 系動的な画像変換

nginx 標準の HttpImageFilterModule だけでリサイズ(2011/12 当時)

OpenResty+Lua/ImageMagickで画像変換

See Also

Leave a comment