Буферизация в 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