Top Banner
nginx + lua + ObjectStorage ファイルアップロード/ダウンロードの高速化 2014.12.11 Code the Clouds Mix-up Vol.2 株式会社MNU 雪本修一
26

nginx + lua + ObjectStorage ファイルアップロード/ダウンロードの高速化

Jul 21, 2015

Download

Engineering

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

nginx + lua + ObjectStorage ファイルアップロード/ダウンロードの高速化

2014.12.11 Code the Clouds Mix-up Vol.2 株式会社MNU 雪本修一

Page 2: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

雪本 修一Shuichi Yukimoto株式会社MNU 代表取締役社長 電気通信大学の認定ベンチャーとして起業。 現在も現役プログラマとしてコードを書いている。 好きな言語はJavaScript,Scheme,Lisp,Python SoftLayerを使い始めて一年ぐらい 弊社はSoftLyerのリフェラルパートナーです。

twitter:@nsas454 facebook:shuichi.yukimoto

Page 3: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

今日のお話

• PBOXで実装した技術についてのご紹介

• nginxの拡張モジュールを使ったアップロードとダウンロードの高速化を実現した仕組み

• nginxの拡張モジュールの実装方法について

Page 4: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

nginx• ロシアのIgor Sysoev氏によって、1日に5億リクエストを処理するWebサイトのHTTPサーバーとして開発された

• 注目されるようになったのは、C10K問題(クライアント1万台問題、注2)が叫ばれるようになった2000年代後半です

Page 5: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

Lua• 動的型付言語

• 高速に動作する

• ゲームなどで広く利用されている言語

• インクリメンタルGCで有名

• nginxもluaで実装されているそうです。

• wikipediaより

Page 6: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化
Page 7: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化
Page 8: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

• pboxはnginx + gunicornで構成されているが、ファイルのアップロード、ダウンロード処理をgunicornでやるのは高コスト

• アップロード/ダウンロードには複雑な処理は必要無いにもかかわらず、gunicornのセッションを専有するのは良くない!

ファイル

nginx gunicorn object Storage

フロントエンド バックエンド ストレージ

認証/リクエスト

PUT

Page 9: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

• nginx拡張でなるべく多くの同時リクエストを捌きつつ、静的ファイルの送受信を行う

ファイル

nginx object Storagegunicorn

redis tornade

LUA

フロントエンド バックエンド ストレージ

PUT

PUTリクエスト認証/ストレージ情報

Page 10: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

何故nginx拡張を使うのか?• pboxはnginx + gunicornで構成されているが、ファイルのアップロード、ダウンロード処理をgunicornでやるのは高コスト

• アップロード/ダウンロードには複雑な処理は必要無いにもかかわらず、gunicornのセッションを専有するのは良くない方法

• nginx拡張でなるべく多くの同時リクエストを捌きつつ、静的ファイルの送受信を行う

Page 11: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

nginx + HttpLuaModule

Page 12: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

インストール

• luajitのインストール

• nginx + HttpLuaModuleのビルド&インストール

• 詳細は

• http://wiki.nginx.org/HttpLuaModule

Page 13: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

nginx.conf• luaモジュールをインストールしたら、専用のディレクティブが使える

• 例えば、content_by_lua_file でcontentフェーズにluaを呼び出すことができる。

• 参考: http://wiki.nginx.org/HttpLuaModule#Directives

• nginxのフェーズについては http://wiki.nginx.org/Phases を参照

• レスポンス全体をluaで作る場合はcontentフェーズを使う。認証だけluaを使う場合はaccess_by_lua_file ディレクティブを使用するなどの使い分けを行う。pboxでどうしているかは後述

Page 14: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

nginxのフェーズ

• nginx の Phase のうち、Rewrite, Access, Content, Log のフェーズに対してフックする仕組みを提供

Page 15: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

lua-nginx-module が提供する主なフックの仕組み

• Rewrite Phase

• set_by_lua:変数の設定、ヘッダの操作、リダイレクト等が可能

• rewrite_by_lua:Rewrite Phase の最後で実施され、自由度の高い rewrite処理を実現可能

• Access Phase

• access_by_lua:自由度の高い認可処理を実現可能

• Content Phase

• content_by_lua:コンテンツの生成

• header_filter_by_lua:コンテンツ生成後、header に対するフィルタ処理(書き換えや追加など)に対応

• body_filter_by_lua:コンテンツ生成後、body に対するフィルタ処理

• Log Phase

• log_by_lua:ログ処理のタイミングで動作。ここでリクエストの情報を変数にためておくことで、nginx + lua だけで集計の仕組みを作ることも可能

Page 16: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

luaで何ができるのか?

• 特に重要なのは以下の2つ

• サブリクエスト

• tcp/udpソケット通信

• 詳しくは下記で説明

Page 17: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

サブリクエスト

• ざっくり言えば、他のlocationを呼ぶ機能

• ngx.location.captureを使用する

• 一度のリクエストで何回もサブリクエストを呼ぶことができたりする

Page 18: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

tcp/udpソケット通信• ngx.socket.tcp / ngx.socket.udp でソケット通信ができる。luaの組込ソケットと互換のインターフェイスを持っているが、内部動作が違うのでかならずこちらを使うこと。

• このソケットはnon-blockで動作し、待ち時間で別のリクエストを処理してくれる

• pboxではこのソケットの上にHTTPプロトコルを実装したlua-resty-httpを使用してObjectStorageとの通信を行っている。

Page 19: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

アップロード/ダウンロードの概要

• pboxのファイルアップロード/ダウンロードは以下の動作が必要

• 認証:リクエストヘッダで送られてくる認証トークンが正しいかSQLに保存された情報との比較を行う。また、ここでObjectStorageへのurl、認証情報を取得する

• ObjectStorageへのアップロード/ダウンロード:1で得られた情報を元に実際にファイルをアップロード/ダウンロードする

• (アップロードの場合のみ)SQLへアップロードしたファイルのメタ情報を保存する:ObjectStorageで管理できない追加情報をpbox持たせるため、ファイル・ディレクトリの情報はSQL側で持っている

Page 20: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

HttpLuaModule• pboxはcontentフェーズでluaを使用し、

• 1. 認証を内部サブリクエスト

• 2. オブジェクトストレージへのアクセスにソケット

• 上記を使用しているが、次のようにする方法もあった(RestfulなAPIのために断念した)。

Page 21: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

余談• ダウンロード: accessフェーズのみluaで行い、contentはObjectStorageへプロキシすることもできる(proxy_passディレクティブを使う)。

• アップロード: ObjectStorageへのアップロード前と後にluaの処理が入る。(またレスポンスはObjectStorageのものを直接使わず、メタ情報をjson返したい。)そのため、contentフェーズをluaで書く。

Page 22: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

まとめ• nginxのフェーズの概念は超重要。1つは省力化のため。アップロードはproxy_passを使うことでluaの記述を減らすこともできる(pboxではやらないが)。

• もう1つは出来ることが違う。たとえば、accessフェーズでレスポンスの中身を書き換えることはできない。logフェーズや、post_actionではluaからサブリクエストが使えないなど、フェーズを意識する必要がある。

Page 23: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

さいごに

• とりあえず、重要な事は2つだけ

• サブリクエスト(ngx.location.capture)はマジ便利

• 100% non-blockingなHTTP通信でObjectStorageへアクセスしてます

Page 24: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

Appendix

Page 25: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

location /internals { internal; proxy_pass http://backend; } location ~ /([^/]+)/files/(.*)$ { content_by_lua_file content_file.lua; }

nginx.conf

Page 26: nginx + lua + ObjectStorage  ファイルアップロード/ダウンロードの高速化

local http = require "resty.http"local cjson = require "cjson"

local user = ngx.var[1] -- location の $1 相当local path = ngx.var[2] -- location の $2 相当

--- 認証 local res = ngx.location.capture('/internals/auth', { args = { token = token, user=user, path=path },})

if res.status ~= 200 then ngx.exit(res.status)end

--- ObjectStorageへのURL,Tokenを認証時に返してもらう local body = cjson.decode(res.body)local host = body.hostlocal path = body.pathlocal token = body.token

--- 通信確立 local httpc = http.new()httpc:connect(host, 80)

--- ObjectStorageへGETリクエスト発行 local res, err = httpc:request{ path = path, method = 'GET', headers = {['X-Auth-Token'] = token}}

--- レスポンスボディをそのままnginxのレスポンスとして返す local reader = res.body_readerrepeat local chunk, err = reader(chunk_size) ngx.say(chunk)until not chunk

content_file.lua