notebook

都内でWEB系エンジニアやってます。

fluentd + elasticsearch ではまったところ

fluentd + elasticsearch + kibana

fluentd+elasticsearch+kibanaを導入してみたのですが色々と詰まったところがあったのでこの機会に残しておきます

elasticsearchへの転送

dstatはすでにあるし、あとはcopyしてelasticsearchに流すだけだし余裕っしょ♪

とか思っていたら見事にはまりました。

送ったログをいざグラフ化しようとしても何も選択肢が無いw

レスポンスコードとか、レスポンスタイムとか数値として扱うべきメニューが出てこない

elasticsearch-headプラグインで型を確かめると全部stringになってる!!!!!

elasticsearch側でデフォルトテンプレートを用意してあげる方法もあるようですが、fluentd側で定義してあげればelasticsearchでは空気読んでくれるようなので今回はfluentd側で対応することにしました。

そもそもfluentdでは型を特に指定しないと全てstringとして扱っているようです

なのでfluentdで何か値を生成したりした場合はcastしてあげないと転送先でちゃんと動いてくれない現象に陥ります

これは運用開始前に気付いてよかった。。。。

サーバインフラ要請読本 ログ収集~可視化をよく読んだら載ってたのでちゃんと読もうねって話ですね。。

なので今回はfluent-plugin-typecastを使ってdstatでとった値を全て数値型に変換しました。

<source>
  type dstat
  tag dstat
  option -clmdrns --udp --tcp
  delay 30
</source>
<match dstat>
  type map
  tag "monitor.dstat"
  time time
  record record["dstat"]
</match>
<match monitor.dstat>
  type flatten_hash
  add_tag_prefix string.app.
  separator .
</match>
+ <match string.app.monitor.dstat>
+   type typecast
+   tag app.monitor.dstat
+   item_types total cpu usage.usr:float,total cpu usage.sys:float,total cpu usage.idl:float,total cpu usage.wai:float,total cpu usage.hiq:float,total cpu usage.siq:float,load avg.1m:float,load avg.5m:float,load avg.15m:float,memory usage.used:float,memory usage.buff:float,memory usage.cach:float,memory usage.free:float,dsk/total.read:float,dsk/total.writ:float,io/total.read:float,io/total.writ:float,net/total.recv:float,net/total.send:float,swap.used:float,swap.free:float,udp.lis:float,udp.act:float,tcp sockets.lis:float,tcp sockets.act:float,tcp sockets.syn:float,tcp sockets.tim:float,tcp sockets.clo:float
+ </match>

せっかくdstatで一項目づつ書かなくてよくしたのにだいなしでした。。。

アクセスログとかその他ログも数値で渡したいものに関してはtypeを指定できるなら指定してあげて、できないなら後でcastしてあげる必要があります

source>
  type tail
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/access_log.pos
  tag app.balancer.access_log
  format /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<request_time>[^ ]*)" "(?<forwarded_for>[^\"]*)" "(?<cookie>[^\"]*)")?$/
  time_format %d/%b/%Y:%H:%M:%S %z
+  types code:integer,size:integer,request_time:float
</source>

ちなみにfluent-plugin-cloudwatchとかは数値型で送ってくれていたので何もする必要はなかったです。

elasticsearchへの転送2

やっと平常運転に入れたかと思ったら下記ログに出くわしました。

  • td-agent.log
2015-05-19 11:35:26 +0000 [warn]: Could not push logs to Elasticsearch, resetting connection and trying again. Recv failure: Connection reset by peer
  • td-agent.log
2015-05-19 11:26:29 +0000 [warn]: Size of the emitted data exceeds buffer_chunk_limit.
2015-05-19 11:26:29 +0000 [warn]: This may occur problems in the output plugins ``at this server.``
2015-05-19 11:26:29 +0000 [warn]: To avoid problems, set a smaller number to the buffer_chunk_limit
2015-05-19 11:26:29 +0000 [warn]: in the forward output ``at the log forwarding server.``
  • elasticsearch.log
[2015-05-19 11:36:00,332][WARN ][http.netty               ] [app10.0.21.60] Caught exception while handling client http traffic, closing connection [id: 0x0a031f69, /10.0.21.20:57853 => /10.0.21.60:9200]
org.elasticsearch.common.netty.handler.codec.frame.TooLongFrameException: HTTP content length exceeded 104857600 bytes.

fluentdの設定で、buffer_chunk_limitを多めに変更したのでelasticsearch側で受け付けきれなくなったみたいでした

なのでelasticsearch側で受け付けられるサイズをfluentdのバッファーサイズと同じにしました。

  • elasticsearch.yml
http.max_content_length: 1g

また、queueサイズも変更

  • elasticsearch.yml
# キューが満杯の状態でリクエストが来た際には、そのリクエストは破棄
# 制限をしたくない場合には -1 を設定
threadpool.index.queue_size: -1 # デフォルト 200
threadpool.bulk.queue_size: -1 # デフォルト 50
# threadpool.search.queue_size: -1
# threadpool.get.queue_size: -1

fluent-plugin-forest

same buffer_pathで怒られる件

まぁこれはあたりまえっちゃ当たり前なんですが、理解してないとずっと意味わからん!ってなる

複数タグでbufferに出力しているので違うタグなのに同じバッファへ出力しようとすると怒られるっていうやつですね

たとえばこんな設定にしていると怒られます

type forest
subtype file_alternative
<template>
  buffer_chunk_limit 1g
  path /data/var/log/monitor/${tag_parts[1]}.${tag_parts[3]}
  buffer_path /var/log/td-agent/${tag_parts[1]}.${tag_parts[3]}
  flush_interval 1s
  time_slice_format %Y%m%d
</template>

buffer_pathに指定したファイルが違うタグでも複数存在する可能性があるためエラーになります

仮に複数ホストから受け取ったログを集めてファイルとして置いておきたいという要件だった時に

上記設定よりpathで生成されるファイル名は「log.error_log」になります

ここで

二つのサーバからのエラーログを集約する設定をしていたら

集約サーバでの二つのタグのbuffer_pathは「log.error_log」と同一になってしまうのでエラーが起こる

failed to configure sub output file: Other '' plugin already use same buffer_path: type = , buffer_path = /var/log/httpd/monitor.dstat.*

下記のようにパスが被らないように設定してあげる必要があるみたいです

-  buffer_path /var/log/td-agent/${tag_parts[1]}.${tag_parts[3]}
+  buffer_path /var/log/td-agent/${tag_parts[1]}.${tag_parts[2]}.${tag_parts[3]}

パターン分け

この場合は転送、それ以外はこれだけっていうのをうまくひとまとまりでやりたかったんだけど断念

  • app.monitor.hostname.dstat
  • app.backend.hostname.error_log
  • app.balancer.hostname.access_log

下記の設定をひとまとめで<match app.**>だけで処理したい感じですね

  • 現実
<match app.monitor.**>
  type copy
  <store>
    type forest
    subtype s3
  </store>
  <store>
    type forest
    subtype file_alternative
  </store>
  <store>
    type forest
    subtype elasticsearch
  </store>
</match>
<match app.**>
  type copy
  <store>
    type forest
    subtype growthforecast
  </store>
  <store>
    type forest
    subtype s3
  </store>
  <store>
    type forest
    subtype file_alternative
  </store>
  <store>
    type forest
    subtype elasticsearch
  </store>
</match>
  • 最初試した設定
<match app.**>
  forest
  subtype copy
  <template>
    <store>
      type growthforecast
    </store>
    <store>
      type s3
    </store>
    <store>
      type file_alternative
    </store>
    <store>
      type elasticsearch
    </store>
  <template>
</match>

そもそもconfigtestが通せなかったので断念

  • 次に試した設定
<match app.**>
  type copy
  <store>
    type forest
    subtype growthforecast
  </store>
  <store>
    type forest
    subtype s3
  </store>
  <store>
    type forest
    subtype file_alternative
  </store>
  <store>
    type forest
    subtype elasticsearch
  </store>
</match>

growthforecastの部分のtemplateでcase指定してログファイルはgrowthforecastに送信しないというような設定

growthforecastのpathをcaseで指定しないようにしたら怒られる、指定したら送信される、ということで断念

なんかいい方法あったら教えていただきたいです

fluent-plugin-s3

下記全く同じ現象でした

fluent-plugin-s3で、time_slice_format %Y%m%dにしてても、一日に複数ファイルがでてくる件

buffer_chunk_limitに気をつけようねっていうことですね

これは通常のファイルへの出力でもはまるので覚えておいて損はないはず

最初pathにインデックスがあるからダメなんだと思って%{index}を抜いた設定にしたら一度書き込まれてそれ以降何も書き込まれないっていう状況になった

s3の場合は追記ができないのでファイル出力以降はエラーが出てました。

ファイルだけあるの確認してOK!でも実はほとんどバックアップできてなかったなんて落ちになりそうな感じですね。。。