td-agent のプロセスが死んでから復旧するまでの間に in_tail で監視しているファイルにログが追記されてローテートされると追記されたログが拾えない

タイトルが長くてすみません。

事象としては掲題の通りです。

以下に確認したことをメモします。

環境

  • アプリが出力するログをtailプラグインを使ってアグリゲータに送信
  • アグリゲータはs3にログをputする
  • 送信側のtd-agent バージョンは 1.1.3
  • 送信ログは2GBごとにローテートされる
  • 以下のようにだいたい10分に1回ローテートされます。
[root@送信 ~]# ls -ltrh /var/log/test.log*
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 10:16 /var/log/test.log.20
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 10:25 /var/log/test.log.19
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 10:34 /var/log/test.log.18
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 10:43 /var/log/test.log.17
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 10:52 /var/log/test.log.16
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:00 /var/log/test.log.15
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:09 /var/log/test.log.14
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:17 /var/log/test.log.13
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:26 /var/log/test.log.12
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:34 /var/log/test.log.11
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:42 /var/log/test.log.10
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:50 /var/log/test.log.9
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 11:58 /var/log/test.log.8
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:06 /var/log/test.log.7
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:14 /var/log/test.log.6
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:22 /var/log/test.log.5
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:29 /var/log/test.log.4
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:37 /var/log/test.log.3
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:45 /var/log/test.log.2
-rw-rw-r-- 1 ec2-user ec2-user 2.1G Apr 10 12:52 /var/log/test.log.1
-rw-rw-r-- 1 ec2-user ec2-user 115M Apr 10 12:53 /var/log/test.log

設定

具体的な設定は以下のようにしました。

今回は受信側の設定も載せていますがあんまり関係ないですね。

送信側

  • test.logをtailします
<match tail.test>
  @type forward
  transport tcp

  <buffer tag,time>
    @type file
    path /var/log/td-agent/buffer/
    chunk_limit_size 64m
    queue_limit_length  2560
    timekey 3600 # 1 hour partitioon
    timekey_use_utc true # use utc
    flush_mode interval
    flush_interval 5s
    flush_at_shutdown
    retry_timeout 5m  #default = 72h
    #retry_max_times 5  #default = none
  </buffer>

  <server>
    host xxxxxxxxxxxxx
    port 24224
  </server>
</match>

<source>
  @type tail
  format none
  path /var/log/test.log
  pos_file /var/log/td-agent/test.pos
  tag tail.test
</source>

受信側

  • 今回は確認のために受信した内容をそのままファイルに吐き出します。
<match tail.test>
  @type file
  format single_value
  path /var/log/td-agent/tmp.log
  append true

  <buffer>
    @type file
    path /var/log/td-agent/buffer/
    flush_mode interval
    flush_interval 5s
  </buffer>
</match>

## built-in TCP input
## @see http://docs.fluentd.org/articles/in_forward
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

確認方法と事象

  • 送信側のlogに適当に書き込みます
[root@送信 ~]# for i in `seq -w 01 05` ; do echo "`date`      $i" >> test.log ; done
  • 受信側で確認します
[root@受信 ]# tailf tmp.log
Tue Apr 10 11:54:58 UTC 2018      01
Tue Apr 10 11:54:58 UTC 2018      02
Tue Apr 10 11:54:58 UTC 2018      03
Tue Apr 10 11:54:58 UTC 2018      04
Tue Apr 10 11:54:58 UTC 2018      05
  • 送信側のtd-agentを止めて、先ほどと同じ要領でログを追記してみます
[root@送信 ~]# /etc/init.d/td-agent stop
Stopping td-agent: td-agent                                [  OK  ]

[root@送信 ]# for i in `seq -w 06 10` ; do echo "`date`      $i" >> test.log ; done

[root@送信 ]# cat test.log
Tue Apr 10 11:54:58 UTC 2018      01
Tue Apr 10 11:54:58 UTC 2018      02
Tue Apr 10 11:54:58 UTC 2018      03
Tue Apr 10 11:54:58 UTC 2018      04
Tue Apr 10 11:54:58 UTC 2018      05
Tue Apr 10 13:00:54 UTC 2018      06
Tue Apr 10 13:00:54 UTC 2018      07
Tue Apr 10 13:00:54 UTC 2018      08
Tue Apr 10 13:00:54 UTC 2018      09
Tue Apr 10 13:00:54 UTC 2018      10
  • 手動でtest.logをローテートします
[root@送信 ]# logrotate -f /etc/logrotate.d/test
  • 再度ログを書き込んでみます
[root@送信 ]# for i in `seq -w 11 15` ; do echo "`date`      $i" >> test.log ; done

[root@送信 ]# cat test.log
Tue Apr 10 13:10:59 UTC 2018      11
Tue Apr 10 13:10:59 UTC 2018      12
Tue Apr 10 13:10:59 UTC 2018      13
Tue Apr 10 13:10:59 UTC 2018      14
Tue Apr 10 13:10:59 UTC 2018      15
  • td-agentを起動して受信側のログを確認します
[root@送信 ]# /etc/init.d/td-agent start
td-agent td-agent:                                         [  OK  ]

[root@受信 ]# tail tmp.log
Tue Apr 10 11:54:58 UTC 2018      01
Tue Apr 10 11:54:58 UTC 2018      02
Tue Apr 10 11:54:58 UTC 2018      03
Tue Apr 10 11:54:58 UTC 2018      04
Tue Apr 10 11:54:58 UTC 2018      05
Tue Apr 10 13:10:59 UTC 2018      11
Tue Apr 10 13:10:59 UTC 2018      12
Tue Apr 10 13:10:59 UTC 2018      13
Tue Apr 10 13:10:59 UTC 2018      14
Tue Apr 10 13:10:59 UTC 2018      15

td-agentが止めてから書き込まれたログは無視されています。

ローテート後のファイルからしかforwardされていません

考察

posファイルにはwatchするログのi-nodeと位置が記録されていますが、プロセスが落ちて起動させた際、これまでのposファイルに記録されたファイルや位置に関係なく、設定されたtail対象のファイルを探してi-nodeが更新されてしまうようです。

僕はposファイルのi-nodeが更新される前に、posファイルに記録されているi-nodeのファイルを最後まで読み切ってから次のファイルを見つけてtailすると思っていたのですが、そのような挙動では無いんですね、、

回避方法

約10分に1回ローテートが走る今回の環境ではtd-agentのプロセスが突然死する障害が起きた場合、例えば30分程度検知〜復旧に時間がかかると欠損が出てしまいます。

いろいろ調べましたが今回の事象を回避するようなオプションを見つけることが出来ませんでした。

このような場合にはいかにtd-agentのプロセスが死んでからの復旧を早めるかが重要になりそうです。

今回はmonitやsupervisorなどを使ってなるべくプロセスが死亡し続けないようにして回避できればなと考えています。

最後に

こんなのこういう風にすれば回避できるよとかあれば情報を頂けると助かりますm( )m