fluent+dstat+kibana4でのサーバリソース可視化
コメントいただいた id:a3no さんの記事のほうが良いので、そちらを参照しましょう。a3no.hatenablog.com
普段はmuninやzabbixのグラフでまあいいかというサーバリソースグラフが、秒単位で見たいというケースがあって色々試行錯誤してできたもの。
rrdtoolで1秒を対応するグラフを作るという手もあるのだけど、なかなか秒単位にいじれるフロントエンドツールが無くて Elasticsearch 触ったこと無かったしで、Web記事を参考にして作ってみることにしました。
参考URL
dstatをkibanaで可視化+3.0.0milestone5新機能 - ほわいとぼーど
curator で Kibana 用の elasticsearch のインデックスを定期的に削除する - Qiita
Use relative paths instead of absolute · Issue #1630 · elastic/kibana · GitHub
Elasticsearch Kibana beta behind Apache Proxy - mmbash.de
作った時期が比較的最近で、fluentdやkibanaのバージョンが違っててなんかWeb上の設定から色々変わってて、これでいいのか?という設定になったけどまあ動いてるのでとりあえずメモということで。
バージョン
OS:CentOS 6.6
elasticsearch-1.6.0
td-agent-2.2.0-0
kibana-4.0.3
注意点とか考慮点(殆ど fluentd )
- fluent-plugin-map の設定記述方法が fluentd の v1config と合わないパターンがあるので注意
- elasticsearch 側でデータ型自動判別が上手くいくように fluent-plugin-typecast でデータ型変更
- elasticsearch に入れる時点で、@timestamp を予め付与してデータのタイムスタンプはなるべく正確に
- elasticsearch に入れる時点で、ホスト名を予め付与して elasticsearch 側でホスト名フィルタを使えるように
- kibana の設定で reverse proxy 経由アクセスを予定して elasticsearch_url の書き換えを行う
- dstat取得ノードから直接 ES に入れることも考えたけど、テキストログの集約保存もしたかったため結局一旦 ES ホスト上の fluentd に集めてから ES に入れる方向に
インストール手順
※なるべく外に取りに行かずにできるように予めパッケージ類落としてきて入れようとしました…が、curator 忘れてて結局外部見にいってしまっていますorz 普通に使う分にはyumとか適当に使えばいいと思います!
elasticsearch
alternatives でjavaのシンボリックリンク切り替えていますが、java環境の整え方はお好みでしょう。
yum install java-1.8.0-openjdk.x86_64 alternatives --display java rpm -ivh elasticsearch-1.6.0.noarch.rpm chkconfig --add elasticsearch
td-agent
td-agent の設定は後述します。
rpm -ivh td-agent-2.2.0-0.x86_64.rpm chkconfig td-agent on /opt/td-agent/embedded/bin/fluent-gem install *.gem cd /var/log/td-agent/ cp -pr buffer/ arch cp -pr buffer/ pos vi /etc/td-agent/td-agent.conf ※入れたプラグインリスト:irc通知とか色々見越した余計なプラグインが入ってます fluent-plugin-slack-0.6.1.gem fluent-plugin-typecast-0.2.0.gem いる fluent-plugin-dstat-0.2.5.gem いる fluent-plugin-forest-0.3.0.gem いる fluent-plugin-parser-0.5.0.gem fluent-plugin-config-expander-0.1.5.gem いる fluent-plugin-numeric-counter-0.2.2.gem fluent-plugin-map-0.0.4.gem いる fluent-plugin-ikachan-0.2.6.gem fluent-plugin-snmptrap-0.0.1.gem fluent-plugin-record-reformer-0.6.3.gem いる fluent-plugin-notifier-0.2.3.gem fluent-plugin-elasticsearch-0.9.0.gem いる fluent-plugin-irc-0.0.7.gem fluent-mixin-rewrite-tag-name-0.1.0.gem
kibana4
先の注意点に書いていますが kibana.yml で elasticsearch_url をデフォルトの localhost から変更します。
詳しい理屈と原因は追っていませんが、そうしないと reverse proxy apache からアクセスした際に上手くいきませんでした。
cd tar xzf kibana-4.0.3-linux-x64.tar.gz chown -R root:root kibana-4.0.3-linux-x64/ cd kibana-4.0.3-linux-x64/config vi kibana.yml == elasticsearch_url: "http://[elasticsearch server ip(not localhost)]:9200" ===
curator
後付で入れたので外に取りに行ってしまった残念?なもの。
wget --no-check-certificate https://raw.github.com/pypa/pip/master/contrib/get-pip.py python get-pip.py pip install elasticsearch-curator curator --version curator show dstat*
ホストリソース取得ノードの td-agent 設定
<source> type config_expander <config> type dstat tag host.dstat.__HOSTNAME__ option -tclmsr -dD sda --disk-util -nN bond0,bond1 delay 5 </config> </source> <match host.**> type forward send_timeout 60s recover_wait 10s heartbeat_type tcp heartbeat_interval 1s phi_threshold 16 hard_timeout 60s <server> name es-host host [fluent server] port 24224 weight 60 </server> </match>
ホストリソース取得ノードの td-agent 設定
<source> type forward port 24224 </source> <match host.dstat.*> type copy <store> type forest subtype file <template> time_slice_format %Y%m%d append true buffer_type file buffer_chunk_limit 100m flush_interval 30s </template> <case **> path /var/log/td-agent/arch/__TAG__ symlink_path /var/log/td-agent/arch/__TAG__.log buffer_path /var/log/td-agent/buffer/__TAG__/ </case> </store> <store> type map map '["map." + tag + ".cpu_idl", time , "cpu_idl" => record["dstat"]["total cpu usage"]["idl"]]' </store> <store> type map map '["map." + tag + ".loadavg_1m", time , "loadavg_1m" => record["dstat"]["load avg"]["1m"]]' </store> <store> type map map '["map." + tag + ".mem_free", time , "mem_free" => record["dstat"]["memory usage"]["free"]]' </store> <store> type map map '["map." + tag + ".swap_used", time , "swap_used" => record["dstat"]["swap"]["used"]]' </store> <store> type map map '["map." + tag + ".io_sda_read", time , "io_sda_read" => record["dstat"]["io/sda"]["read"]]' </store> <store> type map map '["map." + tag + ".io_sda_write", time , "io_sda_write" => record["dstat"]["io/sda"]["writ"]]' </store> <store> type map map '["map." + tag + ".dsk_sda_read", time , "dsk_sda_read" => record["dstat"]["dsk/sda"]["read"]]' </store> <store> type map map '["map." + tag + ".dsk_sda_write", time , "dsk_sda_write" => record["dstat"]["dsk/sda"]["writ"]]' </store> <store> type map map '["map." + tag + ".sda_util", time , "sda_util" => record["dstat"]["sda"]["util"]]' </store> <store> type map map '["map." + tag + ".net_bond0_recv", time , "net_bond0_recv" => record["dstat"]["net/bond0"]["recv"]]' </store> <store> type map map '["map." + tag + ".net_bond0_send", time , "net_bond0_send" => record["dstat"]["net/bond0"]["send"]]' </store> <store> type map map '["map." + tag + ".net_bond1_recv", time , "net_bond1_recv" => record["dstat"]["net/bond1"]["recv"]]' </store> <store> type map map '["map." + tag + ".net_bond1_send", time , "net_bond1_send" => record["dstat"]["net/bond1"]["send"]]' </store> </match> <match map.host.dstat.**> type record_reformer enable_ruby true tag timeadd.map.host.dstat <record> hostname ${tag_parts[3]} @timestamp ${time.strftime('%Y-%m-%dT%H:%M:%S%z')} </record> </match> <match timeadd.map.host.dstat.**> type typecast item_types cpu_idl:float,loadavg_1m:integer,mem_free:integer,swap_used:integer,io_sda_read:integer,io_sda_write:integer,dsk_sda_read:integer,dsk_sda_write:integer,sda_util:float,net_bond0_recv:integer,net_bond0_send:integer,net_bond1_recv:integer,net_bond1_send:integer tag typecast.timeadd.map.host.dstat </match> <match typecast.timeadd.map.host.dstat.**> type copy # <store> # type stdout # </store> <store> type elasticsearch type_name dstat host localhost port 9200 logstash_format true logstash_prefix dstat flush_interval 3s </store> </match>
ちなみにelasticsearchに入るデータ構造はこんな感じ
2015-06-20 11:21:24 +0900 typecast.timeadd.map.host.dstat: {"sda_util":2.18,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:24+0900"} 2015-06-20 11:21:29 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.72,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:29+0900"} 2015-06-20 11:21:34 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.3,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:34+0900"} 2015-06-20 11:21:39 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.08,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:39+0900"} 2015-06-20 11:21:44 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.06,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:44+0900"} 2015-06-20 11:21:49 +0900 typecast.timeadd.map.host.dstat: {"sda_util":1.84,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:49+0900"} 2015-06-20 11:21:54 +0900 typecast.timeadd.map.host.dstat: {"sda_util":2.26,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:54+0900"} 2015-06-20 11:21:59 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.06,"hostname":"dstathost","@timestamp":"2015-06-20T11:21:59+0900"} 2015-06-20 11:22:04 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.32,"hostname":"dstathost","@timestamp":"2015-06-20T11:22:04+0900"} 2015-06-20 11:22:09 +0900 typecast.timeadd.map.host.dstat: {"sda_util":1.42,"hostname":"dstathost","@timestamp":"2015-06-20T11:22:09+0900"} 2015-06-20 11:22:14 +0900 typecast.timeadd.map.host.dstat: {"sda_util":1.32,"hostname":"dstathost","@timestamp":"2015-06-20T11:22:14+0900"} 2015-06-20 11:22:19 +0900 typecast.timeadd.map.host.dstat: {"sda_util":0.12,"hostname":"dstathost","@timestamp":"2015-06-20T11:22:19+0900"} 2015-06-20 11:22:24 +0900 typecast.timeadd.map.host.dstat: {"sda_util":1.72,"hostname":"dstathost","@timestamp":"2015-06-20T11:22:24+0900"}
elasticsearchのインデックス定義
name type analyzed indexed ------------------------------------ _index string false false loadavg_1m number false true hostname string true true cpu_idl number false true swap_used number false true io_sda_write number false true _type string false true io_sda_read number false true dsk_sda_read number false true dsk_sda_write number false true @timestamp date false true mem_free number false true _source string false false _id string false false sda_util number false true net_bond0_recv number false true net_bond1_send number false true net_bond0_send number false true net_bond1_recv number false true
kibana4設定
画像かき集めて無いので無し
kibanaアクセスのためのReverseProxy?定義
nginx
location ~* /kb4/.* { rewrite ^/kb4/(.*) /$1 break; proxy_pass http://[kibana server]:5601; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_send_timeout 600s; proxy_read_timeout 600s; }
apache
ProxyRequests On ProxyPreserveHost On ProxyPass / http://[kibana server]:5601/ ProxyPassReverse / http://[kibana server]:5601/ RewriteEngine on RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule .* http://[kibana server]:5601%{REQUEST_URI} [P,QSA]
作ってみて
dstat + fluentd + Graphite + Grafana でサーバモニタリングする - blog.nomadscafe.jp の記事にありますが、ESのCPU使用率がきついです。
あと、dstat 5秒間隔取得データで、ES のヒープ 2G で 20日データ保存が安定稼動ラインで、それを超えるとメモリ不足や search の queue size エラーが出はじめます。ES のチューニングやトラブル対応のネタ的にはいいのですが、予想以上にデータ溜められないかもな…という印象。とりあえず数日の可視化はできているので、目標的にはOK。ES の調整は30日までは頑張って、後は fluentd で集めたテキストログ見ればいいやという割り切りでしばらく使うことに。