fluent-plugin-redis-slowlogを作った
fluent-plugin-redis-slowlogを作った。
以前からプラグインつくってみたいなーと思っていたけどアイデアとか無かった。
すると、会社でRedisのSlowlog集めたいな−って話が出て、Fluentdのプラグインとか存在してるだろうからそれ使えば楽じゃね?と思ったらプラグイン見つからなかった…。
なので作ってみた。
始めてFluentdのプラグインをつくるので以下を参考にさせていただいた
kenjiskywalkerさんにおんぶにだっこ状態ですが…
超初級!Fluentdのプラグインを書きたくなった時の下地づくり - さよならインターネット
kenjiskywalker/fluent-plugin-rds-slowlog · GitHub
fluent-plugin-redis-slowlogの使い方
fluent.confのinputプラグインとして利用します。
<source> type redis_slowlog host localhost # Redis-serverのホスト名又はIP port 6379 # Redis-serverのPort番号 (デフォルトは6379) interval 10 # Slowlogを取得に行くタイミング(デフォルト10秒に1回) logsize 128 # 一度に取得するSlowlogの数 (デフォルト128)※Redisの初期設定だとSlowlogが128個までしか保存されない。 # また、数が多くなるほど取得にかかる時間も増えるのでRedisの負荷等見て調整してください tag redis.slowlog # タグ名 </source> <match ** > type stdout </match>
出力はコチラ
※どんなcommandでもSlowlogに登録されるようにRedis側にconfig set slowlog-log-slower-than 1
を実行しています。なので、fluent-plugin-redis-slowlogから実行しているSlowlog取得のコマンドも出力されてます。
2014-06-08 05:33:31 +0900 redis.slowlog: {"id":173,"timestamp":1402173257,"exec_time":15,"command":["keys","*"]} 2014-06-08 05:33:31 +0900 redis.slowlog: {"id":172,"timestamp":1402173253,"exec_time":137,"command":["slowlog","get","128"]} 2014-06-08 05:33:41 +0900 redis.slowlog: {"id":174,"timestamp":1402173263,"exec_time":140,"command":["slowlog","get","128"]} 2014-06-08 05:33:51 +0900 redis.slowlog: {"id":176,"timestamp":1402173275,"exec_time":9,"command":["set","hoge","aga"]} 2014-06-08 05:33:51 +0900 redis.slowlog: {"id":175,"timestamp":1402173273,"exec_time":137,"command":["slowlog","get","128"]} 2014-06-08 05:34:01 +0900 redis.slowlog: {"id":177,"timestamp":1402173283,"exec_time":166,"command":["slowlog","get","128"]}
Format"id":slowlog-id,"timestamp": Redisでcommandが発行された時間(unixtime),"exec_time":コマンドの処理にかかった時間(マイクロ秒),"command":["実際に発行されたコマンド","と","引数"]}
尚このプラグイン毎回logsize
分のSlowlogを取得しに行き、取得したSlowlogは削除していません。
なので毎回取得する度に同じSlowlogを取得している場合が普通に考えられます。
しかしそのままでは無意味なので、RedisのSlowlogに付与されているidを利用しています。
取得の度に前回に取得したslowlogのidの最大値を取り出しておき、その最大値より大きなidを持つものだけemitしています。
また、今度追加する予定ですが、このプラグイン再起動するとSlowlogのid情報が無くなってしまうので以前取り出したslowlogを取得してしまいます。 id情報をファイルに出力しておいて再起動時にはそのファイルのidを最大値として格納するよにしないと…
Docker+Packer で MySQLを動かしてみた
最近Dockerが話題なので会社でも利用し始めており、そしてPackerも勉強しようと思い調べてたらDockerで利用できるようだったので組み合わせてみた。
ついでに、MySQL 5.6をインストールしてみた
まずUbuntu Server 13.10にDockerとPackerを導入
# Docker Install sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\ > /etc/apt/sources.list.d/docker.list" sudo apt-get update sudo apt-get install lxc-docker # Packer Install wget https://dl.bintray.com/mitchellh/packer/0.5.2_linux_amd64.zip sudo unzip 0.5.2_linux_amd64.zip -d /usr/local/bin/
packer で利用するjson(mysql.json)はこちら
"builders"
には"type": "docker"
を指定して、Dockerイメージの元となるイメージと、
出力されるDockerイメージのファイル名を指定します。
ここをAWSの設定にしてやればMySQL5.6をAWSで起動するAMIを作れちゃうかな?修正必要ですけど。
"provisioners"
ではSSHのインストールをMySQLインストール用スクリプトを呼び出しています。
{ "builders": [{ "type": "docker", "image": "ubuntu:12.04", "export_path": "mysql.tar" }], "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "apt-get update", "apt-get -y update", "apt-get install -y openssh-server", "mkdir /var/run/sshd /root/.ssh/" ] }, { "type": "file", "source": "ssh/id_rsa.pub", "destination": "/root/.ssh/authorized_keys" }, { "type": "shell", "inline": [ "chmod 600 /root/.ssh/authorized_keys" ] }, { "type": "shell", "script": "mysql-install.sh" } ] }
上記jsonの"provisioners"
の2つ目にSSH-Keyを指定していますが、
Jsonファイルが置いてある場所にDockerで利用するSSHkeyを配置しておりそれを利用しています。
MySQLインストール用のスクリプト(mysql-install.sh)
# Dockerで利用する ubuntu:12.04だと以下をしとかないとMySQLインストールに必要なパッケージがインストールと、 # MySQLのスクリプトが失敗する。 sudo locale-gen en_US.UTF-8 sudo apt-get install -y perl # MySQLのインストール wget http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.16-debian6.0-x86_64.deb sudo dpkg -i mysql-5.6.16-debian6.0-x86_64.deb sudo apt-get install -y libaio1 sudo cp -p /opt/mysql/server-5.6/support-files/mysql.server /etc/init.d/mysql # MySQLユーザの作成 sudo groupadd mysql sudo useradd -r -g mysql mysql # MySQLユーザに合わせて権限等の変更 sudo chown -R root:root /opt/mysql sudo chown -R mysql:mysql /opt/mysql/server-5.6 sudo install -o mysql -g mysql -d /data/mysql sudo -u mysql /opt/mysql/server-5.6/scripts/mysql_install_db --user=mysql --datadir=/data/mysql # 適当な設定ファイル用意 echo ' [mysqld] basedir = /opt/mysql/server-5.6 datadir = /data/mysql ' |sudo tee /etc/my.cnf # サービスに登録 # 登録してもDocker起動時には動かないけど… sudo update-rc.d mysql defaults sudo /etc/init.d/mysql start # 外部から接続するためのユーザ追加 /opt/mysql/server-5.6/bin/mysql -e "grant all privileges on *.* to root@'172.17.42.1' IDENTIFIED BY 'root';" # MySQLとSSHDを起動するスクリプトを用意 echo ' /etc/init.d/mysql start /usr/sbin/sshd -D ' |sudo tee /usr/local/bin/docker-start.sh
Packer の実行 ※Dockerを利用するのでsudo付きで…
sudo packer build mysql.json
Packerでのイメージ作成後Dockerにイメージを取り込みます
# " - ubuntu/mysql " で Dockerイメージ名の設定 cat mysqlimage.tar |sudo docker import - ubuntu/mysql # 取り込まれたか確認 sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu/mysql latest 3e60e3386690 3 days ago 1.729 GB ubuntu 12.04 9cd978db300e 3 weeks ago 204.4 MB
「REPOSITORY」に「ubuntu/mysql」が表示されているので取り込みは成功です。 続いて起動
# bash /usr/local/bin/docker-start.sh はDockerで実行するコマンドを指定 # 内容はMySQLの起動とSSHDの起動 # sudo docker run -p 22 -p 3386 ubuntu/mysql bash /usr/local/bin/docker-start.sh # 起動確認 sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 78f1af31b25c ubuntu/mysql:latest bash /usr/local/bin/ 3 days ago Up 3 days 0.0.0.0:49161->22/tcp, 0.0.0.0:49162->3306/tcp stoic_torvalds # Dockerのport番号取得 # docker inspect を利用し起動したDockerの情報を取得し jq で整形してPort番号を取り出す mysqlport=`sudo docker inspect \`sudo docker ps |grep ubuntu/mysql | cut -f 1 -d ' '\` | jq '.[].NetworkSettings.Ports["3306/tcp"][].HostPort | tonumber'` # MySQLへの接続 mysql -h 127.0.0.1 -P $mysqlport -u root -p
以上でPakcerを利用したMySQLのDockerイメージの作成手順の終了です。 一応後で直接設定変更したいだとか、ログを確認したいだとかのためにSSH残してあります。 ログだけが心配ならFluentd等を一緒に導入して外出しにしてもいいのかなと思います。
あ、最後にファイル構成
tree . |-- mysql-install.sh |-- mysql.json |-- packer_cache |-- ssh | |-- id_rsa | |-- id_rsa.pub 2 directories, 5 files
Fluentd Config DSL と fluent-plugin-forest
久しぶりにいつか書こう、書こうと思って放置してたやつ。 DSLの書き方もすぐ忘れるので、メモ代わりにしつつ…
会社のログ管理としてFluentd: Open Source Log Managementを利用しています。
Fluentdはプラグインを追加したり、作成したりして自分の好きなようにログや、アプリからのデータ等を加工できます。
しかし、いろいろできてしまう為設定ファイルがとても長くなってしまうことも…
しかし最近ではFluentdもDSLに対応し、Rubyのコードで設定ファイルが書けるようになりました。
Fluentd界隈ではバイブルのtagomorisさんのブログより
以下に適当なサンプルを用意しました、本気をだすとどんどん長くなります。 *1
# fluentd.conf <source> type forward </source> <match *.nginx> type file path /var/log/fluentd/nginx-* time_slice_format %Y%m%d-%H time_format %Y%m%dT%H%M%S%z compress gzip </match> <match *.app> type file path /var/log/fluentd/app-* time_slice_format %Y%m%d-%H time_format %Y%m%dT%H%M%S%z compress gzip </match> <match *.syslog> type file path /var/log/fluentd/syslog-* time_slice_format %Y%m%d-%H time_format %Y%m%dT%H%M%S%z compress gzip </match>
これをFluentd Config DSLで書くとこんな感じ
# fluentd.rb source { type :forward } ['nginx','app','syslog'].each do|tag| match("*.#{tag}") { type :file path "/var/log/fluentd/#{tag}-*" time_slice_format '%Y%m%d-%H' time_format '%Y%m%dT%H%M%S%z' compress 'gzip' } end
そこそこ減ったんじゃないでしょうか?
次のように実行してやると「$ fluentd -c fluentd.rb --log /tmp/fluentd.log
」実行でき、
/tmp/fluentd.log の中に fluentd.rbが展開されfluentd.confと同じ内容が出力されてるのが確認できます。
Config DSLで書いていて、思った通りの設定になってるか確認したいときは実行してログなど見ると良いかも、
テストだけなら次を実行すると「$ fluentd -c fluentd.rb --dry-run
」Fluentdは起動しないで、展開された設定が標準出力されます。
と、DSLの話をしてきましたがタイトルにはもうひとつ fluent-plugin-forest とあります。 このFluentdプラグインまたしてもtagomorisさんのブログを引用します。
私もいろんな場所で利用させて頂いています。
しかしDSLでこのプラグインを利用すると…
実行した設定ファイルはこれ
# fluentd.rb source { type :forward } match("**") { type :forest subtype :file template { time_slice_format '%Y%m%d-%H' time_format '%Y%m%dT%H%M%S%z' compress 'gzip' } ['nginx','app','syslog'].each do|tag| cases("*.#{tag}.*") { path "/var/log/fluentd/${tag_parts[1]}/${tag}-*" } end }
これを実行してみると
$ fluentd -c fluentd.rb --dry-run 2013-12-10 02:45:06 +0900 [info]: reading config file path="fluentd.rb" /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/config_dsl.rb:28:in `instance_eval': ./fluentd.rb:16: syntax error, unexpected '{', expecting keyword_when (SyntaxError) ./fluentd.rb:19: syntax error, unexpected '}', expecting keyword_end from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/config_dsl.rb:28:in `eval' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/config_dsl.rb:14:in `parse' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/engine.rb:72:in `parse_config' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/supervisor.rb:285:in `run_configure' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/supervisor.rb:108:in `dry_run' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/supervisor.rb:83:in `start' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/lib/fluent/command/fluentd.rb:146:in `<top (required)>' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:53:in `require' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:53:in `require' from /home/momin/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluentd-0.10.41/bin/fluentd:6:in `<top (required)>' from /home/momin/.rbenv/versions/2.0.0-p353/bin/fluentd:23:in `load' from /home/momin/.rbenv/versions/2.0.0-p353/bin/fluentd:23:in `<main>'
なんでかなーと思って、ちょこちょこ設定ファイル変更したりしてみても動かない…
よくよく考えてみると、fluent-plugin-forestの中には case が…はい、 つまり Fluentdの設定ではなくてRubyのコードして読み取られてたわけなんですよ… なのでちょこっとプラグインと設定ファイルを修正します
$ cd ~/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/fluent-plugin-forest-0.2.2/lib/fluent/plugin $ diff out_forest.rb out_forest.rb.bk 44c44 < when 'cases' --- > when 'case' $ cd - $ diff fluentd.rb fluentd.rb.bk 16c16 < cases("*.#{tag}.*") { --- > case("*.#{tag}.*") {
特に何も考えないでcaseの後ろにsをつけてみました…
そして再度実行…
$ fluentd -c fluentd.rb --dry-run 2013-12-10 02:56:51 +0900 [info]: reading config file path="fluentd.rb" 2013-12-10 02:56:51 +0900 [info]: gem 'fluent-plugin-forest' version '0.2.2' 2013-12-10 02:56:51 +0900 [info]: gem 'fluentd' version '0.10.41' 2013-12-10 02:56:51 +0900 [info]: using configuration file: <ROOT> <source> type forward </source> <match **> type forest subtype file <template> time_slice_format %Y%m%d-%H time_format %Y%m%dT%H%M%S%z compress gzip </template> <cases *.nginx.*> path /var/log/fluentd/${tag_parts[1]}/${tag}-* </cases> <cases *.app.*> path /var/log/fluentd/${tag_parts[1]}/${tag}-* </cases> <cases *.syslog.*> path /var/log/fluentd/${tag_parts[1]}/${tag}-* </cases> </match> </ROOT> 2013-12-10 02:56:51 +0900 [info]: adding source type="forward" 2013-12-10 02:56:51 +0900 [info]: adding match pattern="**" type="forest"
するとちゃんと動作してくれました。
実際会社ではDSL使ってないのでこんな修正はいらないのですが、 もしDSL使ってfluent-plugin-forest利用される場合は考慮いただけたらなと思います。
*1:ファイルを分けてincludeする手もありますけど…
丸の内MongoDB勉強会 #10に参加してきました
先日はじめてMongoDBの勉強会に参加してきました。
勉強会はこちら:丸の内MongoDB勉強会 #10
主な内容はMongoDBの初心者向けのハンズオンとZabbixとMMSを利用したMongoDBの監視の話とプラス懇親会でした。
私は勤め先のサービスでMongoDBの構築や運用をしているのですが、少しさわれるだけで、オペレーション等を全く勉強したことがないのです…。
すると今回初心者向けと私の心に響くハンズオンがあるということで、参加しようと思いました。
また、それだけではなくちょうどMMSを利用していたところなので、いろいろとTispを聞けたらいいなと思ってもいました。
ハンズオンの内容等は上に張り出しましたAtndから巡っていただくと資料はあるのでそちらで確認して下さい。
つづいてMongoDBの監視について
続きを読む