Download - elixir in production
Elixir in Production
Elixir Meetup #1 in Drecom
Agenda• 発表の趣旨• 自己紹介– 最近の Elixir 事情
• 運用システム構成– 利用しているツール / ライブラリ群
• 運用 ( 負荷テスト ) 時のトラブル ( とその地雷処理 )– 事例 1. ログ– 事例 2. コネクションプール– 事例 3. アセット– その他
• まとめ
発表の趣旨• 本番運用事例の紹介をする事で– 本番採用事例が増える一助に– 採用ハードルが少しでも低く
• 本番運用時のトラブル対応の紹介をする事で– あるあるの事例と思うので、知見共有する事で同様のトラブル回避の手助けに
なったら良いなと思います
自己紹介• おーはら (@ohrdev)
• 写経 ( 仏教的 )/ 仏像彫り / 寺社仏閣• 広告エンジニア (Drecom)– Erlang/Elixir/Phoenix– Ruby/Rails– (Lisp/Scala)
最近の Elixir事情• コミックマーケット C89 で Phoenix 本発売– アランビックの錬金術師– http://hayabusa333.tumblr.com/– BOOTH: https://hayabusa333.booth.pm/items/
186705
• Elixir 1.2 released– https://github.com/elixir-lang/elixir/blob/v1.2.0/
CHANGELOG.md
最近の Elixir事情• Programming Elixir 1.2 (Dave Thomas)– https://pragprog.com/book/elixir12/programming
-elixir-1-2
– Β 版• Programming Phoenix– https://pragprog.com/book/phoenix/programmin
g-phoenix
– Β 版
運用システム構成• 広告配信 API/ ミニコンテンツ ( ゲーム )– F/W: maru( WAF/API DSL ) / Phoenix( WAF )– DB: Redis( exredis + poolboy ) / Dynamo( ex_aws )– Job: exq( + Sidekiq )– 環境変数 : dotenv– Deploy: exrm / mina / asset_sync( 自製 )– テスト : meck / power_assert– 監視 : sentry( raven-elixir ) / monit / 社内監視 tool– プロビジョニング : ansible( 自製 galaxy-role )– インフラ : AWS( EC2 / AutoScaling / ELB / S3 / CF )
利用ツール /ライブラリ• WAF:– maru: https://maru.readme.io/• 特徴 :
– シンプル /Api DSL(grape like)• 出来ない事 :
– セッション管理 /DB コネクション / テンプレート描画– Phoenix: http://www.phoenixframework.org/• 特徴 :
– フルスタック ( 一通り揃ってる )/maru に比べると複雑– アセットコンパイルは brunch.io を採用( node/npm が必要 )
利用ツール /ライブラリ• DB:– Redis:• exredis: https://github.com/artemeff/exredis• poolboy: https://github.com/devinus/poolboy
– Dynamodb:• ex_aws: https://github.com/CargoSense/ex_aws
– MySQL/PostgreSQL/Mongodb/etc• 弊社サービスでは採用していないのですが、恐らく ecto: https://github.com/elixir-lang/ecto 一択
利用ツール /ライブラリ• Job:– exq: https://github.com/akira/exq (+ sidekiq)– http://qiita.com/ohr486/items/
9db88866786ee8bb89d9
• 環境変数 :– dotenv: https://github.com/avdi/dotenv_elixir
利用ツール /ライブラリ• エラー監視 (sentry):– raven-elixir:
https://github.com/vishnevskiy/raven-elixir
利用ツール /ライブラリ• 死活監視 / 自動再起動– monit• DB/ ミドルウェア / 外部サービスの監視
– supervisor(OTP)• 言語の一部 (OTP) として提供される• きちんとチューニング / 設定しておくと安心できる
– 半年の本番運用で 2 回程お世話になった– パラメータの設定不備でプロセスが死亡する事象が発生したが、自動的にプロセスを監視 / 再起動して、サービスを落す事なく復旧 / 修正まで凌げた
利用ツール /ライブラリ• プロビジョニング :– ansible + galaxy-role: https
://galaxy.ansible.com/detail#/role/2930– Erlang/Elixir/Phoenix のバージョン up の頻度はかなり早いので、自動化しておくべき– Erlang と Elixir のバージョンの相性がある為、両方のバージョンを指定できると捗る
運用 (負荷テスト )時のトラブル• Elixir の開発 / 本番運用を約 1 年程やってきて、地雷はそれなりに踏み抜いてきました• 今回は特に– 開発時には発見し辛く、負荷テスト / 本番運用時に現れる– サービス規模 / トラフィックがある程度大きくなるまで現れない といった事例をピックアップしています
事例 1.ログ• 事象 : 大したリクエスト数でもないのに、
iowait が高まり LA / CPU 使用率が上昇
事例 1.ログ• 検証 :– サンプル http://github.com/falood/
maru_examples– ab で負荷をかけて計測 (echo_server)
$ ab -n 10000000 -c 2 http://xxx.xxx.xxx.xxx:8800/
$ vmstat -a 1
事例 1.ログ• 検証 :– vmstat の結果 : bo が異常値
$ vmstat -a 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free inact active si so bi bo in cs us sy id wa st 2 0 0 6807288 45796 562724 0 0 21 1242 11712 5338 37 25 30 8 0 1 1 0 6807156 45796 562988 0 0 0 4528 28259 5784 15 15 51 20 0 1 1 0 6806908 45800 563184 0 0 0 4484 28252 5717 15 16 50 20 0 0 1 0 6806660 45796 563384 0 0 0 4548 28171 5843 15 16 50 19 0 2 0 0 6806412 45796 563584 0 0 0 4556 28003 5825 15 15 51 20 0 1 1 0 6806288 45796 563780 0 0 0 4484 28262 5787 15 16 50 20 0 1 1 0 6806040 45796 563984 0 0 0 4488 28604 5868 14 17 50 19 0 2 1 0 6805792 45796 564180 0 0 0 4472 28473 5888 13 18 50 19 0 1 1 0 6805668 45800 564384 0 0 0 4480 28193 5772 15 16 50 19 0 1 1 0 6805420 45796 564580 0 0 0 4472 28356 5746 14 17 50 20 0 2 0 0 6805420 45796 564784 0 0 0 4492 28445 5757 14 16 50 19 0 1 1 0 6805172 45796 564980 0 0 0 4504 28393 5787 15 16 50 20 0 1 1 0 6804924 45796 565184 0 0 0 4456 28411 5671 13 17 50 20 0 2 0 0 6804676 45796 565380 0 0 0 4488 28169 5786 14 15 51 20 0 1 1 0 6804428 45800 565576 0 0 0 4504 28053 5761 13 17 50 20 0
事例 1.ログ• 検証 :– logger の backend がデフォルト (console) だと、
O_SYNC モードでログファイルが open されるhttps://github.com/erlang/otp/blob/maint/erts/etc/common/run_erl_common.c
– naoya さんの記事 (Linux I/O のお話 write 編 )http://d.hatena.ne.jp/naoya/20070523/1179938637
– 『アプリケーションが SYNC モードでファイルを開いていたり、明示的に fsync() してたりするとそこで wait が発生するのはいわずもがな、です。』
事例 1.ログ• 事象 : 大したリクエスト数でもないのに、
iowait が高まり LA / CPU 使用率が上昇• 原因 :logger のバックエンドがデフォルトの console だった(為、ログファイルを
O_SYNC モードで開いていた)ので、毎秒ディスクへの同期とフラッシュが走っていた
事例 1.ログ• 対応– 本番環境の logger の backend を console から変更– ※ Elixir の Logger の backend は公式には consoleしか提供されていない
• https://github.com/elixir-lang/elixir/tree/master/lib/logger/lib/logger/backends
• https://github.com/onkel-dirtus/logger_file_backend• https://github.com/basho/lager
– logger_file_backend はカスタマイズに難ありだったので backend を自前実装した
事例 1.ログ• 教訓 :– 本番環境のログの backend は必ず fileベースのものに変更すること– 負荷テスト時のサーバー状況のチェックは必ず実施する事(あたりまえですが)
事例 2.コネクションプール• 事象 : リクエストを大量に長時間なげ続けると、 ElasticCache(Redis) のコネクション数があふれる
事例 2.コネクションプール• 状況 :–各種 DB ドライバのコネクション管理事情• PostgreSQL/MySQL/MSSQL/SQLite3/MongoDB
– ecto: https://github.com/elixir-lang/ecto– コネクション管理 ( 内部的には poolboy で実装 ) を含む
• Redis– exredis: https://github.com/artemeff/exredis– クライアントのみ、コネクション管理は含まれない
• Dynamodb– ex_aws: https://github.com/CargoSense/ex_aws– APIベースなのでコネクション管理なし– Read/Write Capacity Unit の設定で担保
事例 2.コネクションプール• 状況 :– ( コネクション管理をしていなかったので ) リクエスト毎に Redis のコネクションを確立していた– ElasticCache(Redis) のコネクション• コネクションタイムアウト : デフォルト 5分• コネクション上限数 :2万
– 開発時は、コネクション数自体が少なく、上限にいくまでにタイムアウトで切断されていたので気がつかなかった、高負荷をかけて初めて発覚
事例 2.コネクションプール• 事象 : リクエストを大量に長時間なげ続けると、 ElasticCache(Redis) のコネクション数があふれる• 原因 :Redis のコネクション管理をしていなかった / するドライバを使っていなかった
事例 2.コネクションプール• 対応 :– コネクション管理を含む Redis ドライバを使用• https://github.com/quarkgames/exredis_pool• https://github.com/le0pard/redis_pool• 問題点 : コネクションプールの設定が貧弱 /十分にチューニングできない
– poolboy でコネクションプールを自前実装• 参考 : たのしい poolboy(@hagiyat さん )• http://qiita.com/hagiyat/items/
a28683d01223bfc204d9
事例 2.コネクションプール• 教訓 :– Redis を使う際は、コネクション管理に注意、必ずコネクション管理機構を実装する事– poolboy は良実装( Erlang の良いお手本コード)– 負荷テスト時のサーバー状況のチェック( ry
事例 3.アセット• 事象 :AWS のデータ転送量の費用が増大• 原因 :EC2 上に deploy した phoenix アプリのアセット ( 画像 /css/js/font/etc) の転送量だった
事例 3.アセット• Phoenix のアセットの参照 :– digest: 静的ファイルを圧縮して manifest を作成• phoenix.digest (mix コマンド )• manifest.json に、圧縮前後のファイルパスの mapping を
JSON形式で出力する– cache_static_manifest != true (config.exs)• 静的ファイルを priv/static 以下から参照
– cache_static_manifest == true (config.exs)• manifest.json をパースして、 ets(Erlang の In-memory ストレージ ) にマッピング情報をストア• 静的ファイル参照時に、圧縮後のファイルを参照させる
事例 3.アセット• 改善前の手順– 1. アセットの参照方法を manifest に
– 2. 圧縮ファイルと manifest.json を作成• MIX_ENV=prod mix phoenix.digest
– 3. MIX_ENV=prod でアプリを起動– 4. 2. のマッピング先 (圧縮後ファイル ) が参照
# config/prod.exsconfig :my_app, MyApp.Endpoint, http: [port: xxxx], url: [host: “xxxx”], cache_static_manifest: “priv/static/manifest.json”, server: true
事例 3.アセット• アセット参照の実体 (static_path/2)– Phoenix.Route.Helpers # static_path/2• https://github.com/phoenixframework/phoenix/blob/
master/lib/phoenix/router/helpers.ex
– MyApp.Web # web ( web/web.ex )• import MyApp.Router.Helpers
– static_path/2 が import されて利用可能に– View/css/javascript # static_path/2• static_path/2 でアセットを参照
事例 3.アセット• アセット参照の実体 (priv/static参照 )– http://xxx.xxx.xxx.xxx:4000/images/hoge.png• priv/static/images/hoge.png が参照される
– http://xxx.xxx.xxx.xxx:4000/css/var.css• priv/static/css/var.css が参照される
事例 3.アセット• 対応 :– Phoenix には asset_sync 相当のライブラリが
( 自分が調べた限り採用できそうなのものが )存在しなかった– Rails の asset_sync 相当のライブラリを自前実装• 対象ファイルのアセットファイルを s3 に upload• static_path/2 を、 s3/cloudfront を参照しにいく様に差換える• アセットファイルをバージョン管理 (sync/cleanup)
事例 3.アセット• 対応 :– asset_sync(phoenix 版 ) は、もう少し本番運用した後、 hex に公開予定–仮リポジトリ /参考実装(テスト / ドキュメント /残ン実装対応中):
• https://github.com/ohr486/asset_sync–注意 :
• 2016/1 現在、 ex_aws の s3 は東京リージョンから一部機能が利用できません• https://github.com/CargoSense/ex_aws/pull/101 の修正が hex に publish されるまでパッチを当てるなりして下さい
事例 3.アセット• 教訓 :– インフラコストはちゃんと監視する事– Phoenix on AWS で画像を扱う際は、転送量に注意、必要に応じて CloudFrontへ– 負荷テスト時のサーバー状況のチェック (ry
その他• 地雷処理の為にやった事 / 必要だった事– ドキュメント (英語 ) を読む• 日本語の情報はまだまだ不足
–実装コード (Elixir/Erlang) を読む• Erlang の参照ライブラリを読むケースはそれなりにある( Erlang のライブラリを wrap しただけの
Elixir ライブラリ)– awesome-elixir/awesome-erlang のチェック• 他の実装ライブラリや、似た様な機能を探す際に便利、定期的に追いかけておくと何かと捗る
その他• 地雷処理の為にやった事 / 必要だった事– 地雷処理できる人を増やす活動• Erlang が読めるように
– Elixir独自の機能はありますが、やはりベースは Erlang です– Erlang を Ruby の Syntax で記述している感じ
• OTP の概念を理解できるように– OTP の理解無しに Elixir のアプリ運用はできない(と感じた)
• 関数型言語を理解する– 社内勉強会(すごい E 本 / コップ本読書会)– Erlang に自信が無い場合は、時雨堂さんにコンサルをお願いすれば良いんじゃないでしょうか
まとめ• 弊社にて運用している Elixir のサービスについての紹介をしました• 本番運用時に発生したトラブルとその対応を紹介しました• (完璧では無いですが )十分に本番で運用できています• まだまだ足りない機能 / ライブラリがあるので、もっと充実してきて欲しいです ( 自分ももっと公開していきます )