Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
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/9db88866786ee8b
b89d9
• 環境変数:
– 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 1
procs -----------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/com
mon/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/a28683d01223bfc204d
9
事例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.exs
config :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のサービスについ
ての紹介をしました
• 本番運用時に発生したトラブルとその対応を
紹介しました
• (完璧では無いですが)十分に本番で運用でき
ています
• まだまだ足りない機能/ライブラリがあるので、
もっと充実してきて欲しいです(自分ももっと公
開していきます)

More Related Content

elixir in production