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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[comment]: # ({55d83c24-b922d0f2})
##### Горизонт предсказания

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

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

[comment]: # ({1ccaacd1-625c0c85})
##### Достигаемый порог

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

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

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

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

По умолчанию `аппроксимация` является линейной (*linear*) функцией. Но если наблюдаемая система более сложная, вы можете выбрать один из следующих вариантов.

|`аппроксимация`|x = f(t)|
|-----|--------|
|линейная (*linear*)|x = a + b\*t|
|полиномиальная (*polynomialN*)^[2](#примечания)^|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>
Каждый раз, когда вычисляется функция триггера, данные запрашиваются из указанного периода истории и по полученным данным строится указанная аппроксимация. Поэтому, если данные немного изменятся, то и построенная аппроксимация немного изменится. Если мы будем просто рассчитывать значение функции аппроксимации в заданный момент времени в будущем, то вы ничего не будете знать о том, как согласно прогнозу будет меняться анализируемый элемент данных между текущим моментом и этим моментом в будущем. При некоторых параметрах `аппроксимации` (вроде *polynomial*) просто лишь одно значение из будущего может ввести в заблуждение.

|`режим`|Результат **forecast**|
|------|-------------------|
|значение (*value*)|f(сейчас + `время`)|
|максимум (*max*)|max~сейчас\ <=\ t\ <=\ сейчас\ +\ `время`~ f(t)|
|минимум (*min*)|min~сейчас\ <=\ t\ <=\ сейчас\ +\ `время`~ f(t)|
|дельта (*delta*)|*max* - *min*|
|среднее (*avg*)|среднее значение f(t) (сейчас <= t <= сейчас + `время`) в соответствии с [определением](https://ru.wikipedia.org/wiki/Среднее_значение_функции)|

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

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

Для того, чтобы избежать вычислений с большими числами, мы рассматриваем штамп времени первого значения в указанном периоде плюс 1 наносекунда как новую точку отсчёта времени (текущие штампы времени порядка 10^9^, в квадрате уже 10^18^, а точность дробных значений около 10^-16^). 1 наносекунда прибавляется для того, чтобы все значения времени были положительными, поскольку построение логарифмической (*logarithmic*) и степенной (*power*) аппроксимаций подразумевает вычисление log(t). Этот сдвиг времени не влияет на линейную (*linear*), полиномиальную (*polynomial*) и экспоненциальную (*exponential*) функции (за исключением более легких и более точных вычислений), но изменяет форму логарифмической (*logarithmic*) и степенной (*power*) функций.

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

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

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

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

::: 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})
