HAProxy の external-check で Read Replica から Master に昇格した Amazon Aurora に接続できないようにする
追記 2016/07/22 19:06
error: 'Lost connection to MySQL server at 'reading initial communication packet', system error: 0'
というエラーがでて接続できなくなる現象が発生するようなので、改良が必要なようです。
エラーの検証をしようとしたら再現できなかったので、とりあえず気にしなくても良さそうです。
追記 2016/07/19 18:48
ブックマークにもコメントいただきましたが、
SHOW GLOBAL VARIABLES LIKE 'innodb_read_only';
を実行して、
OFF なら master、ON なら Read Replica という判断方法もあります。
Amazon Aurora を使用する際のベストプラクティス に書いてあります。
なぜ、これを使わなかったかというと、検証したときは知らなかったからです…
検証した環境は以下の通りです。
$ haproxy -v HA-Proxy version 1.6.6 2016/06/26 Copyright 2000-2016 Willy Tarreau <willy@haproxy.org> $ cat /etc/system-release Amazon Linux AMI release 2016.03
RDS for MySQL は Multi-AZ 構成にした場合、スタンバイ用のインスタンスにアクセスできません。
Amazon Aurora(以降、Aurora) はスタンバイ用インスタンスが Read Replica となっているため参照することができます。
Aurora を HAProxy で参照分散するとき、Read Replica のいずれかが Master に昇格するため、
Read Replica のつもりで参照していたインスタンスが Master になっている可能性があります。
Slave 参照しない Read Replica を用意し、Master に昇格させるインスタンスの優先順位を調整することで、
HAProxy からは Master に参照することがないように調整することも可能ですが、
一台は余剰なインスタンスとなってしまいますし、3台構成の場合に Master と Read Replica 1台が同時にダウンした場合どうするかなど、
考慮しなくてはならないことがたくさんあります。
もちろん、Master を参照しても負荷的に問題なければ良いですが、Slave 参照する場合は Master への負荷を軽減したい場合でしょうから問題になるケースが多いのではないでしょうか。
以上のことから、HAProxy の mysql-check では意図しない挙動をしてしまいます。
そこで、HAProxy の external-check という、任意のコマンドでヘルスチェックを行う機能を利用できないか検証しました。
haproxy.conf
使用した設定ファイルです。
global external-check resolvers mydns nameserver dns1 10.2.0.2:53 nameserver dns2 8.8.8.8:53 resolve_retries 3 timeout retry 1s hold valid 60s defaults log 127.0.0.1 local1 debug retries 2 timeout connect 3000 timeout server 5000 timeout client 5000 frontend f_mysql_slave bind 127.0.0.1:3307 default_backend b_mysql_slave backend b_mysql_slave log 127.0.0.1 local1 debug mode tcp option external-check external-check path "/usr/bin:/bin:/usr/local/bin" external-check command /usr/local/bin/check_mysql_slave.sh balance roundrobin server slave test-db01.xxxxxx.ap-northeast-1.rds.amazonaws.com:3306 check resolvers mydns server master test-db.cluster-xxxxxx.ap-northeast-1.rds.amazonaws.com:3306 check resolvers mydns backup
external-check を使うためには、
global external-check backend b_mysql_slave option external-check external-check path "/usr/bin:/bin:/usr/local/bin" external-check command /usr/local/bin/check_mysql_slave.sh
が必要です。
server master ... backup
は Read Replica が全部ダウンしたときのみ Master を参照するための設定です。
external-check command
HAProxy がコマンドを実行する際に環境変数を設定するようになっています。
環境変数は以下のとおりです。
- HAPROXY_PROXY_ADDR
- backend の bind IP
- backend に定義した bind は無視されるので実質使用しない(はず)
- HAPROXY_PROXY_ID
- backend ID.
- HAPROXY_PROXY_NAME
- backend 名
- HAPROXY_PROXY_PORT
- backend の bind port
- backend に定義した bind は無視されるので実質使用しない(はず)
- HAPROXY_SERVER_ADDR
- server の IP
- HAPROXY_SERVER_CURCONN
- server のカレントコネクション数
- HAPROXY_SERVER_ID
- server の ID
- HAPROXY_SERVER_MAXCONN
- server の 最大コネクション数
- HAPROXY_SERVER_NAME
- server の設定名
- HAPROXY_SERVER_PORT
- server で設定したホストの port
- PATH
- external-check path で設定した PATH
詳細は external-check command を参照してください。 環境変数を上から順に出力した例は以下のとおりです。
2 b_mysql_slave 10.206.1.20 0 2 0 slave 3306 usr/bin:/bin:/usr/local/bin
check_mysql_slave.sh
ヘルスチェックを行うスクリプトです。
#!/bin/bash BACKUP="master" MASTER_IP=$(dig +short test-db.cluster-cnttkfxtxwao.ap-northeast-1.rds.amazonaws.com | tail -n 1) [ "${MASTER_IP}" = "" ] && exit 1 [ "${HAPROXY_SERVER_NAME}" = "${BACKUP}" ] && exit 0 [ "${HAPROXY_SERVER_ADDR}" != "${MASTER_IP}" ]
${MASTER_IP}
が取得できなければ fail${HAPROXY_SERVER_NAME} = ${BACKUP}
の場合、backup 以外のインスタンスはダウンしているので Master を参照するようにする${HAPROXY_SERVER_ADDR} != ${MASTER_IP}
の場合、Read Replica を参照しているのでヘルスチェックを success にする
追記: 2016-07-25 16:05
SHOW GLOBAL VARIABLES LIKE 'innodb_read_only';
を使う場合は以下のようになります。
#!/bin/bash BACKUP="master" READ_ONLY=$(mysql -u haproxy -h ${HAPROXY_SERVER_ADDR} -P ${HAPROXY_SERVER_PORT} -BN -e "SHOW GLOBAL VARIABLES LIKE 'innodb_read_only';" --connect-timeout=5 | awk '{print $2}') [ "${HAPROXY_SERVER_NAME}" = "${BACKUP}" ] && exit 0 [ "${READ_ONLY}" = "ON" ]
DNSを引く場合と違って、BACKUP
以外は環境ごとに変わる要素がなくなったので使いやすくなっています。
検証結果
Master と Read Replica それぞれ 1 台ずつで 2 種類の検証を行いました。
Read Replica が Master に昇格した場合
backup の設定は削除した状態です。
server slave = Master なのでヘルスチェックに失敗しています。
Read Replica が 1 台なので no server available になっていますが、Read Replica が 2台以上ある場合は、
Read Replica には接続できて、Master には接続できない状態になります。
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1032ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1032ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN. Server b_mysql_slave/slave is DOWN. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. Server b_mysql_slave/slave is DOWN. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. backend b_mysql_slave has no server available! backend b_mysql_slave has no server available!
backup を設定して、Read Replica が Master に昇格した場合
backup 以外の server のヘルスチェックに失敗して、backup のみヘルスチェックに成功した場合のログです。
Master 以外ダウンしているときは Master に接続できるようになっていることがわかります。
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 0/2 DOWN. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 0/2 DOWN. Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue. Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue. b_mysql_slave/master changed its IP from 10.2.0.10 to 10.2.1.20 by mydns/dns1. b_mysql_slave/master changed its IP from 10.2.0.10 to 10.2.1.20 by mydns/dns1. Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1015ms, status: 1/2 DOWN. Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1015ms, status: 1/2 DOWN. Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1007ms, status: 3/3 UP. Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1007ms, status: 3/3 UP. Server b_mysql_slave/slave is UP. 1 active and 1 backup servers online. 0 sessions requeued, 0 total in queue. Server b_mysql_slave/slave is UP. 1 active and 1 backup servers online. 0 sessions requeued, 0 total in queue. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN. Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN. Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue. Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue.
まとめ
HAProxy の external-check で、Aurora の Read Replica が Master に昇格したときに参照させないようにすることができました。
また、Read Replica が全台ダウンしたときだけ Master を参照できることも確認できました。
独自のヘルスチェックが行えるので、他にも応用ができそうですね。
Amazon Linux で certbot(letsencrypt) を使って SSL 証明書を取得する
※2016年5月16日現在の情報です。
バージョンが変わると動作しなくなる可能性があります。
letsencrypt のクライアントが certbot に改名したようです
(See: https://github.com/certbot/certbot)。
Amazon Linux 上で certbot-auto(letsencrypt-auto) を使って SSL 証明書を取得する手順を検証しました。
検証した環境は以下のとおりです。
- certbot-auto(letsencrypt-auto) 0.6.0
- Amazon Linux 2016.03
- amzn-ami-hvm-2016.03.1.x86_64-gp2 (ami-29160d47)
- Nginx 1.8.1
コマンドはすべて ec2-user で実行しました。
試行錯誤した結果、
https://github.com/certbot/certbot/issues/2872#issuecomment-211959637
のように pip と virtualenv のバージョンを上げたらうまくいきました。
pip と virtualenv のバージョンを上げる
sudo easy_install pip sudo pip install --upgrade pip
pip をアップグレードすると、/usr/local/bin/pip
に最新版の pip がインストールされたので、
以降はこちらを使います。
sudo /usr/local/bin/pip install --upgrade virtualenv
letsencrypt 環境を作成
virtualenv で letsencrypt 環境を作成します。
mkdir -p ~/.local/share virtualenv -p /usr/bin/python27 ~/.local/share/letsencrypt . ~/.local/share/letsencrypt/bin/activate
certbot-auto を実行
例では Nginx を使っていますが、Apache や certbot の Standalone Web サーバを使いたい場合は適宜変更してください。
Nginx や Apache を使う場合は予め起動しておいてください。
curl -s -L -O https://dl.eff.org/certbot-auto chmod +x ./certbot-auto ./certbot-auto certonly --webroot -w /usr/share/nginx/html -d your.domain --agree-tos -m your@email.address --debug
以下の様な出力になったら成功です。
yum install の出力 ... Checking for new version... Creating virtual environment... Installing Python packages... Installation succeeded. Requesting root privileges to run certbot... sudo CERTBOT_AUTO=./certbot-auto /home/ec2-user/.local/share/letsencrypt/bin/letsencrypt certonly --webroot -w /usr/share/nginx/html -d your.domain --agree-tos -m your@email.address --debug Version: 1.1-20080819 Version: 1.1-20080819 IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/your.domain/fullchain.pem. Your cert will expire on 2016-08-14. To obtain a new version of the certificate in the future, simply run Certbot again. - If you lose your account credentials, you can recover through e-mails sent to your@email.address. - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
証明書の更新
以下のコマンドでできるようなので定期的に実行して、Web サーバを reload するようにしておくと自動更新できると思います。
./certbot-auto renew --webroot -w /usr/share/nginx/html --force-renew --debug Checking for new version... Requesting root privileges to run certbot... sudo CERTBOT_AUTO=./certbot-auto /home/ec2-user/.local/share/letsencrypt/bin/letsencrypt renew --webroot -w /usr/share/nginx/html --force-renew --debug ------------------------------------------------------------------------------- Processing /etc/letsencrypt/renewal/your.domain.conf ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- new certificate deployed without reload, fullchain is /etc/letsencrypt/live/your.domain/fullchain.pem ------------------------------------------------------------------------------- Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your.domain/fullchain.pem (success)
Github Webhook を受けて任意のスクリプトを実行するツール
ghooks-cmd-runner という、
Github の Webhook を受けて任意のスクリプトを実行する Go 製のツールを書きました。
Installation
https://github.com/tkuchiki/ghooks-cmd-runner/releases にバイナリがあるので、ダウンロードして解答してください。
Usage
$ ./ghooks-cmd-runner --help usage: ghooks-cmd-runner --config=CONFIG [<flags>] Receives Github webhooks and runs commands Flags: --help Show context-sensitive help (also try --help-long and --help-man). -c, --config=CONFIG config file location -p, --port=18889 listen port --host="127.0.0.1" listen host -l, --logfile=LOGFILE log file location --pidfile=PIDFILE pid file location --version Show application version.
config ファイルが必要なので、以下の様な TOML ファイルを用意します。
# port = 18889 (default: 18889) # host = "0.0.0.0 (default: 127.0.0.1)" # secret = "your webhook secret" # logfile = "path to logfile (default: stdout)" # pidfile = "path to pidfile" [[hook]] event = "push" command = "/path/to/script" [[hook]] event = "pull_request" command = "/path/to/script"
[[hook]]
の event
と command
を必要な分記述して、スクリプトを用意すれば完了です。
ghooks-cmd-runner
がスクリプトを実行する際、GITHUB_WEBHOOK_PAYLOAD
という環境変数に payload の JSON テキストを base64 でエンコードした文字列を格納しますので、環境変数を読んで base64 でデコードすればお好きな言語で payload を受け取とることができます。
シェルスクリプトで書くと以下のようになると思います。
echo ${GITHUB_WEBHOOK_PAYLOAD} | base64 -d ...
daemonize の機能はないので各自で行ってください。
追記
〜 2016-05-18 17:00
以下のバージョンをリリースしています。
- v0.1.2
- コマンドの標準(エラー)出力を1行ずつログに書き出すように修正
- v0.1.3
- hook[].branch オプション追加
- イベント毎に、正規表現にマッチした branch のみでコマンドを実行可能に
- hook[].branch オプション追加
- v0.2.0
- イベント毎に、コマンドを直列実行するように修正
時刻文字列をいい感じに parse する Go の package
parsetime という時刻文字列をいい感じに parse する Go のライブラリを書きました。
Example
使用例です。
package main import ( "fmt" "github.com/tkuchiki/parsetime" "log" ) func main() { p, err := parsetime.NewParseTime() if err != nil { log.Fatal(err) } t, err2 := p.Parse("2016-01-02T03:04:05") if err2 != nil { log.Fatal(err) } // Local timezone: JST // 2016-01-02 03:04:05 +0900 JST fmt.Println(t) }
以下、NewParseTime
と Parse
の説明です。
NewParseTime
NewParseTime
は 0 ~ 2 の引数を指定可能です。
引数を指定しなければ local の *time.Location
をセットした状態の time.Time を返します。
第一引数には *time.Location
と Asia/Tokyo
や JST
のような文字列を指定できます。
Asia/Tokyo
のような文字列を指定した場合は、
time.LoadLocation
して *time.Location
をセットします。
JST
のような文字列を指定した場合は、
その文字列から offset を取得して time.FixedZone
を実行します。
第一、二引数に JST
のような文字列、offset を指定した場合も time.FixedZone
を実行します。
ParseTime
構造体には、SetLocation
というメソッドを用意しているので、あとから変更することも可能です。
Parse
Parse
に時刻文字列を指定すると、time.Time
と error
を返します。
Parse
は、time.Parse
ではなく、正規表現でキャプチャして time.Date
を使う実装になっています。
最初に実装した時は、time.Parse
の format を大量に用意しておいて、
parse できるまでループで回していたのですが、正規表現を使ったほうが柔軟に対応できそうだったので実装しなおしました。
15:04
のように、時、分だけ指定した場合、実行した年月日を設定した time.Time
を返すようになっています
(time.Parse
をループで回していたときはこれができていませんでした)。
対応している文字列は、ISO8601、RFC 3339、RFC822, RFC850, RFC1123 などです。
01/02/2006 15:04:05
や11:04 PM
、Jan 2, 2006 at 3:04am (MST)
のような形式にも対応しています。
parse 可能な時刻文字列の例は https://github.com/tkuchiki/parsetime#examples を参考にしてください。
php-build が libphp[57].so を上書きしないようになりました
php-build が libphp5.so を上書きしないようにするパッチ で、
php-build が libphp5.so を上書きしてしまう問題を紹介しました。
2015-12-11 に Remove hard-patch code for APXS handling #353 が merge され、
libphp5.so(PHP 7 は libphp7.so なので、以降 libphp?.so) が上書きされないようになりました。
@tkak さんに Avoid overwriting apache module installed into user's libexec dir #204 を送って頂いていたのですが、方針と合わなかったのかこれ自体は Merge されませんでした。
送っていただいた Pull Request 自体が Merge されなかったのは残念ですが、
@tkak さんのお力添えで問題が解決されるまでに至りました。
ありがとうございました!
使い方
with_apxs2
という関数が追加されましたので、definitions に追記します。
# https://github.com/php-build/php-build/blob/master/bin/php-build#L491-L501 function with_apxs2() { local apxs="$1" shift if [ -z "$apxs" ]; then apxs="$PHP_BUILD_APXS" fi PHP_BUILD_APXS="$apxs" configure_option "--with-apxs2" "$apxs" }
# https://github.com/php-build/php-build/blob/master/bin/php-build#L576-L580 # Use php-build prefix for the Apache libexec folder if [ -n "$PHP_BUILD_APXS" ]; then apxs_libexecdir=$($PHP_BUILD_APXS -q LIBEXECDIR) sed -i"" -e "s|'\$(INSTALL_ROOT)${apxs_libexecdir}'|${PREFIX}${apxs_libexecdir}|g" ${source_path}/Makefile fi
となっていますので、apxs に path が通っていれば with_apxs2
、
通っていなければ with_apxs2 /path/to/apxs
と書けば libphp?.so の install path が変わります。
php-build には default_configure_options という、
全バージョン共通の configure のオプションを記述するファイルがあります。
こちらに --with-apxs2 /path/to/apxs
を書いても、
libphp?.so の install path が変更されませんのでご注意ください。
また、definitions に configure_option "--with-apxs2" "/path/to/apxs"
と書いても同様です。
しかし、異なるバージョンの php を install するごとに definitions を編集するのは大変です。
全部に追記したい場合は、以下のコマンドを実行すれば追記されます。
$ find /path/to/definitions -type f -print | xargs -I{} sh -c "grep -qs with_apxs2 {} || perl -p -i -e 'print \"with_apxs2 /usr/bin/apxs\n\" if $. == 1' {}"
追記済みの場合は何もしないので安心してお使いいただけるはずです。
上記のコマンドは色々な環境でも動くようにしたものですので、
GNU sed のある環境でしか使わない場合は以下のコマンドでも同じことができます。
$ find /path/to/definitions -type f -print | xargs -I{} sh -c "grep -qs with_apxs2 {} || sed -i '1i\with_apxs2 \"/usr/bin/apxs\"' {}"
まとめ
php-build が libphp?.so を上書きしてしまう問題への対応方法を紹介しました。
default_configure_options に書いたら libphp?.so の install path が変わったら楽そうだなと思いましたが、default_configure_options は全バージョン共通で使える configure option しか書かないと考えると、そういう方針なのだろうということで納得できました
(--with-apxs2
オプションは、現状 php-build が扱っている全バージョンで使えるようですが......)。
patch を当てる方法だとアップデートへの追従が大変なので、公式がサポートしてくれて良かったです。
jq で JSON を LTSV に変換する
結論
[ {"foo": "bar1", "hoge": "piyo1"}, {"foo": "bar2", "hoge": "piyo2"}, {"foo": "bar3", "hoge": "piyo3"} ]
という json(test.json とする) があるときに、
$ cat test.json | jq -r '.[] | to_entries | map("\(.key):\(.value)") | join("\t")'
と実行すると、
foo:bar1 hoge:piyo1 foo:bar2 hoge:piyo2 foo:bar3 hoge:piyo3
と出力されます。
解説
分解して説明します。
to_entries
で key
, value
という key を持った hash の array に変換します。
$ cat test.json | jq -r '.[] | to_entries' [ { "key": "foo", "value": "bar1" }, { "key": "hoge", "value": "piyo1" } ] [ { "key": "foo", "value": "bar2" }, { "key": "hoge", "value": "piyo2" } ] [ { "key": "foo", "value": "bar3" }, { "key": "hoge", "value": "piyo3" } ]
map は配列に対して処理を行え、
"(\.KEY)"
で文字列変数展開ができるので、
map("\(.key):\(.value)")
として Label:Value
の形式に変換します。
$ cat test.json | jq -r '.[] | to_entries | map("\(.key):\(.value)")' [ "foo:bar1", "hoge:piyo1" ] [ "foo:bar2", "hoge:piyo2" ] [ "foo:bar3", "hoge:piyo3" ]
最後に、join("\t")
で array を Tab 区切りの文字列に変換して完了です。
謝辞
http://stackoverflow.com/a/25378171 をちょっといじっただけです。
とても助かりました。aioobe さん、ありがとうございます!
fluentd の out forward の secondary を S3 にして信頼性を向上する
オートスケールするサーバ(web、アプリ)に立てている fluentd(以下、sender) から、
ログ集約用の fluentd(以下、aggregator) にデータを送るとき、
aggregator がデータを受け付けられないと sender で buffer すると思います。
この状態でスケールイン(ディスクごとサーバを削除)すると、
buffer していてもデータをロストしてしまいます。
そこで、sendor から aggregator に送れない場合は Amazon S3 に送ることができたのなら、
信頼性を向上できるのではないかと考え実験しました。
検証環境
fluentd 0.12.22
fluent-plugin-s3 0.6.6
ruby 2.3.0
注意点
sender から aggregator にデータを送れない状況を再現するために、
server には fluentd を起動していないホストを指定します。
存在しないホストを指定すると fluentd の起動に失敗するので、存在するホストを指定してください。
file buffer
buffer したデータを比較するため、まず file buffer の実験を行います。
以下の様な設定ファイルで fluentd を起動します。
以下の様に fluent-cat
でデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
buffer は msgpack なようなので decode するスクリプトを用意しました。
decode すると以下の様になります。
$ ruby unpack.rb /path/to/forward.debug.test.xxx.log [1459155557, {"foo"=>"bar"}]
s3 buffer
次は S3 に buffer できるかの実験です。
以下の様な設定ファイルで fluentd を起動します。
実験のため、retry_limit
と max_retry_wait
を非常に短くしています。
起動できたら file buffer の時と同じようにデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
S3 を見るとデータが保存されていました。
送れていることが確認できたのならば、file buffer のときと同じく復元できるか確認します。
$ aws s3 cp s3://path/to/buffer/forward_debug.test.gz . $ gunzip forward_debug.test.gz $ ruby unpack.rb /path/to/forward.debug.test [1459155737, {"foo"=>"bar"}]
復元できました。
タイムスタンプ以外は同じ結果になったので、
aggregator を復旧すれば buffer からデータを再送できると思います。
まとめ
out forward の secondary を S3 にすることができるか検証しました。
検証に使った設定ファイルのままでは使えないと思いますので調整する必要はあると思いますが、
buffer をロストしにくくできそうですね。
実際に使用する場合は、S3 の buffer からデータを送り直す手順を確認しておくと良いと思います。
primary と secondary の type が違うのは推奨していないようで、
type of secondary output should be same as primary output primary="Fluent::ForwardOutput" secondary="Fluent::S3Output"
のような warn が出力されます。
secondary を S3 にした場合は問題なさそうな挙動でしたが、
他の plugin ではどうなるかわかりませんのでご注意ください。