График за прошлый месяц есть, а avg в триггере пишет «недостаточно данных»: когда в Zabbix 7.0 нужен trendavg
Классическая ситуация: админ ужал историю, чтобы база перестала расти, графики за год как рисовались, так и рисуются, все довольны. А через месяц выясняется, что триггер «нагрузка выросла против прошлого месяца» тихо ушёл в «недостаточно данных» и не сработал ни разу. Разбираю, почему графики и триггеры в Zabbix читают разные таблицы, как это диагностировать за пять минут, чем именно trendavg отличается от avg и что ломается при переписывании триггеров на trend-функции.
Графики рисуются, а триггер молчит: почему так вообще бывает
Начну с картины, которую вижу у клиентов раз в квартал. Понедельник, руководитель открывает дашборд: график входящего трафика на аплинке за последние 12 месяцев на месте, сезонность видна, всё красиво. Рядом висит триггер «средняя нагрузка выросла более чем на 30 % против прошлого месяца» — и он в состоянии Unknown с припиской про недостаточное количество данных. Причём висит так уже недель шесть, и никто этого не заметил, потому что переход триггера в Unknown не создаёт проблему: Zabbix генерирует только внутреннее событие, и если под него не настроено действие в Alerts → Actions → Internal actions, никто ничего не получит.
Разгадка простая и неочевидная одновременно. Zabbix хранит числовые метрики в двух независимых слоях. History — это каждое отдельное измерение так, как оно пришло с агента: itemid, время, значение. Trends — часовые агрегаты: за каждый час по каждому item сохраняются минимум, среднее, максимум и количество значений, из которых это среднее посчитано. Сроки хранения у слоёв настраиваются раздельно, и это ключевой момент.
Дальше начинается расхождение. Графики в Zabbix умеют деградировать корректно: если history за нужный период уже подчищена хаускипером, фронтенд подставляет данные из trends и продолжает рисовать линию. В документации это записано прямым текстом — при короткой истории вы всё равно сможете просматривать старые данные на графиках, потому что графики используют значения трендов. А вот функции triggers-выражений вроде avg(), min(), max(), last() работают строго по history и никуда автоматически не переключаются. Нет истории — нет и результата.
Получается тихий отказ: визуальная часть системы работает, аналитическая — нет, и никакого события об этом не приходит. Именно поэтому я считаю такую ситуацию не мелкой настроечной неточностью, а вполне себе инцидентом мониторинга: система перестала видеть рост нагрузки и износ железа ровно в тот момент, когда её об этом попросили.
- history — отдельные измерения, таблицы history, history_uint, history_str, history_log, history_text;
- trends — часовые агрегаты только для числовых типов, таблицы trends (float) и trends_uint (unsigned);
- графики при отсутствии history автоматически берут trends;
- avg()/min()/max()/sum() и прочие history-функции на trends не переключаются никогда;
- trendavg()/trendmin()/trendmax()/trendsum()/trendcount() читают только trends и не видят history.
Что где хранится и кто это удаляет
Структура таблицы трендов предельно скупая: itemid, clock (начало часа), num, value_min, value_avg, value_max. Никаких перцентилей, никакой формы распределения внутри часа. Это надо принять как данность до того, как вы начнёте переписывать триггеры: percentile() по трендам вы не посчитаете, всплеск длиной три минуты внутри часа в trends превратится в чуть приподнятый max и почти незаметный avg. Для отчётности и для сравнения «месяц к месяцу» этого хватает с запасом, для ловли коротких пиков — нет.
Срок хранения задаётся в трёх местах: в карточке самого item (поля History и Trends), через массовое обновление элементов и глобально в Administration → Housekeeping. Глобальные переключатели называются Override item history period и Override item trend period; если их включить, значения в карточках элементов игнорируются, и вся база живёт по одному правилу. В карточке элемента история задаётся от одного часа до 25 лет, тренды — от одного дня до 25 лет, плюс вариант Do not store; в глобальных настройках Housekeeping поле принимает значения от 1 часа до 25 лет либо 0.
Отдельно про дефолты, потому что на них и строится большинство ошибочных ожиданий. В Zabbix 7.0 новый элемент данных создаётся с History = 31d и Trends = 365d, и официальные шаблоны переведены на эти же 31 день истории (раньше по умолчанию было 90 дней). То есть «из коробки» avg() за 30 дней ещё считается, а сравнение «последние 30 дней против предыдущих 30» уже упирается в край истории: ему нужно 60 дней. Удаляет устаревшие данные встроенный хаускипер: по умолчанию он запускается раз в час (HousekeepingFrequency=1 в zabbix_server.conf) и за один проход удаляет не больше MaxHousekeeperDelete строк на элемент (по умолчанию 5000), поэтому после резкого сокращения сроков на обычном PostgreSQL или MySQL база худеет не сразу.
Если у вас PostgreSQL с TimescaleDB — а на новых стендах я ставлю именно эту связку, — оба override включать обязательно. Документация прямо требует включить Override item history period, Override item trend period и внутренний хаускипинг, иначе автоматическое партиционирование не будет дропать чанки, а во фронтенде повиснут предупреждения о конфигурации. И тут же появляется вторая ловушка: TimescaleDB сжимает старые чанки, а хаускипер, который удаляет данные построчно, по сжатым чанкам работать не может — поэтому сроки хранения должны выставляться именно глобально, чтобы старые данные уходили удалением чанков целиком.
Проверить фактическое положение дел удобнее всего запросом в базу, а не глазами по карточкам элементов. Вот что я запускаю первым делом, когда клиент говорит «у нас что-то с историей»:
-- элементы, у которых тренды выключены совсем (и long-term аналитика по ним невозможна)
SELECT h.host, i.key_, i.history, i.trends
FROM items i
JOIN hosts h ON h.hostid = i.hostid
WHERE i.trends = '0'
AND i.value_type IN (0, 3) -- 0 = float, 3 = unsigned
AND i.status = 0 AND h.status = 0
ORDER BY h.host, i.key_;И сразу второй запрос — по конкретному проблемному item, чтобы увидеть реальные границы данных в обоих слоях. Именно он снимает спор «да у нас всё хранится» за десять секунд:
SELECT 'history' AS src, to_timestamp(min(clock)) AS oldest,
to_timestamp(max(clock)) AS newest, count(*) AS rows
FROM history_uint WHERE itemid = 45217
UNION ALL
SELECT 'trends', to_timestamp(min(clock)), to_timestamp(max(clock)), count(*)
FROM trends_uint WHERE itemid = 45217;- History — детальные значения, дефолт для нового item в 7.0: 31d;
- Trends — часовые min/avg/max/num, дефолт 365d, только для Numeric (float) и Numeric (unsigned);
- сроки задаются в item, массовым обновлением или глобальными override в Administration → Housekeeping;
- хаускипер по умолчанию ходит раз в час и удаляет порциями (MaxHousekeeperDelete), а не мгновенно;
- с TimescaleDB обязательны оба override и включённый внутренний хаускипинг для history и trends.
Разбор из практики: креативное агентство на 42 рабочих места
Возьму проект из практики, клиента назову условно — креативное агентство «Креатив-цех», 42 рабочих места, один офис, рендер-станции и файловое хранилище с макетами и видео. Мониторинг: Zabbix 7.0 LTS на Ubuntu 24.04, PostgreSQL 16 с TimescaleDB, 23 хоста, около 2 600 активных элементов данных, порядка 60 NVPS. Виртуалка на два ядра и 8 ГБ памяти, диск 200 ГБ. К лету база доросла до 150 ГБ, место заканчивалось, и коллега клиента сделал ровно то, что советует любой первый ответ в поиске: включил глобальный override и срезал историю с 90 дней до 7, оставив тренды на 730 дней.
Решение, кстати, абсолютно правильное. Как только хаускипер прошёл по базе и удалил устаревшие чанки, она ужалась примерно до 25 ГБ, Latest data стала открываться заметно быстрее, нагрузка на диск упала. Проблема была не в этом, а в том, что вместе с историей молча отвалились девять триггеров, написанных в стиле «сравни текущий месяц с предыдущим». Выглядели они так:
avg(/kc-gw/net.if.in[eth1],30d) > 1.3 * avg(/kc-gw/net.if.in[eth1],30d:now-30d)Пока история жила 90 дней, выражение считалось. После сокращения до 7 дней левая часть ещё как-то набирала данные, правая не набирала ничего, и триггер уходил в Unknown с ошибкой о нехватке данных для вычисления функции. Заметили это только когда я делал плановый аудит и открыл фильтр по состоянию триггеров: 9 Unknown, самый старый — 41 день. Ни одного письма, ни одного алерта: действия по внутренним событиям на этом стенде никто не настраивал.
Переписали всё на trend-функции. Ключевой момент — не просто заменить avg на trendavg, а перейти с плавающих окон на календарные. Плавающее «последние 30 дней против предыдущих 30 дней» в отчётности всё равно никого не устраивало, потому что руководитель мыслит календарными месяцами. Итоговое выражение получилось таким:
trendavg(/kc-gw/net.if.in[eth1],1M:now/M) >
1.3 * trendavg(/kc-gw/net.if.in[eth1],1M:now/M-1M)Здесь 1M:now/M — это полный предыдущий календарный месяц, а 1M:now/M-1M — позапрошлый. Никаких обрезков, никакой зависимости от того, в какой день вы смотрите. По итогам: 9 триггеров переписаны, ещё 4 добавлено (по свободному месту на файловом хранилище с проектами и по средней загрузке рендер-станций), история осталась 7 дней, тренды подняли до 5 лет — это около 57 миллионов строк, с компрессией TimescaleDB единицы гигабайт. Побочный эффект, который клиенту понравился больше всего: нагрузка на базу от самих триггеров упала. При минутном интервале окно в 30 дней — это 43 200 строк истории на каждое вычисление, а трендов за тот же период всего 720.
Кандидатов на переписывание перед сокращением истории я ищу запросом к базе. Важная деталь: в Zabbix 5.4+ в triggers.expression хранятся не имена функций, а ссылки вида {functionid}, сами функции и их параметры лежат в таблице functions, поэтому искать надо там:
SELECT DISTINCT t.triggerid, t.description, f.name, f.parameter
FROM functions f
JOIN triggers t ON t.triggerid = f.triggerid
WHERE f.name IN ('avg','min','max','sum','count')
AND f.parameter ~ '[0-9]+[dwM]'
AND t.status = 0
ORDER BY t.description;- симптом: графики за год рисуются, а триггеры сравнения периодов висят в Unknown;
- причина: окно avg() со сдвигом (30d:now-30d) требует 60 дней истории, а осталось 7;
- диагностика: фильтр триггеров по состоянию Unknown и запрос к таблице functions;
- исправление: trendavg с календарными якорями now/M вместо плавающих окон;
- страховка: действие на внутренние события «триггер перешёл в Unknown».
Синтаксис trendavg и его родственников
Общая форма всех trend-функций одинакова: имя, ссылка на элемент, затем обязательный второй параметр вида «период:сдвиг». Период задаётся как число плюс единица времени, минимум — 1h, единицы: h (час), d (день), w (неделя), M (месяц), y (год). Сдвиг — смещение точки отсчёта в прошлое, и именно якорь в нём делает период календарным: now/h — граница часа, now/d — граница суток, now/M — граница месяца, now/y — граница года.
Документация Zabbix 7.0 даёт канонический набор примеров, который я советую держать перед глазами при первой миграции. Он снимает 90 % вопросов «а как написать позапрошлую неделю»:
trendavg(/host/key,1h:now/h) # среднее за предыдущий час
trendavg(/host/key,1h:now/h-1h) # среднее за два часа назад
trendavg(/host/key,1h:now/h-2h) # среднее за три часа назад
trendavg(/host/key,1M:now/M-1y) # среднее за предыдущий месяц год назадСемейство trend-функций в 7.0 состоит из восьми штук: trendavg, trendmin, trendmax, trendsum, trendcount, trendstl, baselinedev и baselinewma. Первые пять — прямые аналоги привычных history-функций. trendcount, к слову, крайне полезен для самопроверки: если trendcount(/host/key,1M:now/M) вернул подозрительно мало, значит за прошлый месяц агент половину времени не отвечал, и любые выводы по trendavg за тот же период надо делить надвое.
Отдельно стоят две baseline-функции, и вот их я советую попробовать всем, кто устал выдумывать пороги руками. baselinewma(/host/key, data period:time shift, season unit, num seasons) считает взвешенное скользящее среднее по одному и тому же участку нескольких прошлых «сезонов»: например, baselinewma(/host/key,1h:now/h,"d«,3) возьмёт тот же самый час суток за три предыдущих полных дня. baselinedev с теми же параметрами возвращает не значение, а количество отклонений от сезонной базы, посчитанное алгоритмом stddevpop — по документированному примеру baselinedev(/host/key,1d:now/d,»M",6) сравнивается предыдущий день с тем же днём за шесть прошлых месяцев. Единица сезона — h, d, w, M или y.
- период у trend-функций не может быть меньше 1h — trendavg(/host/key,30m:now/h) не заработает;
- сдвиг с календарным якорем (now/h, now/d, now/M) — не украшение, а способ гарантировать, что период выровнен по границе часа;
- trendcount по тому же периоду — бесплатная проверка полноты данных;
- baselinewma и baselinedev избавляют от ручных порогов там, где нагрузка сезонная;
- trendstl возвращает долю аномалий от 0 до 1 — вещь мощная, но требующая аккуратной настройки, на небольших стендах я её обычно не включаю.
Главный сюрприз: триггер на trend-функциях пересчитывается редко
Вот та деталь, из-за которой миграция чаще всего выглядит как «переписал, а оно всё равно не работает». В документации Zabbix записано: триггеры, которые ссылаются исключительно на trend-функции, вычисляются один раз за наименьший временной период в выражении. Не при каждом новом значении, как вы привыкли, а по границе периода.
Разберу на примере. Если в выражении есть и 1d, и 1w — триггер будет пересчитан один раз в сутки. Если только 1M — раз в месяц. Это ровно то поведение, которое нужно для отчётной аналитики, и совсем не то, которого ждёт человек, привыкший к секундной реакции мониторинга. Я на этом обжигался: переписал триггер по дисковому пространству на trendavg с месячным окном, а потом сутки объяснял, почему после явного роста нагрузки триггер не позеленел обратно немедленно.
Второй нюанс из той же оперы: как только вы подмешиваете в выражение хотя бы одну history-функцию, правило «раз в период» отменяется, и триггер снова считается по обычным принципам вычисления, как любой триггер на history-функциях. С точки зрения нагрузки это худший вариант из возможных: вы получаете и тяжёлые обращения к trends, и их частоту от history. Поэтому я держу такие вещи раздельно: триггер сравнения «месяц к месяцу» — чисто на trend-функциях, оперативный триггер «прямо сейчас плохо» — чисто на history.
И третье: пересчёт привязан к завершившемуся периоду, а не к текущему. Никогда не пишите в trend-функции окно, захватывающее текущий незакрытый час. Сервер накапливает тренды в кэше и сбрасывает их в базу по определённым событиям — когда пришло первое значение нового часа, когда до конца часа осталось пять минут и обновлений нет, или при остановке сервера. Документация честно предупреждает: до появления трендов на графике может пройти до двух часов. В коллективном блоге Zabbix эта же мысль сформулирована как правило — для trend-функций надо учитывать только данные до последнего полного часа, потому что существует процесс синхронизации trend-кэша.
- триггер только на trend-функциях считается раз за наименьший период выражения (1d и 1w — раз в сутки);
- добавили хотя бы одну history-функцию — триггер снова считается на каждом новом значении;
- окно не должно захватывать текущий незакрытый час: тренд за прошлый час сбрасывается в базу с задержкой;
- до появления тренда за час может пройти до двух часов;
- оперативные и отчётные условия держите в разных триггерах.
Мой чек-лист: как перевести стенд на trends и ничего не потерять
Порядок действий, которым я пользуюсь на всех клиентских стендах. Он сознательно начинается не с урезания истории, а с инвентаризации — потому что сокращать хранение до того, как вы поняли, кто на него опирается, это и есть та ошибка, ради которой написана вся статья.
Сначала аудит: выгружаете все триггеры с окнами больше суток, все calculated-элементы и все виджеты дашбордов типа Item value / Top hosts с агрегацией за длинный период. Затем правите триггеры — переводите на trendavg с календарными якорями. Потом проверяете, что у нужных элементов тренды вообще включены (запрос по items.trends из второго раздела). И только после этого трогаете срок хранения истории.
По цифрам мои дефолты для компаний до 50 рабочих мест такие: history 7–14 дней, trends 3–5 лет, глобальный override включён, внутренний хаускипинг включён, TimescaleDB с компрессией. Тренды почти ничего не весят: одна строка на item в час, для стенда на 6 000 числовых элементов это примерно 52,5 миллиона строк в год — единицы гигабайт. Держать их три-пять лет вместо дефолтного одного года — решение, которое стоит дешевле, чем один разговор с директором о том, почему нет данных за позапрошлый год.
Ещё одна вещь, которую редко делают: подкрутить кэши сервера. У Zabbix есть отдельный параметр TrendCacheSize (буфер накопления часовых агрегатов) и TrendFunctionCacheSize (кэш результатов trend-функций). Второй нужен, чтобы триггеры и вычисляемые элементы с trend-функциями не долбили базу одинаковыми запросами. После массовой миграции триггеров на trends оба стоит поднять и потом посмотреть на внутренние метрики кэшей — Zabbix отдаёт их собственными item’ами семейства zabbix[tcache,cache,<параметр>] (эффективность кэша trend-функций) и zabbix[wcache,trend,...] (заполнение кэша трендов).
- выгрузить триггеры с окнами > 1d и переписать на trend-функции с якорями now/d, now/M;
- проверить items.trends != 0 у всех элементов, участвующих в долгосрочной аналитике;
- включить Override item history period и Override item trend period в Administration → Housekeeping;
- для TimescaleDB — обязательно оба override плюс внутренний хаускипинг, иначе чанки не дропаются;
- поднять TrendCacheSize и TrendFunctionCacheSize в zabbix_server.conf и перезапустить сервер;
- через сутки проверить, что нет триггеров в состоянии Unknown с ошибкой о нехватке данных;
- добавить один служебный триггер, который следит за самим наличием данных: trendcount(/host/key,1d:now/d)=0.
Грабли, спорные места и что можно не делать
Начну с того, где риск обычно преувеличен. Многие боятся сокращать историю до недели, считая, что «потеряют данные». Не потеряете, если тренды включены: графики продолжат рисоваться, отчёты — считаться, а всё, что вы реально теряете, это возможность посмотреть отдельные измерения глубже недели. За 15 лет практики я ни разу не видел задачи, где админу через два месяца понадобилась бы конкретная точка с интервалом в минуту. Час детализации хватает.
Теперь где риск недооценивают. Первое — дискавери-шаблоны. В прототипах элементов, приезжающих из шаблонов вендора, значения History и Trends приходят из шаблона, и при обновлении или повторной привязке шаблона ручные правки в карточках могут откатиться. Держите переопределения на уровне глобального override, а не в карточках, тогда обновление шаблона вам ничего не сломает. Второе — зависимые элементы: у мастер-item часто ставят history=0 ради экономии, и это нормально, но если кто-то потом напишет по нему триггер, тот просто не будет вычисляться, потому что триггерные функции считаются по истории.
Спорное место, где единого мнения в сообществе нет: стоит ли вообще держать history больше пары дней, если триггеры переписаны на trends. Часть коллег утверждает, что 2 суток достаточно, потому что оперативная диагностика всё равно смотрит последние часы. Моя позиция — 7–14 дней, и вот почему: инцидент нередко всплывает в понедельник за события прошлой недели, и когда надо посмотреть точную форму всплеска в прошлый четверг, часовое среднее вам не расскажет ничего. Разница в объёме базы между 2 и 14 днями на стенде среднего размера — десятки гигабайт, это не та экономия, за которую я готов платить слепотой при разборе инцидента.
И то, на что можно спокойно забить. Не надо переписывать на trend-функции вообще всё подряд — оперативные триггеры по доступности, по свободному месту прямо сейчас, по загрузке CPU за пять минут отлично живут на history и должны там остаться. Не надо гнаться за trendstl без реальной сезонности в данных — на стенде на 40 хостов вы потратите неделю на подбор параметров и получите шум. И не надо вручную чистить таблицы trends: они маленькие, а ручной DELETE по большой таблице в PostgreSQL — это отдельная история с раздуванием и вакуумом, которую вы себе устроите на ровном месте.
- не переписывайте на trends оперативные триггеры: доступность, CPU за 5 минут, свободное место прямо сейчас;
- не держите history меньше недели: форма всплеска нужна при разборе инцидентов;
- не чистите таблицы trends вручную DELETE-ом;
- не включайте trendstl без выраженной сезонности в данных;
- не храните сроки только в карточках шаблонных элементов, используйте глобальный override.
Частые вопросы
Почему график за прошлый месяц есть, а avg() пишет «недостаточно данных»?
Потому что это разные источники. Графики при отсутствии history автоматически подставляют часовые агрегаты из trends и продолжают рисоваться. Функция avg() читает исключительно history и на trends не переключается. Как только хаускипер вычистил историю за нужный период, выражение перестаёт вычисляться, а триггер уходит в Unknown. Решение — переписать выражение на trendavg().
Как в Zabbix 7.0 посчитать среднее за предыдущий календарный месяц?
Выражением trendavg(/host/key,1M:now/M). Сдвиг now/M выравнивает окно по границе календарного месяца, поэтому результат не зависит от того, в какой день вы смотрите. Позапрошлый месяц — trendavg(/host/key,1M:now/M-1M), тот же месяц год назад — документированный пример trendavg(/host/key,1M:now/M-1y).
Как часто пересчитывается триггер, написанный только на trend-функциях?
По документации Zabbix — один раз за наименьший временной период в выражении. Если в выражении есть 1d и 1w, триггер проверяется раз в сутки. Если только 1M — раз в месяц. Как только вы добавите в то же выражение хотя бы одну history-функцию, действует обычное правило и триггер начинает считаться на каждом новом значении.
Можно ли поставить History storage period = 0 и жить только на трендах?
Технически можно, но триггеры по такому элементу вычисляться не будут вообще — документация прямо указывает, что оценка триггеров построена на данных истории. Останутся только зависимые элементы, инвентарь и накопление трендов. Я так делаю лишь для мастер-элементов, из которых парсятся зависимые метрики, и никогда — для элементов, по которым есть алерты.
Сколько места занимают тренды и сколько их стоит хранить?
Одна строка на элемент в час: для стенда на 6 000 элементов это около 52,5 миллиона строк в год, единицы гигабайт. По умолчанию в Zabbix 7.0 это 31 день истории и 365 дней трендов. Мой дефолт для небольших компаний — history 7–14 дней, trends 3–5 лет. Экономить на трендах бессмысленно: именно они дают сравнение год к году, а весят они на два порядка меньше истории.
Почему trendavg вернул значение, а данных за период почти не было?
Trends хранят среднее по фактически собранным значениям и их количество, но не знают, что агент молчал. Ставьте рядом контрольное выражение trendcount(/host/key,1M:now/M) — оно покажет, из скольких часов реально собран агрегат. Если значение сильно меньше числа часов в периоде, доверять среднему нельзя.
Источники
- Zabbix 7.0 — History and trends — Официальная документация Zabbix 7.0, раздел Configuration → Items → History and trends: состав trends (min/avg/max/count за час), правило History storage period = 0, сброс trend-кэша и задержка до 2 часов, фраза о том, что графики при короткой истории используют значения трендов. https://www.zabbix.com/documentation/7.0/en/manual/config/items/history_and_trends
- Zabbix 7.0 — Trend functions — Официальная документация Zabbix 7.0, Appendix → Functions → Trend functions: список из восьми функций (trendavg, trendcount, trendmax, trendmin, trendsum, trendstl, baselinedev, baselinewma), формат параметра «time period:time shift» с минимумом 1h, пример trendavg(/host/key,1M:now/M-1y), правило о пересчёте триггеров раз в наименьший период. https://www.zabbix.com/documentation/7.0/en/manual/appendix/functions/trends
- Zabbix 7.0 — Aggregate functions — Официальная документация Zabbix 7.0, Appendix → Functions → Aggregate functions: синтаксис avg(/host/key,(sec|#num)<:time shift>) и подтверждение, что функция работает по данным истории. https://www.zabbix.com/documentation/7.0/en/manual/appendix/functions/aggregate
- Zabbix 7.0 — Housekeeping — Официальная документация Zabbix 7.0, Web interface → Administration → Housekeeping: параметры Override item history period / Override item trend period, диапазон Data storage period от 1 часа до 25 лет либо ноль, требование включать оба override и внутренний хаускипинг при работе с TimescaleDB. https://www.zabbix.com/documentation/7.0/en/manual/web_interface/frontend_sections/administration/housekeeping
- Zabbix Blog — Zabbix in: exploratory data analysis rehearsal, Part 1 — Официальный блог Zabbix: сравнение history-based и trend-based функций, тезис о ресурсоёмкости расчёта history-функций на длинных периодах и правило учитывать только данные до последнего полного часа из-за синхронизации trend-кэша. https://blog.zabbix.com/zabbix-in-exploratory-data-analysis-rehearsal-part-1/25802/
- Zabbix 7.0 — Item configuration — Официальная документация Zabbix 7.0, Configuration → Items → Item: поля History (Do not store / Store up to, от 1 часа до 25 лет) и Trends (от 1 дня до 25 лет), глобальное переопределение в Administration → Housekeeping, отсутствие трендов для нечисловых типов. https://www.zabbix.com/documentation/7.0/en/manual/config/items/item
- Zabbix 7.0 — Zabbix server configuration file — Официальная документация Zabbix 7.0, Appendix → Configuration files → Zabbix server: параметры TrendCacheSize, TrendFunctionCacheSize, HousekeepingFrequency, MaxHousekeeperDelete. https://www.zabbix.com/documentation/7.0/en/manual/appendix/config/zabbix_server
- Zabbix 7.0 — Internal checks — Официальная документация Zabbix 7.0, Configuration → Items → Item types → Internal checks: zabbix[tcache,...] и zabbix[wcache,...]. https://www.zabbix.com/documentation/7.0/en/manual/config/items/itemtypes/internal
