Fluentdのプラグインのメモリリークの特定を支援するプラグインを使う方法 - 2021-10-06 - ククログ

ククログ

株式会社クリアコード > ククログ > Fluentdのプラグインのメモリリークの特定を支援するプラグインを使う方法

Fluentdのプラグインのメモリリークの特定を支援するプラグインを使う方法

クリアコードではFluentdのサポートサービスを提供しています。

今回は、プラグインのメモリリークの特定を支援するプラグインを開発したので、 どんなことができるのか、またどのように使ったら良いのかを説明します。

なぜ特定の支援をするプラグインが必要なのか?

Fluentdには用途別にさまざまなプラグインがあり、それらを組み合わせて使うことで 非常に柔軟にログを収集・転送することができます。

その一方で、長時間時間実行しつづけるというソフトウェアの特性上、メモリリークしていると運用に影響がでて問題になります。 過去に遭遇したプラグインのメモリリークでは fluent-plugin-systemd でオブジェクトを破棄し忘れている事例がありました。

また、プラグイン本体ではなく、プラグインが利用しているCの拡張ライブラリー側でメモリリークしているという事例もありました。 いずれにせよ、これらのメモリリークは一定時間実行しないと発覚しにくいです。

シンプルなやりかたとしてはtopコマンドを定期的に実行してチェックするか、 fluent-plugin-watch-process を使ってプロセスごとのメモリ使用量を確認するというやりかたがあります。

しかし、Rubyの内部の状態を知りたい場合にはそれではできません。 若干トリッキーなやりかたとしてはrecord_modifierを使うと、より詳細な状態をレコードに記録することができます。

例えば、10秒ごとにGCの状況を raw_data フィールドに記録するには次のような設定で実現できます。

<filter **>
  @type record_modifier
  prepare_value GC::Profiler.enable; @gc_interval = Time.now + 10;
  remove_keys _dummy_
  <record>
    _dummy_ ${if Time.now > @gc_interval then GC.start; record['raw_data'] = GC::Profiler.raw_data; GC::Profiler.clear; @gc_interval = Time.now + 10; end}
  </record>
</filter>

これに加えて、プラグインで使っている特定のオブジェクトの数の推移を確認するには、ObjectSpace.each_object(対象のクラス名) などを使うとできます。 しかし、 対象となるクラスが増えるなどすると、 <record> の記述が複雑になってしまうという問題があります。

fluent-plugin-watch-objectspaceプラグインの使い方

そこで、このような作業を簡略化するために、次のような要件を満たすinputプラグインを開発しました。

  • 指定した間隔で memsize_of_all によるメモリ使用量を確認できる
  • 測定の基準となるメモリ使用量の測定を一定期間後にずらせる
  • 測定対象のクラスを任意に指定できる
  • メモリ使用量の増分のしきい値(比率)を指定できる
<source>
  @type watch_objectspace
  tag watch_objectspace
  modules cmetrics
  watch_class CMetrics::Counter, CMetrics::Gauge, CMetrics::Untyped, CMetrics::Serde
  watch_interval 60
  watch_delay 10
  <threshold>
    memsize_of_all 1.3
  </threshold>
</source>

上記は、測定対象となる cmetrics モジュールを読み込み、CMetrics::Counter, CMetrics::Gauge, CMetrics::Untyped, CMetrics::Serde の4つのクラスのオブジェクトを60秒ごとにカウントします。(比較の基準となるメモリ使用量は10秒後のものを使う) メモリ使用量の増加分が3割を超えるとエラーをログに記録するための設定となっています。

例えば、このプラグインでメモリ使用量が想定以上に増加した場合、次のようなログが記録されます。

2021-09-30 16:32:47.797488204 +0900 watch_objectspace: {"pid":342228,"count":{"cmetrics::counter":37,"cmetrics::gauge":68,"cmetrics::untyped":7,"cmetrics::serde":7},"memory_leaks":false,"memsize_of_all":14946683,"virt":251232,"res":61304,"shr":10100,"%cpu":0.0,"%mem":0.2,"time+":"0:00.82"}
2021-09-30 16:32:52 +0900 [error]: #0 Memory usage is over than expected, threshold of memsize_of_all rate <1.300000>: 27829366.5 > 18552911.000000 * 1.300000

さいごに

今回は、プラグインのメモリリークなどのように、想定よりも使用メモリが増加した場合を特定しやすくするプラグインの紹介をしました。

クリアコードの提供するFluentdのサポートサービスでは、障害発生時の調査や回避策の提案、パッチの提供などを行います。 Fluentdに関するトラブルを抱えて困っている方は、ぜひこちらのお問い合わせフォームからご連絡ください。