Буферизация в Fluent-bit

Постановка задачи

После того, как я настроил метрики и попробовал их использовать в течении несколько месяцев, обнаружился один существенный недостаток - данные легко потерять. У меня мониторятся Raspberry PI в удалённых местах. И каждый раз, когда пропадает сеть, или заканчиваются деньги на сим карте, или что-то ломается, сеть пропадает и совершенно невозможно понять, в чём проблема. А как раз метрики и логи нужны для того, чтобы такие проблемы исследовать!

В итоге я сформулировал следующие требования:

  • Сохранять данные локально и при подключении к сети отправлять на центральный сервер.
  • Возможность работать до нескольких месяцев в оффлайн режиме. Устройства могут работать удалённо и доступ к ним может быть ограничен.
  • Минимизировать использование диска, когда к сети есть доступ. Особенно актуально для Raspberry PI, в котором SD карта часто выходит из строя.

Ещё один случай, когда нужно сохранять метрики - это полевые испытания. Они выглядят следующим образом:

  • Raspberry PI с новой версией r2cloud и поворотным устройством устанавливается в поле
  • После тестирования, я подключаю Raspberry PI к домашней сети и сливаю данные наблюдений на сервер. В этот момент неплохо было бы сливать логи и накопленные метрики на центральный сервер

Поиск решения

После продолжительных поисков в Интернет, мне удалось найти несколько решений.

Буферизация данных на диске с помощью Fluent-bit

Идея заключается в том, чтобы использовать стандартный способ буферизации данных на диске, который есть во fluent-bit. Согласно документации, он будет сохранять данные в памяти и на диске. Как только закончится выделенная для этого память, он будет скидывать данные только на диск. Выглядит разумно. К сожалению, у этого подхода есть один существенный недостаток: данные пишутся на диск даже если есть доступ к сети. В итоге весь процесс выглядит так:

  • fluent-bit пишет данные в память и на диск, создавая файл
  • сразу же отправляет данные в сеть
  • удаляет файл

Эти файлы не очень большого объёма - 4кб, но для SD карты постоянная запись крайне вредна.

Использование репликации данных influxdb

influxdb поддерживает удалённую репликацию данных. Fluent-bit будет писать всегда в локальную базу, которая будет сохранять данные локально и одновременно отправлять на центральный сервер. Преимущества данного подхода:

  • стандартное решение, которое было разработано как раз для того, чтобы решить мою проблему
  • данные хранятся локально в оптимизированном формате. Если сеть недоступна длительное время, то influxdb может начать применять правила прорежевания данных (downsampling). Вместо удаления данных, он может хранить не минутные, а часовые сэмплы. Это можно настроить стандартным образом.
  • данные можно визуализировать даже если центральный сервер недоступен. В моём случае это не актуально, так как Raspberry PI слишком слабый и недоступен по сети!

Недостатки всё те же: если центральный сервер доступен, то данные всё равно будут писаться на локальный диск. Плюс к этому добавляется поддержка ещё одной базы: увеличивается потребление памяти и настройка всего этого. К тому же этот способ сработает только для метрик. Для логов придётся поднимать локальный Loki или придумывать что-то ещё.

Написать самому

Очень заманчивая опция. Можно было бы написать легковесный HTTP прокси, который бы:

  • при получении данных отправлял их дальше
  • если центральный сервер недоступен, то сохранял бы на диск
  • при проявлении сети, читал бы предыдущие запросы с диска и отправлял как обычно
  • работал как для метрик, так и для логов

Из недостатков: downsampling придётся реализовывать самому, а для этого нужно понимать какие запросы проксируются, нужен ещё один процесс, нужно много времени, чтобы написать и отладить.

Решение

В итоге из всех трёх решений я выбрал fluent-bit. А проблему с записью файла я решил с помощью дополнительного SSD. Тем более SSD всё равно нужен, чтобы повысить надёжность всей системы.

Для настройки буферизации достаточно следовать официальной документации. Правда тут есть небольшой нюанс: ничего не сработает. Не знаю почему, но по-умолчанию fluent-bit будет перепосылать chunk данных всего один раз. В итоге вся буферизация оказывается бессмысленной. Данные будут удаляться примерно через 7-15 секунд. Для того, чтобы всё сработало надо дополнительно указать Retry_Limit: False. В результате конфигурация выглядит следующим образом:

service:
  storage.path: /var/log/fluent-bit/
  storage.backlog.mem_limit: 5MB

pipeline:
  inputs:
    - name: cpu
      tag: metrics.cpu
      interval_sec: 30
      storage.type: filesystem
  outputs:
    - name: influxdb
      match: metrics.*
      host: somehost
      database: fluentbit
      tag_keys: hostname
      Retry_Limit: False
      storage.total_limit_size: 10G

Но это ещё не всё. По-умолчанию Loki отбрасывает логи старше одной недели. Хорошо, что это можно отключить следующим образом:

limits_config:
  reject_old_samples: false