toyama0919/fluent-plugin-http_shadowというShadow Proxyっぽいことを簡単にやるプラグインを作りました。
production環境で半年くらい動かしてたのでメモしときます。
「Fluentd Meetup 2015 夏」で実際のユースケースを発表しました。
Shadow Proxyサーバとは
Shadow Proxyサーバについては以下がわかりやすいです。
実装としては以下のようなものが公開されています。
本番のリクエストをそのままバックエンドにあるサーバーに複製して送信するのですが、アプリケーションの規模が大きくなればなるほど効果を発揮します。
規模が大きくなればなるほどテスト方法も複雑になってきます。
現在本番で発生しているrequestをそのまま持ってくることで、限りなく本番に近い状態を再現できます。
Shadow Proxy代表的なユースケースとしては負荷試験や結合試験になります。
これをもう少し簡単かつ安全に出来ないかと考え、fluentdで実現してみました。
概要
fluentdに送信されるログからhttp requestを復元しています。
Proxyは使わないので、本番のWEBサーバーには影響なく導入出来ます。
設定例(Apache等)
<source>
type tail
format ltsv
time_key log_time
time_format %d/%b/%Y:%H:%M:%S %z
path /var/log/httpd/access_log
pos_file /var/log/td-agent/access.pos
tag http_shadow.example
</source>
ログフォーマット例
{
"host": "exsample.com",
"ip_address": "127.0.0.1",
"server": "10.0.0.11",
"remote": "-",
"time": "22/Dec/2014:03:20:26 +0900",
"method": "GET",
"path": "/hoge/?id=1",
"code": "200",
"size": "1578",
"referer": "http://exsample.com/other/",
"user_agent": "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko"
}
設定はこう
<match http_shadow.example>
type http_shadow
host_hash {
"www.example.com": "staging.example.com",
"api.example.com": "api-staging.example.com",
"blog.ipros.jp": "blog-staging.ipros.jp"
}
host_key host
path_format ${path}
method_key method
header_hash { "Referer": "${referer}", "User-Agent": "${user_agent}" }
max_concurrency 10
flush_interval 10
timeout 10
rate 10
</match>
-
host_hashでVirtual Hostに対応できます。
- Host名に対応したrequest先を定義します。
-
rateが10の場合、requestが10%に希釈されます。(残りの90%は破棄される)
- ステージング環境が本番環境よりも低いスペックの場合などはrateを調節します
-
header_hashでhttp headerを指定できます。
- ${referer}のようにplaceholderでkeyを指定。
- 固定文字列も可能です。
-
apacheのログの場合、postのパラメータはないので欠損します。
設定例2(アプリ内で専用のログを作れる場合、Railsとか)
アプリケーションから以下のようなログを出す場合、
{
"host": "example.com",
"ip_address": "127.0.0.1",
"log_time":"2015-05-18 16:38:14",
"method": "GET",
"path": "/hoge/",
"uuid": "e78407cf040f67d17361281906895ca1283929e33592f81cdbda54a4a24e8cf7",
"session_id": "42d0c906bfde8a30d323865d82a234abb4d13db80471d3b0bf4b7adc515d06da903f514289340ca17ba5cedde118868deebe53ef3986bfae8b591b9a614f7242",
"user_id": 1
"params": {"utf8"=>"✓", "client_id"=>"384809"} ,
"referer": "http://exsample.com/other/",
"user_agent": "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko"
}
設定例
<match http_shadow.exsample>
type http_shadow
host_hash {
"example.com": "staging.example.com"
}
host_key host
path_format ${path}
method_key method
header_hash { "Referer": "${referer}", "User-Agent": "${user_agent}" }
cookie_hash {"rails-app_session": "${session_id}"}
params_key params
max_concurrency 10
flush_interval 10
timeout 10
rate 10
</match>
-
cookie_hashでcookieを送信も送信可能です。
- 設定方法はheader_hashと同じ
-
getやpostのパラメータはparams_keyの中にhashで格納しておけばパラメータをmergeします。
パラメータ
設定可能な値とデフォルト値
config_param :host, :string, :default => nil
config_param :host_key, :string, :default => nil
config_param :host_hash, :hash, :default => nil
config_param :path_format, :string
config_param :method_key, :string, :default => nil
config_param :header_hash, :hash, :default => nil
config_param :cookie_hash, :hash, :default => nil
config_param :params_key, :string, :default => nil
config_param :max_concurrency, :integer, :default => 10
config_param :timeout, :integer, :default => 5
config_param :username, :string, :default => nil
config_param :password, :string, :default => nil
config_param :rate, :integer, :default => 100
詳細
設定値 | 内容 |
---|---|
host | httpリクエストを送信するhost名 |
host_key | Virtual Hostの際の接続Hostのキー |
host_hash | Virtual Hostの際の接続Hostのペア |
path_format | urlのpathのフォーマット。${path}などでテンプレート化 |
method_key | http methodが定義されたキー。デフォルトはGET |
header_hash | http headerのペア |
cookie_hash | cookieのペア |
params_key | parameterが格納されたhashのkey |
max_concurrency | httpリクエストの並列数 |
timeout | タイムアウト時間(秒) |
username | Basic認証のユーザー名 |
password | Basic認証のパスワード |
rate | HTTPリクエストの希釈率。デフォルトが100で全てのリクエストがそのまま送信される。50ならば半分のリクエストが送信される。 |