[comment]: # ({c34725dc-f445d963})
# Прогнозирующие функции триггеров

[comment]: # ({/c34725dc-f445d963})

[comment]: # ({9dac6d6d-9dac6d6d})
#### Обзор

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

В Zabbix есть инструменты для прогнозирования будущего поведения
контролируемой системы на основе исторических данных. Эти инструменты
реализованы с помощью прогностических функций триггеров.

[comment]: # ({/9dac6d6d-9dac6d6d})

[comment]: # ({827f1d5f-24b155a7})
#### Функции

Перед настройкой триггера необходимо определить, что считается проблемным состоянием и
сколько времени требуется для принятия мер. Затем есть два способа настроить
триггер, сигнализирующий о потенциальной нежелательной ситуации. Первый: 
триггер должен сработать, когда ожидается, что система будет
в проблемном состоянии через «время на реагирование». Второй: триггер должен сработать, когда система
достигнет проблемного состояния менее чем через «время на реагирование».
Соответствующие функции триггера для использования — **forecast** и
**timeleft**. Обратите внимание, что лежащий в основе статистический анализ по сути
идентичен для обеих функций. Вы можете настроить триггер любым удобным для вас способом
и получить схожие результаты.

[comment]: # ({/827f1d5f-24b155a7})

[comment]: # ({9f0f6aee-c80922f6})
#### Параметры

Обе функции используют почти одинаковый набор параметров. Для справки используйте список [поддерживаемых функций](/manual/config/triggers/expression#functions).

[comment]: # ({/9f0f6aee-c80922f6})

[comment]: # ({33e199b9-a93b071e})
##### Интервал времени

Прежде всего, следует указать исторический период, который Zabbix должен
проанализировать, чтобы построить прогноз. Это делается привычным способом
с помощью параметра `time period` и необязательного сдвига по времени, так же,
как и в функциях **avg**, **count**, **delta**, **max**, **min** и **sum**.

[comment]: # ({/33e199b9-a93b071e})

[comment]: # ({55d83c24-b922d0f2})
##### Горизонт прогнозирования

(только для **forecast**)<br>
Параметр `time` указывает, насколько далеко в будущее Zabbix должен
экстраполировать зависимости, обнаруженные в исторических данных. Независимо от того, используете вы
`time_shift` или нет, `time` всегда отсчитывается от текущего
момента.

[comment]: # ({/55d83c24-b922d0f2})

[comment]: # ({1ccaacd1-625c0c85})
##### Порог для достижения

(только для **timeleft**)<br>
Параметр `threshold` задаёт значение, которого анализируемый элемент данных должен достичь,
независимо от того, сверху или снизу. После того как мы определили f(t)
(см. ниже), следует решить уравнение f(t) = `threshold` и вернуть
корень, который ближе к текущему моменту и находится справа от него, либо
1.7976931348623158E+308, если такого корня нет.

::: notetip
Когда значения элемента данных приближаются к порогу, а затем пересекают
его, **timeleft** предполагает, что пересечение уже произошло в прошлом, и
поэтому переключается на следующее пересечение с уровнем `threshold`, если
таковое имеется. Рекомендуется использовать прогнозы как дополнение к
обычной диагностике проблем, а не как её замену.^[1](#footnotes)^
:::

[comment]: # ({/1ccaacd1-625c0c85})

[comment]: # ({4d1deb86-976bd98e})
##### Функции аппроксимации

По умолчанию `fit` — это *линейная* функция. Но если ваша отслеживаемая система
более сложная, у вас есть больше вариантов на выбор.

|`fit`|x = f(t)|
|-----|--------|
|*linear*|x = a + b\*t|
|*polynomialN*^[2](#footnotes)^|x = a~0~ + a~1~\*t + a~2~\*t^2^ + ... + a~n~\*t^n^|
|*exponential*|x = a\*exp(b\*t)|
|*logarithmic*|x = a + b\*log(t)|
|*power*|x = a\*t^b^|

[comment]: # ({/4d1deb86-976bd98e})

[comment]: # ({3c1c1442-add67840})
##### Режимы

(только для **forecast**)<br>
Каждый раз, когда вычисляется функция триггера, она получает данные из
указанного периода истории и подбирает указанную функцию к данным. Таким
образом, если данные немного отличаются, подобранная функция также будет
немного отличаться. Если просто вычислить значение подобранной функции в
указанный момент времени в будущем, вы ничего не узнаете о том, как
ожидается поведение анализируемого элемента данных в промежутке между
текущим моментом и этим моментом в будущем. Для некоторых параметров `fit`
(например, *polynomial*) простое значение из будущего может вводить в
заблуждение.

|`mode`|Результат **forecast**|
|------|----------------------|
|*value*|f(now + `time`)|
|*max*|max~now\ <=\ t\ <=\ now\ +\ `time`~ f(t)|
|*min*|min~now\ <=\ t\ <=\ now\ +\ `time`~ f(t)|
|*delta*|*max* - *min*|
|*avg*|среднее значение f(t) (now <= t <= now + `time`) согласно [определению](https://en.wikipedia.org/wiki/Mean_of_a_function)|

[comment]: # ({/3c1c1442-add67840})

[comment]: # ({3f946ebf-5ff2285e})
#### Подробности

Чтобы избежать вычислений с огромными числами, мы рассматриваем временную метку
первого значения в указанном периоде плюс 1 нс как новое нулевое время (текущее
время эпохи имеет порядок 10^9^, квадрат эпохи — 10^18^, двойная точность
составляет около 10^-16^). 1 нс добавляется, чтобы обеспечить все положительные
значения времени для *логарифмической* и *степенной* аппроксимации, которые
включают вычисление log(t). Сдвиг времени не влияет на *линейную*,
*полиномиальную*, *экспоненциальную* аппроксимацию (кроме более простых и
точных вычислений), но изменяет форму *логарифмической* и *степенной*
функций.

[comment]: # ({/3f946ebf-5ff2285e})

[comment]: # ({d180bad2-660cda6b})
#### Возможные ошибки

Функции возвращают -1 в следующих случаях:

-   указанный период оценки не содержит данных;
-   результат математической операции не определён^[3](#footnotes)^;
-   численные осложнения (к сожалению, для некоторых наборов входных данных
    диапазон и точность формата чисел с плавающей точкой двойной точности
    оказываются недостаточными)^[4](#footnotes)^.

::: notetip
Предупреждения или ошибки не выдаются, если выбранная аппроксимация плохо
описывает предоставленные данные или если данных просто слишком мало для
точного прогнозирования.
:::

[comment]: # ({/d180bad2-660cda6b})

[comment]: # ({e57d3e18-06e0a230})
#### Примеры и обработка ошибок

Чтобы получить предупреждение, когда на вашем узле сети вот-вот закончится свободное место на диске, вы можете использовать такое выражение триггера:

    timeleft(/host/vfs.fs.size[/,free],1h,0)<1h

Однако в дело может вмешаться код ошибки -1 и перевести ваш триггер в проблемное состояние. В целом это хорошо, потому что вы получаете предупреждение о том, что ваши прогнозы работают некорректно, и вам следует изучить их более тщательно, чтобы выяснить причину. Но иногда это плохо, потому что -1 может просто означать, что за последний час не было получено данных о свободном месте на диске узла сети. Если вы получаете слишком много ложноположительных оповещений, рассмотрите возможность использования более сложного выражения триггера ^[5](#footnotes)^:

    timeleft(/host/vfs.fs.size[/,free],1h,0)<1h and timeleft(/host/vfs.fs.size[/,free],1h,0)<>-1

С **forecast** ситуация немного сложнее. Прежде всего, -1 может как перевести триггер в проблемное состояние, так и не сделать этого, в зависимости от того, есть ли у вас выражение вида `forecast(/host/item,(...))<...` или вида `forecast(/host/item,(...))>...`

Кроме того, -1 может быть допустимым прогнозом, если для элемента данных нормально иметь отрицательное значение. Но вероятность такой ситуации в реальных условиях пренебрежимо мала (см.
[как](/manual/config/triggers/expression) работает оператор **=**). Поэтому добавьте `... or forecast(/host/item,(...))=-1` или
`... and forecast(/host/item,(...))<>-1`, если вы соответственно хотите или не хотите рассматривать -1 как проблему.

#### Сноски

^**1**^ Например, простой триггер вида
    `timeleft(/host/item,1h,X) < 1h` может перейти в проблемное состояние, когда значение элемента данных приближается к X, а затем внезапно восстановиться, как только значение X будет достигнуто. Если проблема заключается в том, что значение элемента данных ниже X, используйте:
    `last(/host/item) < X or timeleft(/host/item,1h,X) < 1h` Если проблема заключается в том, что значение элемента данных выше X, используйте:
    `last(/host/item) > X or timeleft(/host/item,1h,X) < 1h`

^**2**^ Степень полинома может быть от 1 до 6, *polynomial1* эквивалентен
    *linear*. Однако используйте полиномы более высокой степени [с
    осторожностью](https://en.wikipedia.org/wiki/Runge's_phenomenon). Если период оценки содержит меньше точек, чем требуется для определения коэффициентов полинома, степень полинома будет понижена (например,
    запрошен *polynomial5*, но есть только 4 точки, поэтому будет аппроксимирован
    *polynomial3*).

^**3**^ Например, аппроксимация функциями *exponential* или *power* включает
    вычисление log() от значений элемента данных. Если данные содержат нули или отрицательные числа, вы получите ошибку, поскольку log() определён только для положительных значений.

^**4**^ Для аппроксимаций *linear*, *exponential*, *logarithmic* и *power* все
    необходимые вычисления можно записать явно. Для *polynomial* без дополнительных шагов можно вычислить только *value*.
    Вычисление *avg* включает нахождение первообразной полинома
    (аналитически). Вычисление *max*, *min* и *delta* включает
    нахождение производной полинома (аналитически) и поиск её корней
    (численно). Решение f(t) = 0 включает поиск корней полинома
    (численно).

^**5**^ Но в этом случае -1 может привести к восстановлению вашего триггера из проблемного состояния. Чтобы полностью защититься, используйте:
    `timeleft(/host/vfs.fs.size[/,free],1h,0)<1h and ({TRIGGER.VALUE}=0 and timeleft(/host/vfs.fs.size[/,free],1h,0)<>-1 or {TRIGGER.VALUE}=1)`

[comment]: # ({/e57d3e18-06e0a230})
