Русский
Русский
English
Статистика
Реклама

Monitoring

Эшелонированная защита. Fortinet amp Flowmon Networks

18.08.2020 10:04:18 | Автор: admin


В последнее время все больше компаний дозревают до эшелонированной защиты, когда одно решение защищает периметр сети, другое оконечные станции, третье постоянно мониторит сеть, обнаруживая аномалии, четвертое сканирует сеть на предмет незакрытых уязвимостей и так далее. Одновременно с этим возрастает потребность в различных интеграциях и хорошо, когда они из коробки, то есть писать сложные скрипты не нужно.
Мы не так давно писали о новой услуге TS Solution CheckFlow. Это бесплатный аудит сетевого трафика (как внутреннего, так и внешнего). Flowmon решение по анализу телеметрии и мониторингу сети, которое дает ценную информацию как для сетевых администраторов, так и для безопасников: аномалии, сканирования, нелегитимные сервера, петли, нелегитимные взаимодействия, вторжения в сеть, атаки нулевого дня и многое другое.
Также рекомендую обратиться к статье 9 типовых проблем в сети, которые можно обнаружить с помощью анализа с Flowmon.

Интеграция Flowmon & FortiGate


Интеграция была упомянута в нашем блоге. В общем и целом она заключается в том, что Next-Generation Firewall (такой, как FortiGate) защищает периметр, а Flowmon мониторит сетевую инфраструктуру, тем самым заказчик получает полную видимость сети. Однако Flowmon позволяет лишь обнаруживать, но не предотвращать атаки и аномалии, ведь он работает на телеметрии, которая добывается с помощью Netflow/IPFIX. Для вноса в карантин подозрительного или зараженного хоста может использоваться NGFW или же NAC (Network Access Control) решение.
Так вот, вендор Flowmon выпустил shell скрипт, который в ответ на инциденты безопасности может выполнить следующие действия на FortiGate:

  • Заблокировать зараженный хост по IP адресу (IP Ban);
  • Внести в хост карантин с помощью FortiClient по MAC адресу (Quarantine with FortiClient);
  • Динамический карантин на все зараженные хосты по МАС адресам (Access Layer Quarantine);

Настройка


1. В подробности самого скрипта я вдаваться не буду, скажу лишь, что есть две версии: одна для FortiGate выше версии 6.4.0, другая для более ранних версий. Код приведен ниже.

Код скрипта для FortiGate ниже версии 6.4.0
#!/bin/bash# Author: Jiri Knapek# Description: This script is to quarantine IP on Fortigate Firewalls for FortiOS before 6.4.# Version: 1.3# Date: 8/3/2020# Debug 1 = yes, 0 = noDEBUG=0[ $DEBUG -ne 0 ] && echo `date` "Starting mitigation script" >> /tmp/fg-mitigation.log# Management IP/hostname of Firewall/ Core deviceIP='10.10.30.210'API_KEY='fp8114zdNpjp8Qf8zN4Hdp57dhgjjf'# Default timeout for action is# value in seconds or neverTIMEOUT='300'# FortiGate API URLBAN="http://personeltest.ru/aways/$IP/api/v2/monitor/user/banned/add_users?access_token=$API_KEY"function usage {    cat << EOF >&2usage: mitigation_script.sh <options>Optional:    --fw        IP / hostname of Fortigate firewall--timeoutTimeout in seconds--keyFortiGate API key    EOF    exit}      params="$(getopt -o f:t:k:h -l fw:,timeout:,key:,help --name "mitigation_script.sh" -- "$@")"[ $DEBUG -ne 0 ] && echo `date` "Params $params" >> /tmp/fg-mitigation.logif [ $? -ne 0 ]then    usage    [ $DEBUG -ne 0 ] && echo `date` "Got to usage." >> /tmp/fg-mitigation.logfieval set -- "$params"unset paramswhile truedo    case $1 in        -f|--fw)            IP=("${2-}")            shift 2            ;;        -k|--key)            API_KEY=("${2-}")            shift 2            ;;        -t|--timeout)            TIMEOUT=("${2-}")            shift 2            ;;        -h|--help)            usage            ;;        --)            shift            break            ;;        *)            usage            ;;    esacdone# we dont support any other args[ $# -gt 0 ] && {    usage    [ $DEBUG -ne 0 ] &&  echo `date`  "INFO: Too many arguments. Got to usage." >> /tmp/fg-mitigation.log 2>&1}cat << EOF >&2-----  My params are ------------------FW = $IPAPI KEY = $API_KEYTIMEOUT = $TIMEOUTTOKEN = $TOKEN---------------------------------------EOF[ $DEBUG -ne 0 ] && cat >> /tmp/fg-mitigation.log << EOF >&2-----  My params are ------------------FW = $IPAPI KEY = $API_KEYTIMEOUT = $TIMEOUTTOKEN = $TOKEN---------------------------------------EOFecho "Stdin read started..." >&2LINE_NUM=1array=()while read linedo    IFS=$'\t'    array=($line)    echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}"    [ $DEBUG -ne 0 ] &&  echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" >> /tmp/fg-mitigation.log 2>&1        LINE_NUM=$((LINE_NUM+1))    # BAN the source IP of the event    if [ $DEBUG -ne 0 ]; then        /usr/bin/curl -k -X POST -H "Content-Type": "application/json" --data "{ \"ip_addresses\": [\"${array[10]}\"], \"expiry\": $TIMEOUT}" $BAN >> /tmp/fg-mitigation.log 2>&1    else        /usr/bin/curl -k -X POST -H "Content-Type": "application/json" --data "{ \"ip_addresses\": [\"${array[10]}\"], \"expiry\": $TIMEOUT}" $BAN    fidone < /dev/stdinecho "---- Everything completed ----"[ $DEBUG -ne 0 ] &&  echo `date` "---- Everything completed ----" >> /tmp/fg-mitigation.log

Код скрипта для FortiGate версии 6.4.0 и выше
#!/bin/bash# Author: Jiri Knapek# Description: This script is to quarantine IP or MAC on Fortigate Firewalls and Security Fabric# Version: 2.0# Date: 7/8/2020# Debug 1 = yes, 0 = noDEBUG=0[ $DEBUG -ne 0 ] && echo `date` "Starting mitigation script" >> /tmp/fg-mitigation.log# Flowmon API accessUSER='admin'PASS='admin'# Management IP/hostname of Firewall/ Core deviceIP='10.10.30.210'WEBHOOK='FlowmonADS'API_KEY='fp8114zdNpjp8Qf8zN4Hdp57dhgjjf'MAC=0URL="http://personeltest.ru/aways/$IP/api/v2/monitor/system/automation-stitch/webhook/$WEBHOOK"function usage {    cat << EOF >&2usage: mitigation_script.sh <options>Optional:    --fw        IP / hostname of Fortigate firewall    --user      Username to be used for Flowmon API authentication    --pass      Password for the user--keyFortiGate API key--mac    Add this parameter to enable MAC mitigationEOF    exit}params="$(getopt -o f:u:p:k:h:m: -l fw:,key:,pass:,user:,help,mac: --name "mitigation_script.sh" -- "$@")"[ $DEBUG -ne 0 ] && echo `date` "Params $params" >> /tmp/fg-mitigation.logif [ $? -ne 0 ]then    usage    [ $DEBUG -ne 0 ] && echo `date` "Got to usage." >> /tmp/fg-mitigation.logfieval set -- "$params"unset paramswhile truedo    case $1 in        -f|--fw)            IP=("${2-}")            shift 2            ;;        -k|--key)            API_KEY=("${2-}")            shift 2            ;;        -p|--pass)            PASS=("${2-}")            shift 2            ;;        -u|--user)            USER=("${2-}")            shift 2            ;;        -m|--mac)            MAC=1            shift 2            ;;        -h|--help)            usage            ;;        --)            shift            break            ;;        *)            usage            ;;    esacdone# we dont support any other args[ $# -gt 0 ] && {    usage    [ $DEBUG -ne 0 ] &&  echo `date`  "INFO: Got to usage." >> /tmp/fg-mitigation.log 2>&1}if [ $MAC -ne 0 ];then    # authenticate to localhost    OUTPUT="$(/usr/bin/curl "https://localhost/resources/oauth/token" -k -d 'grant_type=password' -d 'client_id=invea-tech' -d "username=$USER" -d "password=$PASS")"    TOKEN=""    echo "${OUTPUT}" > /tmp/access_token.json    if [[ $OUTPUT == *"access_token"* ]]; then        [ $DEBUG -ne 0 ] && echo `date` "Successfully authenticated to Flowmon Collector!" >> /tmp/fg-mitigation.log        TOKEN="$(cat /tmp/access_token.json | jq '.access_token')"        TOKEN="${TOKEN//\"}"        TOKEN="Authorization: bearer "$TOKEN    fificat << EOF >&2-----  My params are ------------------FW = $IPAPI KEE = $API_KEYURL = $URLMAC = $MACTOKEN = $TOKEN---------------------------------------EOF[ $DEBUG -ne 0 ] && /tmp/fg-mitigation.log << EOF >&2-----  My params are ------------------FW = $IPAPI KEE = $API_KEYURL = $URLMAC = $MACTOKEN = $TOKEN---------------------------------------EOFecho "Stdin read started..." >&2LINE_NUM=1array=()while read linedo    IFS=$'\t'    array=($line)    echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}"    [ $DEBUG -ne 0 ] &&  echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" >> /tmp/fg-mitigation.log 2>&1    # Call a webhook    if [ $MAC -ne 0 ];    then        MAC_ADDR="$(/usr/bin/curl "https://localhost/rest/ads/event/${array[0]}" -G -k -H "$TOKEN"  | jq '.macAddress')"        if [ $DEBUG -ne 0 ]; then            /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ \"srcip\": \"${array[10]}\", \"mac\": $MAC_ADDR, \"fctuid\": \"A8BA0B12DA694E47BA4ADF24F8358E2F\"}" $URL >> /tmp/fg-mitigation.log 2>&1        else            /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ \"srcip\": \"${array[10]}\", \"mac\": $MAC_ADDR, \"fctuid\": \"A8BA0B12DA694E47BA4ADF24F8358E2F\"}" $URL        fi    else        if [ $DEBUG -ne 0 ]; then            /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ \"srcip\": \"${array[10]}\",  \"fctuid\": \"A8BA0B12DA694E47BA4ADF24F8358E2F\"}" $URL >> /tmp/fg-mitigation.log 2>&1        else            /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ \"srcip\": \"${array[10]}\",  \"fctuid\": \"A8BA0B12DA694E47BA4ADF24F8358E2F\"}" $URL        fi    fi    LINE_NUM=$((LINE_NUM+1))done < /dev/stdinecho "---- Everything completed ----"[ $DEBUG -ne 0 ] &&  echo `date` "---- Everything completed ----" >> /tmp/fg-mitigation.log


2. Я использую ForiGate версии 6.4.3. В самом скрипте в 13 и 14 строке следует добавить ваши логин и пароль к Flowmon, а также добавить API ключ из п.5, IP-адрес FortiGate и имя Webhook (имя механизма автоматизации).



3. В веб-интерфейсе FortiGate следует добавить во вкладке Security Fabric > Automation > New Automation Stitch. Имя FlowmonADS, Status Enabled, Trigger Incoming Webhook, Action IP BAN, Access Layer Quarantine, Quarantine with FortiCLient (если используете).



4. Затем вы увидите окно как на скриншоте ниже с URLом FortiGate для данного Webhooka, поле для API токена админа (мы его создадим позже) и пример запроса.



5. Далее следует создать профиль администратора, который будет иметь права. Вкладка System > Admin Profiles > Create New.



6. Назначить права Security Fabric Read, Firewall Read/Write, System Read/Write, Security Profile Read/Write.



7. После во вкладке System > Administrators создаем нового администратора с профилем api_admin. Дополнительно в поле Trusted Hosts можно указать доверенные сети или IP-адрес устройства Flowmon.
Примечание: параметр Trusted Hosts позволяет жестко задать сегменты IP адресов, из которых api_admin сможет отправлять API запросы на FortiGate, тем самым это рекомендуемая настройка.



8. После этого шага генерируется API ключ, который надо добавить в первоначальный скрипт вместе с другими данными, указанными в пункте 1 и в webhook в пункте 4.



9. Далее переходим во Flowmon в модуль ADS (Anomaly Detection System) во вкладку System > System Settings > Custom Scripts > New Custom Script > Выбрать файл с расширение .sh. Далее следует задать параметры --fw (IP-адрес FortiGate), --key (API токен), --mac (ничего), --pass (пароль от REST API Flowmon), --user (пользователь REST API Flowmon). После следует нажать кнопку Save.
Примечание: --pass и --user по умолчанию admin / admin.



10. Финальным шагом является установление событий, на которые данные программный код и будет срабатывать. Во вкладке Settings > Processing > Custom Scripts > New Custom Script Action следует поменять параметр Perspective на Security Issues, установить порог срабатывания (Minimal priority to be reported) и проверить параметры из прошлого шага.



Проверка


В случае срабатывания события из категории Security Issues на Flowmon, FortiGate заблокирует данный хост. Далее в удобном виджете Quarantine можно посмотреть потенциально зараженные хосты, провалившись внутрь. Либо же через команду в CLI diagnose user quarantine list.



После ИБ администратор может приступить к расследованию инцидента с помощью Flowmon ADS, установив первоначально зараженный хост, по каким портам распространяется зловред и его поведение. С помощью же решений по защите рабочих станций, например, FortiEDR можно вылечить машину и провести расследование инцидента безопасности.
Для того, чтобы вынести хост из карантина, его следует выбрать и нажать кнопку Remove.

Заключение


Повсеместный подход к эшелонированной защите подталкивает многих вендоров на интеграцию с другими решениями из коробки. В данной статье были рассмотрены интеграция, настройка и демонстрация совместной работы Flowmon и FortiGate.
В ближайшее время у нас планируется вебинар, на котором более подробно расскажем, как Flowmon и Fortinet дополняют друг друга, их интеграцию между собой, а также ответим на интересующие вас вопросы. Регистрация доступна по ссылке.
Если вам интересна данная тематика, то следите за обновлениями в наших каналах (Telegram, Facebook, VK, TS Solution Blog)!
Подробнее..

IT Service Health Monitoring средствами R. Взгляд под иным углом

23.03.2021 00:21:32 | Автор: admin

Казалось бы тема давно исхоженная, пик инновационности OSS систем давно позади. Однако иногда бывают локальные жаркие всплески и бурные споры на эту тему. Можно ходить по торной вендорской дороге, а можно попробовать погрызть эту задачку с другого угла.


Ключевые слова: cmdb, multi-agent sumulation, monte-carlo, ml.


Является продолжением серии предыдущих публикаций.


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


Постановку детально расписывать не будем, в интернете можно найти на любой вкус и кошелек. Реферативно выглядит следующим образом (изначально придумали ITSM консультанты):


  • есть CMDB (конфигурационная база элементов ИТ). Она содержит описание элементов и связей между ними (граф);
  • есть система мониторинга, которая как-то снимает показания физических воплощений CI элементов;
  • есть какой-то бизнес-сервис, который базируется на инфраструктурных элементах (сервера, приложения, API, тесты, ...);
  • связь между сервисом и элементами обычно описывается деревом и называется ресурсно-сервисной моделью (РСМ);
  • у инфраструктурных элементов есть свои параметры (KPI) по которым с учетом топологической связности надо посчитать здоровье бизнес-сервиса (health/KQI).

Типовую картинку РСМ возьмем с документации одного из апологетов этой темы (HP).


РСМ. Исходник был здесь:https://docs.microfocus.com/OMi/10.62/Content/OMi/images/ServiceHealth.png


Как делается обычно


Типовая процедура внедрения РСМ состоит из:


  • составления списка сервисов;
  • составления списка ресурсов;
  • составления топологической связи между ресурсами;
  • составления правил пропагандирования состояний и метрик.

Все делается консультантами вручную. Особо интересная работа подгонять весовые коэффициенты пропагандирования метрик (событий) с нижних уровней на верхнии. В случае сложных РСМ редко удается пронаблюдать получение удовлетворительного решения.


Технические ссылки:



Альтернативный план


Ручное исполнение задача в 2021 году выглядит уныло и тоскливо. Но у нас под руками есть компьютер. Можно попробовать применить его по назначению.


План


  • фаза multi-agent sumulation: рассматриваем ресурсы как самостоятельных агентов, обладающих свойствами (входные параметры) и коммуницирующих друг с другом (связи в дереве РСМ);
  • фаза itsm: прописываем любым удобным нам способом поведение на уровне отдельных агентов (функцию выхода от состояний входа);
  • фаза monte-carlo: генерим подходящее подмножество входных состояний всех объектов и проводим расчет отклика MAS структуры;
  • фаза ml: сворачиваем полученный data.frame ансамбль правил (rule fit, см Modern Rule-Based Models by Max Kuhn), объясняемый представителям от бизнеса;
  • фаза prod: полученные ml матрицы загоняем в кремний и получаем event propagation в режиме реального времени на одном смартфоне.

При чем тут R?


В целом, альтернативный план можно делать на чем угодно. Хоть на листочках с карандашом в руке. Но если хочется сэкономить силы и время, то на R можно сделать добрую половину задачи кодом в один экран. И поможет нам в этом Shiny. Да, Shiny, но без Shiny.


Писать multi-agent simulation нудно и есть масса мест для ошибок. С другой стороны у нас есть механизм реактивного программирования в Shiny, который обеспечивает коммуникацию между объектами. Воспользуемся им, см. подсказки в Reactive programming in R by Joe Cheng, DSC 2014


Пример идеи в коде, связка трех нод-агентов nodeA -> nodeB -> nodeC.


MAS на коленке
library(tidyverse)library(magrittr)library(shiny)library(foreach)library(iterators)options(shiny.suppressMissingContextError=TRUE)makeReactiveBinding("nodeA")nodeA$in_1 <- NULLnodeA$in_2 <- NULLnodeA$out <- reactive(nodeA %$% (in_1 + in_2))makeReactiveBinding("nodeB")nodeB$in_1 <- reactive(nodeA$out())nodeB$in_2 <- NULLnodeB$out <- reactive(nodeB %$% (in_1() + in_2))makeReactiveBinding("nodeC")nodeC$in_1 <- reactive(nodeB$out())nodeC$in_2 <- NULLnodeC$out <- reactive(nodeC %$% (in_1() * in_2))df <- tidyr::expand_grid(val1 = 0:5, val2 = 0:5, val3 = 0:5, val4 = 0:5) %>%  # результат прямого расчета для демо-сверки  mutate(direct_res = (val1 + val2 + val3) * val4)res <- foreach(it = iter(df, by = "row"), .combine = "c") %do%  {    nodeA$in_1 <- it$val1    nodeA$in_2 <- it$val2    nodeB$in_2 <- it$val3    nodeC$in_2 <- it$val4    shiny:::flushReact()    nodeC$out()  }df$mas_res <- res

Далее натянуть на data.frame ансамбль деревьев (или gbm или еще что...) и сделать прогноз можно двумя строчками. При этом формулу отклика для каждого агента можно писать любыми доступными средствами. В силу того, что состояния агентов в этой задаче ограничены, можно вместо формул создать конфигурационный excel (пример ниже), который понятен любому менеджеру и не требует никаких споров. Считаете, что в строчке #7 на выходе должно быть 'bad'? Пишем и даже не спорим.


Конфигурация агента для менеджеров


Собственно все, задача решена, кино кончилось.


Предыдущая публикация Немного о параллельных вычислениях в R.

Подробнее..

Безотказный Zabbix миграция с асинхронной на групповую репликацию

16.05.2021 22:09:51 | Автор: admin

Введение

Zabbix поддерживает несколько баз данных, но под рассмотрение попали только MySQL и PostgreSQL, как наиболее подходящие под мою установку. PostgreSQL с его repomgr и pgbouncer или каким-нибудь stolon с одной стороны и MySQL Group Replication с другой. Из-за использования MySQL в текущей конфигурации и тяге к стандартной комплектации, выбор пал на второй вариант.

Так что же такое MySQL Group Replication. Как видно из названия, это группа серверов, хранящая одинаковый набор данных. Максимальное количество узлов в группе ограничивается 9-ю. Может работать в режиме single-primary или multi-primary. Но самое интересное всё работает автоматически, будь то выборы нового ведущего сервера, определение поломанного узла, Split-brain или восстановление БД. Поставляется данный функционал в качестве плагинов group_replication и mysql_clone, связь происходит по Group Communication System протоколу в основе которого лежит алгоритм Паксос. Поддерживается данный тип репликации с версий 5.7.17 и 8.0.1.

Моя текущая установка работает на Zabbix 5.0 LTS и MySQL 5.7, миграцию будем проводить с повышением версии MySQL на 8.0, так интереснее ).

Мониторинг репликации

Да да. Это как TDD, только в администрировании, сначала нужно подготовить мониторинг, чтобы новый кластер сразу попал на радары нашей системы мониторинга и не одна проблема не ускользнула от её зоркого взгляда. Так как у вас еще нет групповой репликации (ГР), то вывод команд указанных ниже будет пустым, поэтому я привожу пример выводов с работающего кластера.

Основным источником информации о статусе узлов служит команда:

SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+| CHANNEL_NAME              | MEMBER_ID                           | MEMBER_HOST  | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+| group_replication_applier | 500049c2-99b7-11e9-8d36-e4434b5f9d0c | example1.com |      3306   | ONLINE       | SECONDARY   | 8.0.13         || group_replication_applier | 50024be2-9889-11eb-83da-e4434ba03de0 | example2.com |      3306   | ONLINE       | PRIMARY     | 8.0.13         || group_replication_applier | 500b2035-986e-11eb-a9f8-564d00018ad1 | example3.com |      3306   | ONLINE       | SECONDARY   | 8.0.13         |+---------------------------+--------------------------------------+--------------+-------------+--------------+-------------+----------------+

Значение колонки MEMBER_STATE может быть разное. Статусы можно посмотреть на странице официальной документации https://dev.mysql.com/doc/refman/8.0/en/group-replication-server-states.html. Если сервер к примеру корректно перезагружен или выключен, он исчезнет из этой таблицы, поэтому желательно знать общее количество узлов в вашей схеме и следить за их количеством.

Дополнительно нужно следить за производительностью каждого узла:

SELECT * FROM performance_schema.replication_group_member_stats\G
*************************** 1. row ***************************                              CHANNEL_NAME: group_replication_applier                                   VIEW_ID: 16178860996821458:41                                 MEMBER_ID: 500049c2-99b7-11e9-8d36-e4434b5f9d0c               COUNT_TRANSACTIONS_IN_QUEUE: 0                COUNT_TRANSACTIONS_CHECKED: 75715997                  COUNT_CONFLICTS_DETECTED: 0        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1957048        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 500049c2-99b7-11e9-8d36-e4434b5f9d0c:1-1821470279,500293cf-594c-11ea-aafd-e4434ba03de0:1-622868371,5000d25c-059e-11e8-822b-564d00018ad1:1-140221041,c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:1-125382195            LAST_CONFLICT_FREE_TRANSACTION: c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:125471159COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0         COUNT_TRANSACTIONS_REMOTE_APPLIED: 5664         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 75710337         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0*************************** 2. row ***************************                              CHANNEL_NAME: group_replication_applier                                   VIEW_ID: 16178860996821458:41                                 MEMBER_ID: 50024be2-9889-11eb-83da-e4434ba03de0               COUNT_TRANSACTIONS_IN_QUEUE: 0                COUNT_TRANSACTIONS_CHECKED: 75720452                  COUNT_CONFLICTS_DETECTED: 0        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1955202        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 500049c2-99b7-11e9-8d36-e4434b5f9d0c:1-1821470279,500293cf-594c-11ea-aafd-e4434ba03de0:1-622868371,5000d25c-059e-11e8-822b-564d00018ad1:1-140221041,c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:1-125377993            LAST_CONFLICT_FREE_TRANSACTION: c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:125470919COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0         COUNT_TRANSACTIONS_REMOTE_APPLIED: 75711354         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 9105         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0*************************** 3. row ***************************                              CHANNEL_NAME: group_replication_applier                                   VIEW_ID: 16178860996821458:41                                 MEMBER_ID: 500b2035-986e-11eb-a9f8-564d00018ad1               COUNT_TRANSACTIONS_IN_QUEUE: 38727                COUNT_TRANSACTIONS_CHECKED: 49955241                  COUNT_CONFLICTS_DETECTED: 0        COUNT_TRANSACTIONS_ROWS_VALIDATING: 1250063        TRANSACTIONS_COMMITTED_ALL_MEMBERS: 500049c2-99b7-11e9-8d36-e4434b5f9d0c:1-1821470279,500293cf-594c-11ea-aafd-e4434ba03de0:1-622868371,5000d25c-059e-11e8-822b-564d00018ad1:1-140221041,c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:1-125382195            LAST_CONFLICT_FREE_TRANSACTION: c9aae4fb-97a6-11eb-89d1-e4434b5f9d0c:125430975COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 47096         COUNT_TRANSACTIONS_REMOTE_APPLIED: 49908155         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 03 rows in set (0.00 sec)

Тут нас интересуют в первую очередь COUNT_TRANSACTIONS_IN_QUEUE, похож на Seconds_Behind_Master в асинхронной репликации. Как видно на третьем сервере количество транзакций в очереди слишком большое, а это повод начать разбираться что же здесь не так.

Резервное копирование

Я надеюсь, у вас делается регулярное резервное копирование базы данных (БД) и конечно на специально выделенный сервер. Так же желательно убедиться перед миграцией, что на всех узлах с БД есть запас по месту, превышающий в два с половиной раза размер каталога с базой. Это нам понадобится для создания локальной резервной копии, на случай если что-то пойдёт не так, и позволит нам вернуть всё как было. Если у вас файловая система с поддержкой моментальных снимков, не в чём себе не отказывайте, но свободного места должно быть много, так как в самые тяжёлые таблицы будет добавлен дополнительный столбец, а это повлечёт за собой их пересоздание.

План миграции

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

Если всё идёт гладко:

  1. Пропиливаем необходимые дырки в файрволле (для общения узлов между собой нужно открыть TCP 33061 порт). Выписываем необходимые сертификаты;

  2. Собираем репозиторий с MySQL 8.0 (FreeBSD, Poudriere - у каждого свои причуды);

  3. В системе мониторинга переводим серверы в режим обслуживания, уведомляем всех пользователей Zabbix (чтобы никто не удивлялся);

  4. Выключаем репликацию на всех узлах, которые были Secondary для этого сервера (мы же не хотим, чтобы какие-нибудь наши изменения улетели на действующие сервера). Выключаем репликацию на текущем узле;

  5. Выключаем MySQL 5.7 сервер на первом подопытном узле;

  6. Делаем резервное копирование БД с сохранением атрибутов файлов (сохраняем рядом, чтобы быстро восстановить базу);

  7. Обновляем пакеты на новую версию с новыми зависимостями;

  8. Запускаем MySQL 8.0 сервер (mysql_upgrade не нужен, с 8 версии это действо происходит автоматически);

  9. Добавляем первичные ключи в таблицы, в которых их нет (требования групповой репликации, иначе операции добавления, удаления и т. д. работать не будут). Операция длительная, зависит от размера таблиц и производительности сервера;

  10. Включаем репликацию на этом сервере, отреплецируем все изменения, выключаем репликацию (подтянем изменённые данные с действующего сервера, накопившееся за время наших манипуляций);

  11. Сбрасываем все упоминания об асинхронной репликации на данном сервере (команда RESET SLAVE ALL;);

  12. Настраиваем групповую репликацию и проверяем всё ли работает;

  13. Переключаем Zabbix сервер и Zabbix фронтенд на БД с ГР;

  14. Настраиваем групповую репликацию на других узлах (делаем шаги с 4 по 8, только с удалением каталога с БД перед 8 шагом, т. к. нам нужна чистая установка);

  15. Перенастраиваем мониторинг;

  16. Переделываем Ansible Playbook'и и конфигурационные файлы;

  17. Меняем скрипты и задачи по переключению мастера;

  18. Настраиваем HADNS;

  19. Обновляем документацию;

На непредвиденный случай:

  1. Останавливаем MySQL сервер;

  2. Возвращаем предыдущие версии пакетов;

  3. Удаляем каталог с БД и восстанавливаем из локальной резервной копии, запускаем MySQL сервер;

  4. Настраиваем асинхронную репликацию;

Откатываемся бесконечное количество раз, пока всё не пройдёт гладко.

Далее подробно рассмотрим 9, 12 и 14 шаги.

Шаг 9: Добавление первичных ключей

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

Отсутствие первичных ключей можно выяснить запросом взятым вот отсюда.

SELECT tables.table_schema , tables.table_name , tables.engine FROM information_schema.tables LEFT JOIN ( SELECT table_schema , table_name FROM information_schema.statistics GROUP BY table_schema, table_name, index_name HAVING SUM( case when non_unique = 0 and nullable != 'YES' then 1 else 0 end ) = count(*) ) puksON tables.table_schema = puks.table_schema and tables.table_name = puks.table_nameWHERE puks.table_name is null AND tables.table_type = 'BASE TABLE' AND Engine="InnoDB";

Какой тип ключей и для каких колонок его создать я подсмотрел на форуме Zabbix, вот тут. Чтобы не поломалось обновление Zabbix, в таблице dbversion добавляем первичный ключ по существующему столбцу. Ниже необходимые запросы.

ALTER TABLE history ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;ALTER TABLE history_uint ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;ALTER TABLE history_text ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;ALTER TABLE history_str ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;ALTER TABLE history_log ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;ALTER TABLE dbversion ADD PRIMARY KEY (mandatory);

Напоминаю действие занимает большое количество времени на больших таблицах. Надеюсь, когда-нибудь это внесут в схему БД для Zabbix.

Шаг 12: Запуск групповой репликации

Все настройки, относящиеся к групповой репликации, я собрал в одном месте в конфигурационном файле.

server-id=[номер сервера в кластере по порядку]gtid_mode=ONenforce_gtid_consistency=ONlog_bin=binloglog_slave_updates=ONbinlog_format=ROWmaster_info_repository=TABLErelay_log_info_repository=TABLEtransaction_write_set_extraction=XXHASH64disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"plugin_load_add='group_replication.so;mysql_clone.so'ssl-ca=/usr/local/etc/ssl/mysql/ca.crtssl-cert=/usr/local/etc/ssl/mysql/server.crtssl-key=/usr/local/etc/ssl/mysql/server.keygroup_replication_ssl_mode=VERIFY_IDENTITYgroup_replication_group_name="[одинаковое на всех узлах, генерируем один раз командой SELECT UUID();]"group_replication_start_on_boot=off # включаем после добавления всех узлов в группуgroup_replication_local_address="[полное имя текущего сервера].com:33061"group_replication_group_seeds="example1.com:33061,example2.com:33061,example3.com:33061"group_replication_ip_allowlist="2.2.2.2/32,3.3.3.3/32,4.4.4.4/32"group_replication_member_weight=50group_replication_recovery_use_ssl=ONgroup_replication_recovery_ssl_verify_server_cert=ONgroup_replication_recovery_ssl_ca=/usr/local/etc/ssl/mysql/ca.crtgroup_replication_recovery_ssl_cert=/usr/local/etc/ssl/mysql/server.crtgroup_replication_recovery_ssl_key=/usr/local/etc/ssl/mysql/server.key

Добавляем это всё в my.cnf, дубликаты переменных, которые встречаются в файле до этого, необходимо удалить. Теперь можно перезапустить сервер, либо проверить значение переменных как написано ниже и поменять их вручную. Обратите внимание на переменную group_replication_start_on_boot, она выключена, поэтому при рестарте репликация не запустится.

Проверяем значение переменных командой SHOW VARIABLES LIKE 'binlog_format'; меняем с помощью команды SET GLOBAL binlog_format = RAW; это относится к переменным в верхней части конфига, остальные настройки подтянутся при активации групповой репликации.

Переменные group_replication_ssl_mode и group_replication_recovery_ssl_verify_server_cert установлены в максимально безопасный режим с проверкой сертификата сервера, так что при выписывании сертификата укажите в Subject Alternative Name (SAN) полные имена всех улов кластера, которые есть в group_replication_group_seeds.

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

Создаём пользователя для работы репликации:

SET SQL_LOG_BIN=0;CREATE USER 'replication'@'%' IDENTIFIED BY '[придумайте пароль]' REQUIRE SSL;GRANT replication slave ON *.* TO 'replication'@'%';GRANT BACKUP_ADMIN ON *.* TO 'replication'@'%';FLUSH PRIVILEGES;SET SQL_LOG_BIN=1;

Устанавливаем плагины и проверяем статус:

INSTALL PLUGIN group_replication SONAME 'group_replication.so';INSTALL PLUGIN clone SONAME 'mysql_clone.so';SHOW PLUGINS;

Настраиваем пользователя, используемого при восстановлении БД с работающего сервера:

CHANGE REPLICATION SOURCE TO SOURCE_USER='replication', SOURCE_PASSWORD='[придуманный пароль]' \\  FOR CHANNEL 'group_replication_recovery';

Первый запуск группы. Переменную group_replication_bootstrap_group включаем только на первом сервере, на остальных, просто запускаем групповую репликацию:

SET GLOBAL group_replication_bootstrap_group=ON; # выполняем только на первом сервереSTART GROUP_REPLICATION;SET GLOBAL group_replication_bootstrap_group=OFF; # выполняем только на первом сервере

Если никаких ошибок команда не вернула, то можно посмотреть информацию о вновь созданной группе:

mysql> SELECT * FROM performance_schema.replication_group_members;+---------------------------+--------------------------------------+-------------+-------------+---------------+| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE  |+---------------------------+--------------------------------------+-------------+-------------+---------------+| group_replication_applier | ce9be252-2b71-11e6-b8f4-00212844f856 |example1.com |       3306  | ONLINE        |+---------------------------+--------------------------------------+-------------+-------------+---------------+

Проверьте дополнительно логи MySQL сервера на содержание в них ошибок.

Шаг 14: Добавление узла в группу

После того как вы переключили Zabbix сервер и фронтенд на сервер с ГР, можно добавить оставшиеся узлы в кластер. Для этого выключаем MySQL сервер, делаем локальную копию, обновляем пакеты и удаляем текущий каталог с БД.

Запускаем чистую базу данных и проделываем всё тоже самое как в 12-ом шаге, с добавлением специфичных для этого сервера настроек (server-id, group_replication_local_address). Так как группа уже запущена, использовать переменную group_replication_bootstrap_group не нужно.

На этом этапе и будет использоваться так называемый Distributed Recovery механизм в который входит mysql_clone плагин. При подключении к узлу донору в первую очередь он попытается использовать бинарный лог, если информации в нём будет недостаточно, он полностью скопирует базу, включая созданного для репликации пользователя.

Проверьте статус группы и что сервер добавился в неё, а так же его производительность, успевает ли узел применять все транзакции.

После добавления оставшихся серверов, поменяйте в конфиге my.cnf значения переменной group_replication_start_on_boot с off на on и перезагрузите MySQL сервер на любом ведомом сервере и проверьте что он остался в группе.

Полезные команды

SELECT * FROM performance_schema.replication_group_members; - показывает статус всех узлов в группе.

SELECT * FROM performance_schema.replication_group_member_stats\G - показывает производительность каждого отдельного узла.

SELECT group_replication_set_as_primary('[uuid узла]'); - переключение ведущего узла.

Безотказный Zabbix сервер

А что же с Zabbix сервером спросите вы, если дочитаете до этого момента, а всё просто. Я сделал так чтобы он постоянно следовал за ведущим сервером групповой репликации. В кроне на каждом сервере запускается скрипт, который проверяет что узел сейчас Primary в ГП, если да, то запускает Zabbix сервер, если нет, то останавливает его. Дальше включается в работу HADNS, он проверяет на каком сервере запущен Zabbix и отдает нужный IP адрес для DNS записи.

Заключение

Возможно, сделано не всё так элегантно как хотелось бы. Вы наверно захотите использовать mysql-shell, mysqlrouter и преобразовать Group Replication в InnoDB Cluster, а может добавить HAProxy, особенно это полезно, когда разворачиваешь Zabbix с нуля. Надеюсь, этот рассказ послужит неплохой отправной точкой и будет полезен. Спасибо за внимание!

Дополнительная литература

https://dev.mysql.com/doc/refman/8.0/en/group-replication.html

https://blog.zabbix.com/scaling-zabbix-with-mysql-innodb-cluster/8472/

https://en.wikipedia.org/wiki/Paxos_(computer_science)

Подробнее..

Мониторинг 95 метрик PostgreSQL с помощью плагина Zabbix Agent 2

24.05.2021 20:06:11 | Автор: admin

В прошлом году популярный сервис мониторинга Zabbix представил Agent 2, призванный сократить число TCP-подключений и обеспечить удобную расширяемость за счёт плагинов на Golang.

Меня зовут Даша, и я один из разработчиков плагина мониторинга PostgreSQL для Zabbix Agent 2. В этой статье я расскажу об основных фишках использования Zabbix Agent 2 для мониторинга PostgreSQL, о принципе работы плагина, дам советы по его настройке, а также объясню на примере, как кастомизировать плагин.

Как появился плагин мониторинга PostgreSQL для Zabbix Agent 2?

В 2019 году Zabbix анонсировал выпуск нового Zabbix Agent 2. Он написан с нуля на Golang. Для мониторинга каждого приложения требуется отдельный плагин. Мы в Postgres Professional решили, что это отличная возможность применить наш многолетний опыт использования Zabbix для мониторинга PostgeSQL, и написали модуль мониторинга для Agent 2.

Как устроен мониторинг СУБД в Zabbix?

Начнём с небольшого введения в схему работы мониторинга Zabbix для новичков.

Интересную нам сейчас структуру можно разбить на две составляющие:

  1. Zabbix Server, который хранит и собирает данные.

  2. Агенты, которые устанавливаются на наблюдаемых объектах и собирают данные.

Для мониторинга каждого приложения в Zabbix Server требуется шаблон - XML-файл. В нём указаны ключи метрик (уникальные ID) и параметры их обработки.

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

Как же работает PostgreSQL плагин для Zabbix Agent 2?

Есть основная функция, в которой по уникальному ключу вызываются обработчики для каждой метрики. Обработчик (handler) служит для сбора данных. Это файл, в котором указывается и выполняется SQL-запрос для получения одной или нескольких метрик. Результаты выполнения запроса записываются в переменную, которая относится к типу int, float или string. Если результат должен содержать значения сразу нескольких метрик, то он будет преобразован в JSON ещё на стадии получения запроса. Полученные результаты Zabbix Agent 2 периодически отдаёт Zabbix Server.

Плагин и обработчики находятся вот в этой папке: /plugins/postgres

Какими возможностями обладает модуль мониторинга PostgreSQL для Zabbix Agent 2?

  • Поддержка постоянного подключения к PostgreSQL.

  • Мониторинг нескольких экземпляров (instances) PostgreSQL одновременно.

  • Опции контроля и проверки метрик в реальном времени через командную строку.

  • Конфигурирование плагина через общий файл конфигурации агента.

  • Сохранение состояния между проверками.

  • Довольно простая кастомизация сбора существующих метрик.

  • Возможность писать новые плагины под свои требования.

К плагину есть официальный шаблон, который можно скачать по ссылке.

В нем есть базовые триггеры и комплексный экран, на котором отображается комбинация нескольких графиков. Всего плагин собирает более 95 метрик. Полный список всех метрик также можно найти по ссылке выше.

В веб-интерфейсе Zabbix Server можно редактировать шаблон и его составляющие для своих нужд. Что именно можно настроить?

  1. Изменить интервал сбора метрики.

  2. Добавить триггер для метрики.

  3. Добавить макрос или отредактировать существующий.

Как установить и использовать PostgreSQL-плагин для Zabbix Agent 2?

1. Создаем пользователя PostgreSQL для мониторинга:

CREATE USER 'zbx_monitor' IDENTIFIED BY '<password>';GRANT EXECUTE ON FUNCTION pg_catalog.pg_ls_dir(text) TO zbx_monitor;GRANT EXECUTE ON FUNCTION pg_catalog.pg_stat_file(text) TO zbx_monitor;

2. Редактируем pg_hba.conf, чтобы разрешить подключение от Zabbix Agent 2:

# TYPE DATABASE USER ADDRESS METHOD
host all zbx_monitor 127.0.0.1 md5

Больше информации о pg_hba.conf по ссылке.

Теперь остаётся задать параметры подключения к PostgreSQL для Zabbix Agent 2. Это можно сделать двумя способами:

  • использовать макросы для параметров подключения,

  • создать сессию.

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

1. В шаблоне редактируем макрос {$PG.URI} , в котором указывается путь к PostgreSQL в формате <protocol(host:port)>.

2. Задаем макрос с именем пользователя и паролем ({$PG.USER} and {$PG.PASSWORD}). Так же можно указать макрос {$PG.DBNAME}. Этот параметр опционален для большинства метрик - если он не задан в ключе, то будет использовано имя базы, указанное в конфигурационном файле агента.

В шаблоне эти макросы уже указаны в параметрах всех ключей. Обратите внимание, что порядок указания параметров в ключе фиксирован.

Второй способ позволяет задавать параметры подключения к нескольким экземплярам PostgreSQL:

  1. Задаём параметры подключения для сессии в конфигурационном файле zabbix_agent2.conf в секции плагина Postgres: Postgres.Sessions.<Session_name>.URI,Postgres.Sessions.<Session_name>.User,Postgres.Sessions.<Session_name>.Password. Здесь вместо <Session_name> нужно указать уникальное имя новой сессии.

  2. Создаём макрос с именем сессии в шаблоне {$PG.<Session_name>}.

  3. Указываем макрос как единственный параметр для метрик в шаблоне.

Рассмотрим, как использовать плагин для сбора дополнительных метрик на примере добавления метрики uptime.

Для этого надо создать новый обработчик с запросом и добавить его ключ в основную функцию.

1. Создаем файл для получения новой метрики:

zabbix/src/go/plugins/postgres/handler_uptime.go

Подключаем пакет postgres и указываем ключ (ключи) метрик:

package postgresconst (keyPostgresUptime = "pgsql.uptime")

2. Объявляем обработчик (handler) c запросом, а так же переменную uptime, куда будет записан результат:

func uptimeHandler(ctx context.Context, conn PostgresClient,                    _ string, _ map[string]string, _ ...string) (interface{}, error){var uptime float64query := `SELECT date_part('epoch', now() - pg_postmaster_start_time());

3.Выполняем запрос, проверяем, возникла ли ошибка. Если все ОК, возвращаем переменную uptime с результатом.

row, err := conn.QueryRow(ctx, query)if err != nil {...}err = row.Scan(&uptime)if err != nil {...}return uptime, nil

4. Регистрируем ключ новой метрики:

var metrics = metric.MetricSet{....,keyPostgresUptime: metric.New("Returns uptime.",[]*metric.Param{paramURI, paramUsername, paramPassword,paramDatabase}, false),}

Собираем агент!

Новый функционал

В версии Zabbix 5.2 появилась возможность вычислять метрики, собирая результаты пользовательских запросо из отдельных SQL-файлов. При этом можно создавать даже динамические запросы. В этой версии также обновлена архитектура модуля и исправлены мелкие ошибки.Продемонстрируем, как добавлять кастомные метрики через SQL - файл на примере простого запроса с одним параметром:

  1. Создадим SQL-файл с запросом.

    $touch custom1.sql$echo SELECT id FROM my_table WHERE id=$1; > custom1.sql
    

    Тут в $1 будет передан параметр при выполнении запроса.

  2. В zabbix_agent2.conf заполним параметр Plugins.Postgres.CustomQueriesPath, указав путь к директории с SQL-файлом.

    Plugins.Postgres.CustomQueriesPath=/path/to/the/file

  3. В шаблоне для ключа pgsql.query.custom укажем имя SQL-файла и добавим дополнительные параметры для запроса, т.е. тот, который заменит $1. Стоит отметить, что для названия SQL - файла и для параметров можно также создавать макросы в шаблоне.

Дополнительные материалы

Презентации Zabbix Online Meetup, который проходил 19 июня

Статья Вадима Ипатова - одного из разработчиков Zabbix Agent 2

Шаблон для плагина мониторинга PostgreSQL

Zabbix Git для тех, кто хочет видеть больше реальных примеров и посмотреть на все SQL-запросы для получения метрик

Видео доклада на PGConf.Online 2021 "Обзор новой функциональности и настройка Zabbix Agent 2 для мониторинга PostgreSQL"

Остались вопросы?

Все вопросы можно задавать в комментариях.

Подробнее..

Управление наружным освещением

24.03.2021 00:15:52 | Автор: admin

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

Модернизация предполагала максимальное использование существующей инженерной и IT инфраструктуры. Требовалось воздержаться от монтажа нового или замены старого оборудования, свести к минимуму перечень используемого ПО. Принципы, применяемые в системе управления, должны быть универсальными и пригодными для повторного использования. Должна быть обеспечена возможность легкого расширения системы. Осветительные установки, вводимые в эксплуатацию, могут быть смонтированы в разных районах города, в разных регионах или странах.

Разбираемся с инфраструктурой

На практике мне встречалось несколько подходов к управлению наружным освещением: регламентированное включение и отключение силами оперативного персонала, применение реле времени, сумеречных датчиков, фотореле и астрономических реле.

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

По похожей схеме работает и модернизируемая нами система. В роли астрономического реле выступает свободно программируемый логический контроллер (ПЛК). По линии RS485 ПЛК управляет проприетарными модулями ввода-вывода, которые установлены в разных зданиях. Управление и настройка системы осуществляется с использованием SCADA и OPC-сервера, установленного на одной из машин в сети Ethernet, к которой подключен ПЛК. Все используемое ПО является проприетарным.

Выявленные недостатки и их причины

В ходе эксплуатации осветительных установок стало понятно, что система управления требует постоянного внимания персонала. По большому счету все сводилось к тому, что становилось очевидно: подсветка зданий включается слишком поздно, а отключается слишком рано. Эта проблема решалась корректировкой коэффициентов в системе диспетчеризации. Путем ручного подбора коэффициентов удавалось достигнуть времени включения и отключения, соответствующего городскому графику. Коэффициенты оставались неизменными до следующей подобной ситуации. А повторялись такие ситуации довольно часто.

Было сделано предположение, что причина проблемы кроется в проекте, загруженном в ПЛК. Ознакомиться с исходниками проекта не представлялось возможным. Из текстового описания проекта стало понятно, что для определения времени включения/отключения освещения используется функциональный блок, доступный в проприетарной среде программирования. Используя триальную версию этой среды, удалось получить доступ к справке и более подробному описанию этого блока. Это внесло некоторую ясность: функциональный блок высчитывает время, когда угол (высота) Солнца над горизонтом для заданного географического положения станет равен 0. Коэффициенты корректируют этот угол. Например, при коэффициенте "-6" будет высчитано время, когда Солнце окажется ниже горизонта на 6. Но в ходе проведенных экспериментов сложилось мнение, что функциональный блок производит расчеты не совсем так, как это предполагается. Дальнейшие работы в этом направлении были прекращены ввиду отсутствия универсальности такой реализации.

Начинаем модернизацию

При рассмотрении существующих вариантов, я склонялся к варианту управления по расписанию. Не секрет, что существуют общедоступные графики отключения наружного освещения. Для Москвы и Санкт-Петербурга, например - МОССВЕТ и ЛЕНСВЕТ. Обладая этой информацией несложно написать скрипт, который следит за временем и по графику управляет освещением. Тем более, что в сети Ethernet, к которой подключен ПЛК, имеется Linux-машина.

Для того чтобы такой скрипт мог управлять удаленными модулями ввода-вывода, потребовалось заново создать проект для ПЛК. По-сути ПЛК стал выступать в роли шлюза, что предоставило нам возможность управлять освещением по открытому протоколу Modbus TCP.

Для работы с Modbus будем использовать утилиту modpoll. Скачаем и распакуем ее на нашей Linux машине:

$ wget https://www.modbusdriver.com/downloads/modpoll.tgz$ tar xzf modpoll.tgz$ sudo cp modpoll/linux_x86-64/modpoll /usr/local/bin/

Теперь управлять освещением будем следующим образом:

#Включить освещение$ modpoll -m tcp -r 2 -t 0 -a 1 -p 502 192.168.0.227 1 1 1 1 1 1 1 1 #Отключить освещение$ modpoll -m tcp -r 2 -t 0 -a 1 -p 502 192.168.0.227 0 0 0 0 0 0 0 0 

Дело осталось за малым - вызывать эти команды по заранее сформированному расписанию. Как было упомянуто выше, подобные графики доступны и мы можем ими воспользоваться. Но появилось желание найти более универсальный подход, поэтому давайте вспомним о таком явлении, как "сумерки".

Сумерки

В сутках существуют периоды, называемые сумерки. Это время перед восходом Солнца и после заката, когда небо частично освещено рассеянным солнечным светом. Выделяют три вида сумерек: гражданские, навигационные и астрономические. Гражданские сумерки определяются как период, когда угол нахождения Солнца под горизонтом составляет от 050 до 6, навигационные сумерки от 6 до 12, а астрономические сумерки от 12 до 18.

Наибольший интерес для нас представляют навигационные сумерки. Именно в этот период освещение становится ближе к ночному, чем к вечернему, поэтому улицы городов нуждаются в искусственном освещении. Проще говоря, наружное освещение включается с началом навигационных сумерек (Солнце опускается ниже -6 ) и отключается с их окончанием (Солнце поднимается выше -6 ). Конечно стоит понимать, что в зависимости от погодных условий и в условиях городской застройки, включение может потребоваться раньше, чем Солнце опустится ниже -6 за горизонт.

Еще немного об астрономических реле.

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

Если управлять освещением, опираясь именно на фактическое положение Солнца, то такая проблема отсутствует.

Подробный и крайне наглядный рассказ о движении Солнца был найден на Youtube - Как солнце ходит по небу / How the sun moves across the sky (by daybit).

Положение Солнца и наружное освещение

Итак, для решения нашей задачи мы будем синхронизировать работу наружного освещения с положением Солнца. При наступлении навигационных сумерек - включение освещения, в момент начала гражданских - отключение. Так как в нашем распоряжении имеется Linux машина и соответственно Perl, то для расчета положения Солнца воспользуемся им. Загрузим необходимый нам модуль:

$ sudo cpan install Astro::Coord::ECI

Создадим скрипт get_sun_elevation.pl, вычисляющий угол Солнца относительно горизонта.

#!/usr/bin/perl# Вычисление высоты Солнца над горизонтом в градусах в текущий момент# get_sun_elevation.pl 55.7558 37.6173 127# 55.7558 - широта в градусах# 37.6173 - долгота в градусах# 127 - высота над уровнем моря в метрахuse Astro::Coord::ECI::Sun;use Astro::Coord::ECI::Utils qw{:all};my ($lat, $lon, $elev) = (deg2rad($ARGV[0]), deg2rad($ARGV[1]), $ARGV[2]/1000);my $time = time ();my $loc = Astro::Coord::ECI->geodetic ($lat, $lon, $elev);my $sun = Astro::Coord::ECI::Sun->universal ($time);my ($azimuth, $elevation, $range) = $loc->azel ($sun);print rad2deg ($elevation), "\n";

Скрипт moscow_lights_ctrl.sh будет сравнивать заданное положение Солнца и его текущее положение в Москве. Если Солнце окажется ниже заданного угла, то отправим команду на включение, иначе - команду на отключение освещения:

#!/bin/sh[ -z "$1" ] && angle=-6 || angle=$1sun_angle=`./sun_pos.pl 55.751244 37.618423 124`if [ $(echo "$sun_angle >= $angle" |bc -l) -eq "0" ]; then  modpoll -m tcp -r 2 -t 0 -a 1 -p 502 192.168.0.227 1 1 1 1 1 1 1 1  exit 0fimodpoll -m tcp -r 2 -t 0 -a 1 -p 502 192.168.0.227 0 0 0 0 0 0 0 0

Опытным путем было определено, что на модернизируемом объекте потребность в наружном освещении возникает, когда Солнце опускается ниже -1.5. К слову, также было замечено, что городское освещение включается примерно в это же время.

С помощью cron будем выполнять moscow_lights_ctrl.sh каждую минуту:

# Если Солнце ниже 1.5 градусов - включение освещения, иначе - отключение* * * * * root /path/to/moscow_lights_ctrl.sh -1.5

Нам ничего не мешает создавать такие скрипты для любого географического положения. А когда возникнет необходимость расширения системы, мы сможем применить любое оборудование. Лично я склоняюсь к использованию модулей ввода-вывода, поддерживающих протокол Modbus TCP.

По большому счету все поставленные цели достигнуты. Модернизацию можно считать успешно завершенной.

ZABBIX

В ходе работ появились некоторые планы на ближайшее будущее, а именно настройка мониторинга работы оборудования. Возможности такого мониторинга сильно зависят от степени готовности самих инженерных систем. Например, мы можем следить за положением силового контактора и контролировать включение освещения. Или получать значение силы тока и тем самым определять, сколько ламп вышло из строя и т.д. К сожалению, на текущий момент к полноценному мониторингу модернизируемая система не готова. Тем не менее, для задела на будущее было решено использовать уже существующую на предприятии систему мониторинга - ZABBIX.

Все принципы работы остаются неизменными. Мы лишь перенесем всю описанную выше логику управления в ZABBIX.

Шаблон для ZABBIX

Создадим шаблон astro_outdoor_lighting для Zabbix со следующими макросами:

  • {$CIVIL_DEGREES} - Окончание и начало гражданских сумерек в градусах. Включение и отключение наружного освещения,

  • {$ELEV} - Высота над уровнем моря в метрах,

  • {$LAT} - Широта в градусах,

  • {$LON} - Долгота в градусах.

Элементы данных

Шаблон содержит только один элемент данных - elevation. Этот элемент следит за положением солнца в заданном географическом положении.

Чтобы получать текущее положение Солнца, элемент осуществляет внешнюю проверку через ранее созданный скрипт get_sun_elevation.pl.

/usr/lib/zabbix/externalscripts/get_sun_elevation.pl
#!/usr/bin/perl# Вычисление высоты Солнца над горизонтом в градусах в текущий момент# get_sun_elevation.pl 55.7558 37.6173 127# 55.7558 - широта в градусах# 37.6173 - долгота в градусах# 127 - высота над уровнем моря в метрахuse Astro::Coord::ECI::Sun;use Astro::Coord::ECI::Utils qw{:all};my ($lat, $lon, $elev) = (deg2rad($ARGV[0]), deg2rad($ARGV[1]), $ARGV[2]/1000);my $time = time ();my $loc = Astro::Coord::ECI->geodetic ($lat, $lon, $elev);my $sun = Astro::Coord::ECI::Sun->universal ($time);my ($azimuth, $elevation, $range) = $loc->azel ($sun);print rad2deg ($elevation), "\n";

Подробности настройки внешних проверок в ZABBIX смотрите в документации.

Триггеры

Единственный триггер civil_twilight_dawn срабатывает по окончании гражданских сумерек, т. е. в момент, когда возникает необходимость в работе наружного освещения.

Шаблон созданного макроса доступен на github.

Добавляем узел сети

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

Скрипты и действия ZABBIX

В разделе [Администрирование]->[Скрипты] создадим глобальные скрипты с говорящими названиями facade light off и facade light on.

Когда триггер civil_twilight_dawn переходит в состояние "Проблема", нам необходимо включить наружное освещение, т.е. выполнить скрипт facade light on. После восстановления триггера освещение необходимо отключить, для чего потребуется вызвать скрипт facade light off. Поэтому в разделе [Настройки]->[Действия] мы создадим действие facade light, реализующее необходимое нам поведение системы.

Подобным же образом добавляем скрипты и действия для каждого узла сети.

На этом настройку ZABBIX сервера для управления установками наружного освещения можно считать завершенной.

Заключение

После модернизации прошло несколько месяцев. За это время работа наружного освещения не вызывала каких-либо нареканий.

Как мне видится, даже в простейшем варианте (работа по cron) такой подход перекрывает потребности большинства подобных типовых задач в крупных коммерческих и административных зданиях. В плане экономической конкурентоспособности он тоже выглядит вполне достойно. Когда на объекте требуется более одного астрономического реле, реле времени и т. п., то их стоимость может быть вполне ощутимой. Кроме этого, чаще всего эти элементы управления разнесены по разным частям зданий и добиться их синхронной работы - не такая простая задача, как это может показаться.

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

Конечно, все вышесказанное актуально при наличии какой-никакой IT инфраструктуры. Но, как правило, она имеется.

На этом все. Спасибо за внимание!

Подробнее..

Как я мониторил РИП-12 от Bolid

28.04.2021 02:24:00 | Автор: admin

Резервированные источники питания используются повсеместно. Они обеспечивают бесперебойным электропитанием приборы охранной и пожарной сигнализации, оборудование систем контроля доступа и другие системы. На нашем предприятии в качестве таких источников, как правило, используются приборы от ЗАО НВП Болид. У некоторых из них, как, например, у РИП-12-6/80M3-R-RS, имеется интерфейс RS485, что позволяет включать их в систему мониторинга.

Средства мониторинга

Мы используем Zabbix 5.2. Получать данные от РИП будем по протоколу Modbus RTU over TCP. Поддержка этого протокола реализована в Zabbix с помощью загружаемого модуля libzbxmodbus. Также в процессе мониторинга принимают участие преобразователь протокола C2000-ПП (вер. 1,32) в режиме Master и преобразователь последовательных интерфейсов (RS485 в Ethernet).

Объекты мониторинга

Для начала определимся, что конкретно мы сможем контролировать. Из документации к РИП-12-6/80M3-R-RS и С2000-ПП выяснилось, что рассчитывать мы можем на получение состояния семи зон (ШС) и числовых значений тока и напряжения. В ходе экспериментов мне удалось воспроизвести следующие состояния ШС:

ШС 0 Состояние прибора

149

Взлом корпуса прибора

Корпус РИП открыт

152

Восстановление корпуса прибора

Корпус РИП закрыт

250

Потеряна связь с прибором

Потеряна связь с прибором

ШС 1 Выходное напряжение

193

Подключение выходного напряжения

РИП подключил выходное напряжение при появлении напряжения в сети

192

Отключение выходного напряжения

РИП отключил выходное напряжение при отсутствии напряжения в сети и разряде батареи

199

Восстановление питания

Напряжение питания прибора пришло в норму

250

Потеряна связь с прибором

Потеряна связь с прибором

ШС 2 Ток нагрузки

194

Перегрузка источника питания

Выходной ток РИП более 7,5 А

195

Перегрузка источника питания устранена

Выходной ток РИП менее 7,5 А

250

Потеряна связь с прибором

Потеряна связь с прибором

ШС 3 и ШС 4 Напряжение на батарее 1 и 2 соответственно

200

Восстановление батареи

Напряжение батареи выше 10 В, заряд батареи возможен

202

Неисправность батареи

Напряжение на батарее ниже 7 В или не подключена

211

Батарея разряжена

Напряжение на батарее ниже 11 В при отсутствии сетевого напряжения

250

Потеряна связь с прибором

Потеряна связь с прибором

ШС 5 Степень заряда батарей

196

Неисправность зарядного устройства

ЗУ не обеспечивает напряжение и ток для заряда батареи в заданных пределах

197

Восстановление зарядного устройства

ЗУ обеспечивает напряжение и ток для заряда батареи в заданных пределах

250

Потеряна связь с прибором

Потеряна связь с прибором

ШС 6 Напряжение сети

1

Восстановление сети 220

Сетевое напряжение питания < 150 В или > 250 В

2

Авария сети 220 В

Сетевое напряжение питания в пределах 150250 В

250

Потеряна связь с прибором

Потеряна связь с прибором

Крайне вероятно, что мной была получена только часть из всех возможных состояний. Например, имеются догадки, что ШС 3 и 4 должны также иметь состояние [204] Необходимо обслуживание, а ШС 0 - состояние [203] Сброс прибора и другие. К сожалению, чтение документации ситуацию не прояснило. В связи с этим нам необходимо следить и реагировать на появление событий, которые мы не предусмотрели.

Конфигурирование устройств

Не будем долго останавливаться на процессе конфигурирования приборов, только коротко рассмотрим перечень необходимых действий. Настройка устройств Болид осуществляется при помощи утилиты UProg и имеет следующий порядок:

  1. Назначение сетевых адресов всем устройствам (РИП и С2000-ПП),

  2. Конфигурирование интерфейса интеграции С2000-ПП (Modbus RTU),

  3. Добавление ШС, описанных выше, в таблицу зон С2000-ПП. Крайне важно, чтобы, во-первых, были добавлены все ШС, а во-вторых, ШС должны следовать друг за другом в порядке возрастания.

UProg. Конфигурация С2000-ППUProg. Конфигурация С2000-ПП

При заполнении таблицы зон следует помнить следующее:

  • адрес прибора - сетевой адрес РИП, в нашем случае 126,

  • номер ШС - номер ШС от 0 до 6,

  • тип зоны - тип ШС, для ШС 0 назначаем тип зоны "3 - состояние прибора", для всех остальных - "8-РИП напряжение / ток".

Создаем шаблоны Zabbix

Напомню, что Zabbix с модулем libzbxmodbus выступает в роли Modbus-мастера. Из-за особенностей получения данных от C2000-ПП, о которых речь пойдет в процессе создания шаблонов, мы будем рассматривать два подхода к мониторингу.

  • мониторинг состояния ШС.

  • мониторинг как состояния, так и числовых параметров РИП.

Мониторинг состояния ШС

Итак, создадим шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS. Шаблон имеет один элемент данных с именем Request и типом "Простая проверка". Ключом элемента является функция: modbus_read[{$MODBUS_PORT},{$MODBUS_SLAVE},{$STATUS_REG},3,7*uint16] . В параметрах функции используются значения макросов, которые позволяют составить корректный modbus запрос к C2000-ПП.

  • {MODBUS_PORT} - тип используемого протокола (enc - Modbus RTU over TCP), адрес и порт преобразователя последовательных интерфейсов.

  • {MODBUS_SLAVE} - Modbus UID С2000-ПП (настраивается в UProg на вкладке прибор).

  • {STATUS_REG} - адрес регистра в котором расположен ШС 0 интересующего нас РИПа. Получить данный адрес можно следующим образом: "Номер зоны в таблице зон С2000-ПП" + 40000 - 1. В нашем примере это: 450+40000-1 = 40449.

Основная задача элемента Request - запросить у С2000-ПП значение всех семи ШС контролируемого РИП и предоставить их в формате JSON. Результирующий JSON содержит объекты, ключами которых являются адресы регистров С2000-ПП, а значениями - содержимое этих регистров:

{  "40449":39115,  "40450":51195,  "40451":50171,  "40452":51963,  "40453":51451,  "40454":50683,  "40455":763}

Зависимые элементы данных

Элемент данных Request имеет 7 зависимых элементов. Основная задача этих элементов - распарсить JSON и получить состояние каждого ШС индивидуально. Вот эти элементы:

  • Status - состояние прибора (ШС 0),

  • Uout - выходное напряжение (ШС 1),

  • Iout - ток нагрузки (ШС 2),

  • Ubat1 - напряжение АКБ1 (ШС 3),

  • Ubat2 - напряжение АКБ2 (ШС 4),

  • Capacity - степень заряда АКБ (ШС 5),

  • Uin - напряжение сети (ШС 6).

Предобработка зависимых элементов данных

Чтобы получить состояние ШС 0 (Status), нам достаточно два шага предобработки. На первом шаге мы воспользуемся стандартным функционалом JSONPath, а затем разделим полученное значение на 256, тем самым получим код состояния.

К сожалению, мне не удалось использовать математические операции в параметрах JSONPath. Поэтому для оставшихся элементов данных пришлось использовать javascritpt-предобработку. Например, для элемента данных Iout (ШС 2) javascript-предобработка выглядит так:

function (value){    var reg = parseInt({$STATUS_REG})+2;    var data = JSON.parse(value);    return data[reg];}

Триггеры

После добавления триггеров создание шаблона можно считать завершенным. Перечень созданных триггеров:

  1. Взлом корпуса прибора,

  2. Перегрузка источника питания,

  3. Отключение выходного напряжения,

  4. Неисправность батареи АКБ1,

  5. Неисправность батареи АКБ2,

  6. АКБ1 разряжен,

  7. АКБ2 разряжен,

  8. Авария сети 220 В,

  9. Потеряна связь с прибором,

  10. Неизвестное состояние Status,

  11. Неизвестное состояние Iout,

  12. Неизвестное состояние Uout,

  13. Неизвестное состояние АКБ1,

  14. Неизвестное состояние АКБ2,

  15. Неизвестное состояние Capacity,

  16. Неизвестное состояние Uin,

  17. Превышено время отсутствия по MODBUS.

Демонстрация и импорт RIP 12 mod 56 RIP 12 6 80 M3 R RS

Шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS в картинкахШаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS в картинкахПример создания узла сетиПример создания узла сети

Ссылки для импорта: Шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS, Преобразование значений RIP 12 mod 56 RIP 12 6 80 M3 R RS.

Мониторинг состояния и числовых параметров

Мониторинг числовых параметров имеет свои особенности. Все дело в том, что для получения числового значения нам необходимо сделать два modbus-запроса к С2000-ПП. Первый запрос устанавливает зону для запроса тока или напряжения, второй - непосредственное получение значения. В таком случае мы не имеем возможности использовать функционал libzbxmodbus, т.к. попросту не cможем гарантировать правильную очередность запросов.

Первое и самое простое, что приходит на ум, - это создать скрипт, который сделает получение числового параметра атомарной операцией и воспользоваться возможностями внешних проверок Zabbix. Но такой скрипт тоже не позволит использовать загружаемый модуль libzbxmodbus по причине невозможности организации монопольного доступа к разделяемому ресурсу, в нашем случае к преобразователю последовательных интерфейсов.

В связи с вышесказанным, для этих целей было решено отказаться от использования libzbxmodbus и написать скрипт, который сможет предоставлять и числовые параметры РИП и состояния его ШС.

Пишем shell скрипт для внешней проверки

Для того, чтобы синхронизировать доступ к преобразователю последовательных интерфейсов, воспользуемся утилитой flock. Работу с Modbus будем осуществлять при помощи modpoll. В /usr/lib/zabbix/externalscripts создадим скрипт rip_12_mod_56.sh

#!/bin/bash# rip_12_mod_56.sh# $1 - protocol://host:port# $2 - Modbus UID# $3 - Status register# $4 - Offset (0 - 6)# Example of requesting statuses:       ./rip_12_mod_56.sh enc://127.0.0.1:4001 1 40000# Example value request:                ./rip_12_mod_56.sh enc://127.0.0.1:4001 1 40000 3(($# < 3)) && { printf '%s\n' "You have given little data. Command exited with non-zero"; exit 1; }lockfile=$(echo "$1" | awk -F "://" '{print $2}')setzone(){        modpoll -m $1 -a $4 -r 46181 -0 -1 -c 1 -p $3 $2 $5> /dev/null 2>&1    (($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }    sleep 0.15}getvalue (){        value=$(modpoll -m $1 -a $4 -r 46328 -0 -1 -c 1 -t 4:hex -p $3 $2 |grep ]: |awk '{print $2}')        printf "%d" $value}getstatus (){        status=$(modpoll -m $1 -a $4 -r $5 -1 -c 7 -t 4:hex -p $3 $2 | grep ]: | awk -F "0x" 'BEGIN { printf"["} NR!=7{printf "\""$2"\","} NR==7 {printf "\""$2"\""} END { printf "]"}')    echo "{ \"status\": $status }"}(        flock -e 200        protocol=$(echo $1 | awk -F "://" '{print $1}');        host=$(echo $1 | awk -F "://" '{print $2}' | awk -F ":" '{print $1}')        port=$(echo $1 | awk -F "://" '{print $2}' | awk -F ":" '{print $2}')        register=$(($3+1))        if (($# >= 4)); then                zone=$(($register+$4-40000))                setzone $protocol $host $port $2 $zone                echo $(getvalue $protocol $host $port $2)                sleep 0.15                exit 0        fi        echo $(getstatus $protocol $host $port $2 $register)        sleep 0.15;) 200> /tmp/$lockfile

Подробности настройки внешних проверок в Zabbix уточняйте в документации.

Создаем RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED

Для получения информации о состоянии ШС шаблон содержит элемент данных Request с типом "Внешняя проверка". Ключом элемента является скрипт: rip_12_mod_56.sh[{$MODBUS_PORT}, {$MODBUS_SLAVE}, {$STATUS_REG}]. Как и в шаблоне RIP 12 mod 56 RIP 12 6 80 M3 R RS, задача элемента Request - сформировать JSON с состояниями всех ШС.

Возвращаемый JSON оптимизирован для использования функционала JSONPath. Для упрощения скрипта значения возвращаются в шестнадцатеричной форме:

{  "status": ["98CB","C7FB","C3FB","CAFB","C8FB","C5FB","02FB"]}

Состояния ШС. Снова зависимые элементы данных.

Как и в предыдущем шаблоне, элемент данных Request имеет 7 зависимых элементов. Задача этих элементов тоже неизменна - распарсить JSON и получить состояние каждого ШС.

Получаем числовые значения

Для получения числовых значений создадим 5 элементов данных с типом "Внешняя проверка".

  • Uout_value - значение выходного напряжения, В.

  • Iout_value - значение выходного тока, А.

  • Ubat1_value - значение напряжения на батарее 1, В.

  • Ubat2_value - значение напряжения на батарее 2, В.

  • Uin_value -значение напряжения сети, В.

Ключом этих элементов является скрипт: rip_12_mod_56.sh[{$MODBUS_PORT}, {$MODBUS_SLAVE}, {$STATUS_REG}, <НОМЕР ШС>].

Триггеры

Перечень триггеров не отличается от триггеров, созданных в шаблоне RIP 12 mod 56 RIP 12 6 80 M3 R RS.

Демонстрация и импорт RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED

Шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED в картинкахШаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED в картинкахПоследние значения RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDEDПоследние значения RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED

Ссылки для импорта: Шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS EXTENDED, rip_12_mod_56.sh.

Вместо заключения

В своем мониторинге мы используем шаблон RIP 12 mod 56 RIP 12 6 80 M3 R RS. По-большому счету причина такого решения одна - расширяемость системы. Использование загружаемого модуля позволяет включать в одну линию приборы разных типов и модификаций, организовать их мониторинг стандартными средствами. Кроме этого, большой потребности в получении числовых значений у нас пока не возникало.

Однако, несмотря на все вышесказанное, возможность получения числовых значений тоже может оказаться востребованной. В этом случае можно задуматься об использовании в триггерах функций прогнозирования.

Спасибо за внимание!

Подробнее..

Zabbix OPC DA

25.05.2021 00:13:35 | Автор: admin

В последних релизах Zabbix "из коробки" стал поддерживать некоторые популярные протоколы промышленного оборудования. Имея поддержку Modbus и MQTT, его использование с системами промышленной автоматизации стало чуточку проще. Но подобный подход к мониторингу такого рода оборудования не всегда возможен.

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

Для чего нам Zabbix

В нашем сценарии использования Zabbix последний не является заменой имеющейся SCADA-системе. Параллельное развертывание системы мониторинга позволит иметь возможность гибкой настройки триггеров и своевременного получения оповещений о нештатных ситуациях на оборудовании. Также мы сможем создавать дополнительные информационные панели с графиками, которые смогут давать быстрое представление о ходе тех. процессов.

Взаимодействие с OPC серверами

Самой сложной задачей, которая стоит перед нами, является организация взаимодействия с OPC-серверами. В ходе поисков готового решения такого взаимодействия стало понятно, что подходящих нам вариантов не так много. Из того, что было найдено, наиболее пригодным к использованию оказался консольный клиент OpenOPC.

Установка OpenOPC

Как было сказано ранее, речь идет о стандарте OPC DA, а значит, о технологии DCOM и, соответственно, ОС Windows. В нашем случае установка OpenOPC производилась на машину с Windows XP, где и находится проприетарный OPC сервер. После завершения установки необходимо добавить путь до opc.exe в системную переменную среды PATH.

Проверим работу утилиты. Для начала выведем в консоль список доступных OPC серверов:

C:\Users\Администратор> opc.exe -qMerz.OPC_SAIA_S-BUS.1C:\Users\Администратор>

Теперь попробуем получить теги в удобном нам формате - csv:

C:\Users\Администратор>opc.exe -o csv -s Merz.OPC_SAIA_S-BUS.1 ATP.Register.OAT ATP.Register.OAT,197,Good,05/24/21 07:16:15C:\Users\Администратор>opc.exe -o csv -s Merz.OPC_SAIA_S-BUS.1 ATP.Register.OAT ATP5.Register.T_inlet ATP5.Register.T_outletATP.Register.OAT,198,Good,05/24/21 07:16:41ATP5.Register.T_inlet,627,Good,05/24/21 07:16:41ATP5.Register.T_outlet,654,Good,05/24/21 07:16:41C:\Users\Администратор>

Если что-то пошло не так

В ходе экспериментов с opc.exe выяснились некоторые моменты. Первое: каждый OPC клиент запускал новую копию OPC сервера, а их параллельная работа невозможна. Так как запустить используемый нами OPC сервер как службу не получилось, то через DCOM был настроен запуск OPC сервера от определенного пользователя. Все OPC клиенты - SCADA и агент Zabbix - были также настроены на запуск от этого пользователя. Второе: выявлены некоторые недостатки в работе самого OpenOPC. Например, клиент не вычитывает теги, в названии которых присутствуют символы, отличающиеся от латинских. С этим пока пришлось смириться и решать такие проблемы путем переименования тегов в OPC сервере.

Установка Zabbix агента

На ту же машину установим Zabbix агент, который сможет работать под Windows XP, например, zabbix_agent-5.2.0-windows-i386-openssl.msi. Агент будет выполнять активные проверки. Чтобы облегчить дальнейшую конфигурация агента, во время установки заполним следующие поля:

  • Ноst name - уникальное имя хоста, совпадающее с именем узла сети на Zabbix сервере.

  • Zabbix server IP/DNS - IP-адреса Zabbix сервера.

  • Server or Proxy for active checks - IP-адрес Zabbix сервера для активных проверок.

Конфигурирование Zabbix агента

В конфигурационный файл C:\Program Files\Zabbix Agent\zabbix_agentd.conf были внесены некоторые изменения.

  1. Увеличено время выполнения скрипта.

    ### Option: Timeout#Spend no more than Timeout seconds on processing.## Mandatory: no# Range: 1-30# Default:# Timeout=3Timeout=30
    
  2. Создан параметр для мониторинга.

    #User-defined parameter to monitor. There can be several user-defined parameters.#Format: UserParameter=<key>,<shell command>## Mandatory: no# Default:# UserParameter=UserParameter=opc[*],opc.exe -o csv -s $1 $2
    

Узел сети и элементы данных на сервере Zabbix

На Zabbix сервере создадим узел сети. Имя узла сети должно совпадать с Ноst name, указанном при установке агента, интерфейс - IP-адрес агента.

Далее к созданному узлу сети добавим элемент данных c типом Zabbix агент (активный). Ключом должна являться конструкция типа: opc[<ИМЯ OPC СЕРВЕРА>, <ЗАПРАШИВАЕМЕ ТЕГИ ЧЕРЕЗ ПРОБЕЛ>].

Значениями элемента данных будут строки, разделенные запятыми:

ATP2.Register.OAT,273,Good,05/24/21 15:21:33ATP2.Register.GVS.T_inlet_W,501,Good,05/24/21 15:21:33ATP2.Register.GVS.T_outlet_W,445,Good,05/24/21 15:21:33ATP2.Register.T_outlet_w_com,404,Good,05/24/21 15:21:33ATP2.Register.RAD.T_outlet_W,256,Good,05/24/21 15:21:33ATP2.Register.P_in_W_com,39,Good,05/24/21 15:21:33ATP2.Register.P_out_W_com,36,Good,05/24/21 15:21:33ATP2.Register.RAD.P_outlet_W,43,Good,05/24/21 15:21:33ATP2.Register.FIRE.P_gidrant,68,Good,05/24/21 15:21:33

Зависимые элементы данных

Создадим зависимые элементы данных для того, чтобы распарсить CVS, полученный в самом элементе.

В предобработке используем JavaScript, который получит необходимую нам строку в CVS, проверит качество тега и вернет результат.

function (value){    var nr_line = 4;    var lines = value.split('\n');    var fields = lines[nr_line].split(',');    if(typeof fields[2] != "undefined" &&  fields[2] == "Good"){    return (typeof fields[1] != "undefined") ? fields[1] : null;    }    return null;}

Пример визуализации полученных данных:

Заключение

Теперь, когда данные от оборудования находятся в Zabbix, можно приступить к дальнейшей организации мониторинга: создание и обработка разнообразных триггеров, генерация графиков, отчетов и т. д.

Подробнее..

Перевод New Relic меняет бизнес-модель открывает код агентов и инструментария

08.08.2020 00:06:58 | Автор: admin


Поставщик платформы мониторинга New Relic меняет большую часть своей бизнес-модели, открывая исходный код ряда агентов в каталоге продуктов. В процессе, который руководство описало, как адаптацию к коренным изменениям по отношению к Open Source, компания начала открывать на GitHub исходный код своих агентов, а также инструментария интеграции с общедоступными облачными сервисами и прочими проектами.


Компания все же продолжит продавать свою платформу-как-сервис New Relic One, а агенты, интеграции, SDK, инструменты CLI и свои пользовательские визуализации будут предлагаться компанией в каталоге New Relic One. Открыт код агентов C, Go, .NET, Node, Python и Ruby. По словам компании в сентябре будет доступен код агента на Java, а в октябре PHP.


Все эти агенты открыты, сказал директор по продукту The New Stack Bill Staples, сыгравший важную роль в освоении ПО с открытым исходным кодом в Microsoft и его применении в Azure.


Он же: Мы принимаем участие в работе сообщества и публикуем наши дальнейшие шаги. Мы на 100% являемся приверженцами философии открытого исходного кода.



Одновременно New Relic предоставит код и финансирование для продвижения стандарта OpenTelemetry от Cloud Native Computing Foundations (CNCF), надеясь помочь стандартизировать инструментарий, которого зачастую не хватает в системах управления облачной инфраструктуры.


Представители New Relic заявили, что компания будет активно участвовать и поддерживать стандарты Prometheus для инструментария, а также другие проекты телеметрии, включая Dropwizard, Kamon, Micrometer, StatsD и Telegraf, а также связанные инструменты, к примеру Grafana.


Таким образом, любая компания сможет взять открытый код New Relic и использовать его для своих целей, имея возможность вносить изменения в проект. По условиям лицензии можно будет использовать библиотеки агентов для своих приложений. После запуска приложения, отправляемая телеметрическая диагностическая информация по сути может быть направлена на любое число открытых или коммерческих бэкэндов, например предоставляемых New Relic, по словам Staples.


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


Согласно Clive Longbottom, аналитика Clive Longbottom and Associates, этот шаг New Relic предприняла для того, чтобы привлечь внимание клиентов, поскольку если New Relic привлечет других для создания модулей и интеграций с использованием различных SDK, то она сможет расшириться с небольшим риском для себя. Если они смогут получить хороших последователей, то это означает взрывной рост нового ПО, к примеру в областях IoT и AI, за счет сообщества открытого исходного кода, вместо того, чтобы попытаться все делать самой. В целом достаточно умный ход, если New Relic успешно монетизирует клиентскую базу.


Компания New Relic в значительной степени ответственна, как за продвижение распространения ПО с открытым исходным кодом, так и за потребность в стандартизации, особенно за стандартизацию. В мире облаков, к примеру, различия в мониторинге больше не в проприетарных инструментах, а в масштабируемости всей архитектуры платформы, сказал Torsten Volk, аналитик Enterprise Management Associates (EMA), по словам The New Stack.


Также по словам Volk: Вся суть микросервисов, основанных на Kubernetes, ориентирована на приложения, работающие везде, безо всяких ограничений. По этой причине проприетарный инструментарий для закрытых стеков приложений становится менее жизнеспособным. Компания New Relic потом сможет сосредоточиться на видоизменении своей серверной платформы, в которой действительно заключается магия, управляемая ИИ.


Опять же по его словам трудности Docker служат примером того, чего стоит избегать.


Как видно из падения компании Docker, если вы слишком долго будете держаться за проприетарные инструменты будете наказаны рынком. Так что этот шаг (от New Relic) просто отражает реалии нынешнего рынка, который будет наказывать за любое решение, препятствующее или замедляющее реализацию по настоящему масштабируемых программных платформ.


В масштабируемом рынке проприетарный инструментарий будет рассматриваться как водоросли на якоре цифровой трансформации. Torsten Volk, EMA

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


Поэтому инструментарий остается очень важным, поскольку примерно 70-80% приложений все еще не изменены и полагаются на традиционный мониторинг, по словам Volk. Он же: Открытие New Relic своего большого хранилища готовых агентов будет склонять DevOps команды к тому, чтобы они их частично попробовали, а в случае успеха они возможно будут склоняться к выбору New Relic в качестве нового поставщика платформы мониторинга. В крайнем случае этот шаг сделает New Relic крупным игроком в облачном пространстве, а не парнями, у которых слишком дорогой софт для Kubernetes.


Переход New Relic помогает доказать, что открытый исходный код модель будущего для поставщиков ПО. Один только проект OpenTelemetry вместе c поддержкой New Relic помогает увидеть, насколько такая модель применима к крупномасштабным фреймворкам приложений.


Согласно Volk: Чем больше поставщиков сосредоточатся на успехе OpenTelemetry, а не разработке проприетарных решений, тем больше вероятность того, что клиенты будут стандартизировать свои организации с использованием OpenTelemetry. Вся идея открытого исходного кода основана на убеждении, что несколько различных поставщиков работают совместно над разработкой продуктов, к примеру агентов мониторинга у клиентов будет шире выбор, а поставщики могут потратить свои ресурсы на будущие разработки собственных секретных соусов, вместо создания н-го агента для мониторинга MySQL или Red Hat Enterprise Linux.


Однако, согласно Volk, проект New Relic с открытым исходным кодом также во многих отношениях представляет собой рискованное предприятие, и возможно, его стоит рассматривать, как революционный шаг.


Для убедительности нужна революция, ведь в мире, где все больше и больше компаний предпочитают открытое ПО, вам нужно показать, что вы все делаете на ранней стадии. Все включено означает больше, чем простое совместное использование кода, поскольку такое ПО имеет шанс массового внедрения только в случае поддержки проекта несколькими поставщиками. Таким образом для New Relic имеет смысл поддержать OpenTelemetry, чтобы дальше провести видоизменение своего будущего стека. В масштабируемом рынке проприетарный инструментарий будет рассматриваться, как водоросли на якоре цифровой трансформации.

Подробнее..

Kubernetes мониторинг c помощью Prometheus

29.10.2020 14:07:14 | Автор: admin


В этои статье я постарался показать, как можно использовать Prometheus в качестве системы мониторинга для микросервиснои архитектуры. Подробно рассмотрел архитектуру Prometheus и взаимодеиствие его компонентов. Обозначил ключевые характеристики благодаря чему эта система получила такое широкое распространение в средах использующих контеинеризацию. Предупреждаю сразу: статья получилась довольно объемной. Эта статься будет полезна для начинающих DevOps специалистов, которые планируют или уже используют в своеи работе Docker, Kubernetes. Итак, начнем!



Что такое Prometheus?


Prometheus система мониторинга, разработанная специально для динамически изменяющейся среды. Кроме того, она может использоваться для традиционной инфраструктуры, например, на физических серверах с приложениями, развернутыми непосредственно на ОС. На сегодняшний день Prometheus занимает лидирующую позицию среди инструментов, применяемых в мире микросервисов. Чтобы понять, почему Prometheus пользуется такой популярностью, давайте рассмотрим несколько примеров.


В качестве среды для разворачивания системы будем использовать Kubernetes.


Цель настроить в Prometheus мониторинг для Redis-кластера в Kubernetes. Графический интерфейс Grafana. Для оповещения задействуем email и Slack.


Основные компоненты Prometheus


"

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


  • Time Series Data Base (TSDB) база данных, в которой хранятся метрики, полученные от целевых объектов. Например, CPU usage, Memory utilization или количество запросов к сервису

  • Retrieval worker отвечает за получение этих метрик с целевых ресурсов и размещение данных в TSDB

  • HTTP server API для выполнения запросов к сохраненным в TSDB данным. Используется для отображения данных на дашборде в Prometheus или сторонних системах визуализации таких, как Grafana.

От теории к практике


Давайте развернем наш сервер Prometheus с помощью пакетного менеджера Helm.



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

Для этого потребуются рабочий кластер Kubernetes и настроенный kubectl. Можно попробовать использовать кластер Kubernetes в MCS. Сервер Prometheus устанавливается достаточно просто:


#Добавляем репозиторийhelm repo add stable https://kubernetes-charts.storage.googleapis.com#Обновляемhelm repo update#Создаем namespacekubectl create namespace monitoring#Устанавливаем helm c именем my-prometheushelm install my-prometheus stable/prometheus -n monitoring

В результате выполнения мы получаем:


The Prometheus PushGateway can be accessed via port 9091 on the following DNS name from within your cluster:my-prometheus-pushgateway.monitoring.svc.cluster.localGet the PushGateway URL by running these commands in the same shell:  export POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus,component=pushgateway" -o jsonpath="{.items[0].metadata.name}")  kubectl --namespace monitoring port-forward $POD_NAME 9091For more information on running Prometheus, visit:https://prometheus.io/

Проверяем, все ли поды запущены:


kubectl get pods -n monitoringNAME                                               READY   STATUS    RESTARTS   AGEmy-prometheus-alertmanager-86986878b5-5w2vw        2/2     Running   0          76smy-prometheus-kube-state-metrics-dc694d6d7-xk85n   1/1     Running   0          76smy-prometheus-node-exporter-grgqw                  1/1     Running   0          76smy-prometheus-node-exporter-njksq                  1/1     Running   0          76smy-prometheus-node-exporter-pcmgv                  1/1     Running   0          76smy-prometheus-pushgateway-6694855f-n6xwt           1/1     Running   0          76smy-prometheus-server-77ff45bc6-shrmd               2/2     Running   0          76s

При выводе Helm chart предлагает выполнить port-forward для pushgateway, чтобы получить доступ к интерфейсу Prometheus. Меняем component на server и выполняем:


#получаем название контейнера и сохраняем его в переменную POD_NAMEexport POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}")#пробрасываем портkubectl --namespace monitoring port-forward $POD_NAME 9090

Теперь открываем http://127.0.0.1:9090/ в браузере и видим интерфейс Prometheus:



Итак, у нас есть сервер Prometheus, развернутый внутри кластера Kubernetes. Теперь давайте развернем Redis, который впоследствии и поставим на мониторинг в Prometheus. Для этого также используем Helm:


#добавляем репозиторийhelm repo add bitnami https://charts.bitnami.com/bitnami#Обновляемhelm repo update#Создаем namespacekubectl create namespace redis#Устанавливаем helm c именем redishelm install redis bitnami/redis -n redis --set cluster.enabled=true --set cluster.slaveCount=2 --set master.persistence.enabled=false --set slave.persistence.enabled=false

Параметры cluster.enabled и cluster.slaveCount определяют, что Redis будет развернут в режиме кластер, и в этом кластере два пода будут работать как slave. В параметрах указываем: не использовать persistent volume для master и slave (persistence.enabled=false). Сейчас это нужно, чтобы продемонстрировать работу Redis. В продакшене будет необходимо сделать настройку persistent volume.

Проверяем, что все поды redis запущены:


kubectl get pod -n redis NAME             READY   STATUS    RESTARTS   AGEredis-master-0   1/1     Running   0          65sredis-slave-0    1/1     Running   0          65sredis-slave-1    1/1     Running   0          28s

Теперь, когда у нас развернуты Prometheus и Redis, нужно настроить их взаимодействие.



Targets и metrics


Prometheus-сервер может мониторить самые разные объекты к примеру, Linux- и Windows-серверы. Это может быть база данных или приложение, которое предоставляет информацию о своем состоянии. Такие объекты в Prometheus называются targets. Каждый объект имеет так называемые единицы мониторинга. Для Linux-сервера это может быть текущая утилизация CPU, использование memory и диска. Для приложения количество ошибок, количество запросов и время их выполнения. Эти единицы называются metrics и хранятся в TSDB.



Exporters


Prometheus получает метрики из указанных в его конфигурации источников в блоке targets. Некоторые сервисы самостоятельно предоставляют метрики в формате Prometheus, и для их сбора не нужно ничего дополнительно настраивать. Достаточно подключить Prometheus в конфигурации, как это сделано ниже:


 scrape_configs:      job_name: prometheus       static_configs:          targets:            localhost:9090

Указываем серверу Prometheus забирать метрики из конечной точки: localhost:9090/metrics.


Для сервисов, которые не могут самостоятельно предоставлять метрики в формате Prometheus, нужно установить дополнительный компонент exporters. Обычно exporters скрипт или сервис, который получает метрики от цели, конвертирует их формат, который понимает Prometheus, и предоставляет эти данные серверу по пути /metrics. Prometheus имеет большой набор готовых exporters для разных сервисов эти компоненты можно использовать для HAProxy, Linux system, облачных платформ и др.


Redis и exporter



Давайте подключим exporter для нашего Redis-кластера. Сначала потребуется создать файл values.yaml со следующим содержанием:


cluster: enabled: true slaveCount: 2 #### Redis Master parameters##master: persistence:   enabled: false extraFlags:    "--maxmemory 256mb" slave: persistence:   enabled: false extraFlags:    "--maxmemory 256mb"  ## Prometheus Exporter / Metrics##metrics: enabled: true  image:   registry: docker.io   repository: bitnami/redis-exporter   tag: 1.4.0-debian-10-r3   pullPolicy: IfNotPresent  ## Metrics exporter pod Annotation and Labels podAnnotations:   prometheus.io/scrape: "true"   prometheus.io/port: "9121"

Здесь параметры, которые использовались в командной строке для настройки Redis в режиме cluster, перенесены в yaml-файл. Для сбора метрик добавлено подключение redis-exporter.


Обновляем Redis с новыми параметрами:


helm upgrade redis -f redis/values.yaml bitnami/redis -n redis

Проверяем, что поды Redis запущены:


kubectl get pods -n redisredis-master-0   2/2     Running   0          3m40sredis-slave-0    2/2     Running   0          2m4sredis-slave-1    2/2     Running   0          2m16s

Теперь к каждому pod привязан дополнительный контейнер redis-exporter, который предоставляет доступ к метрикам Redis.


Добавлять снятие метрик для развернутых контейнеров redis-exporter в конфигурацию Prometheus не нужно, так как он по умолчанию содержит kubernetes_sd_configs (листинг представлен ниже). За счёт этого динамически подключается сбор метрик для вновь появившихся подов. Подробнее об этом можно прочитать в документации.

   job_name: 'kubernetes-pods'       kubernetes_sd_configs:          role: pod       relabel_configs:          source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]           action: keep           regex: true          source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]           action: replace           target_label: __metrics_path__           regex: (.+)          source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]           action: replace           regex: ([^:]+)(?::\d+)?;(\d+)           replacement: $1:$2           target_label: __address__          action: labelmap           regex: __meta_kubernetes_pod_label_(.+)          source_labels: [__meta_kubernetes_namespace]           action: replace           target_label: kubernetes_namespace          source_labels: [__meta_kubernetes_pod_name]           action: replace           target_label: kubernetes_pod_name


Давайте убедимся, что мы получаем данные о состоянии Redis. Для этого можно открыть интерфейс и ввести PromQL-запрос redis_up:


"

В отличие от других систем мониторинга, Prometheus не получает данные от целевых сервисов, а самостоятельно забирает с указанных в конфигурации endpoints это одна из его важнейших характеристик. Когда вы работаете с большим количеством микросервисов, и каждый из них отправляет данные в систему мониторинга, вы можете столкнуться с риском отправки слишком большого количества данных на сервер Prometheus, а это может привести его выходу из строя. Prometheus предоставляет централизованное управление сбором метрик, т.е. вы самостоятельно решаете, откуда и как часто забирать данные. Еще одно преимущество использования Prometheus возможность динамически получать источники данных с помощью функции service discovery, работа которой была продемонстрирована выше на примере Redis-подов.


Но бывает случаи, когда необходимо получать данные от источника временно, и у Prometheus нет необходимости забирать их с сервиса постоянно (например, запланированные задания по крону, снятие бэкапов и т.д.). Для таких случаев Prometheus предлагает pushgateway, чтобы сервисы могли отправлять свои метрики в базу данных Prometheus. Использование pushgateway скорее исключение, чем правило, но о его возможности не стоит забывать.


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


Alertmanager и Alerting rules


За отправку предупреждений в Prometheus отвечает компонент AlertManager. В качестве каналов оповещения могут выступать: email, slack и другие клиенты. Для настройки оповещения необходимо обновить конфигурацию файла alertmanager.yml.


Создадим файл prometheus/values.yaml со следующим содержимым:


## alertmanager ConfigMap entries##alertmanagerFiles: alertmanager.yml:   global:     slack_api_url: <secret>    route:     receiver: slack-alert     group_by:        redis_group     repeat_interval: 30m     routes:        match:           severity: critical         receiver: slack-alert    receivers:      name: slack-alert       slack_configs:          channel: 'general'           send_resolved: true           color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'           title: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing             | len }}{{ end }}] {{ .CommonAnnotations.summary }}'           text: |-             {{ range .Alerts }}               *Alert:* {{ .Annotations.summary }}  *{{ .Labels.severity | toUpper }}* on {{ .Labels.instance }}               *Description:* {{ .Annotations.description }}               *Details:*               {{ range .Labels.SortedPairs }}  *{{ .Name }}:* `{{ .Value }}`               {{ end }}             {{ end }}

Slack_api_url должен содержать ключ, который можно получить на сайте Slack.


В поле channel указывается канал, на который будут приходить оповещения. В нашем случае это general. Остальные параметры отвечают за формат уведомлений.


Конфигурацию, описанную далее, можно найти в репозитории.


Обновляем my-prometheus:


helm upgrade my-prometheus -f prometheus/values.yaml stable/prometheus -n monitoring

Для того, чтобы получить доступ к интерфейсу Alertmanager, выполним следующее:


export POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus,component=alertmanager" -o jsonpath="{.items[0].metadata.name}")kubectl --namespace monitoring port-forward $POD_NAME 9093

Теперь в интерфейсе Alertmanager можно убедиться, что появилась конфигурация для отправки оповещения в канал Slack http://127.0.0.1:9093/#/status:



Далее нужно создать правила, по которым нотификация будет отправляться в Slack-канал.


Правила представляют собой значения метрик или их совокупности, объединенные логическим условием. При выходе значения метрики за допустимые пределы Prometheus обращается к Alertmanager, чтобы отправить нотификации по определенным в нем каналам. Например, если метрика redis_up вернет значение 0, сработает уведомление о недоступности того или иного узла кластера.


Добавляем в файл prometheus/values.yaml стандартные правила для сигнализации о проблемах в Redis:


serverFiles:  ## Alerts configuration ## Ref: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ alerting_rules.yml:   groups:      name: redis_group       rules:          alert: redis_is_running           expr: redis_up == 0           for: 30s           labels:             severity: critical           annotations:             summary: "Critical: Redis is down on the host {{ $labels.instance }}."             description: "Redis has been down for more than 30 seconds"          alert: redis_memory_usage           expr:  redis_memory_used_bytes / redis_memory_max_bytes * 100 > 40           for: 5m           labels:             severity: warning           annotations:             description: "Warning: Redis high memory(>40%) usage on the host {{ $labels.instance }} for more than 5 minutes"             summary: "Redis memory usage {{ humanize $value}}% of the host memory"          alert: redis_master           expr: redis_connected_clients{instance!~"server1.mydomain.com.+"} > 50           for: 5m           labels:             severity: warning           annotations:             description: "Warning: Redis has many connections on the host {{ $labels.instance }} for more than 5 minutes"             summary: "Redis number of connections {{ $value }}"          alert: redis_rejected_connections           expr: increase(redis_rejected_connections_total[1m]) > 0           for: 30s           labels:             severity: critical           annotations:             description: "Critical: Redis rejected connections on the host {{ $labels.instance }}"             summary: "Redis rejected connections are {{ $value }}"          alert: redis_evicted_keys           expr: increase(redis_evicted_keys_total[1m]) > 0           for: 30s           labels:             severity: critical           annotations:             description: "Critical: Redis evicted keys on the host {{ $labels.instance }}"             summary: "Redis evicted keys are {{ $value }}"

Обновляем my-prometheus:


helm upgrade my-prometheus -f prometheus/values.yaml stable/prometheus -n monitoring

Для проверки работы нотификации в Slack, изменим правило алерта redis_memory_usage:


 expr:  redis_memory_used_bytes / redis_memory_max_bytes * 100 < 40

Снова обновляем my-prometheus:


helm upgrade my-prometheus -f prometheus/values.yaml stable/prometheus -n monitoring

Переходим на страницу http://127.0.0.1:9090/alerts:



Redis_memory_usage перешел в статус pending. Значение выражения для всех трех подов чуть больше 0.72. Далее уведомление проходит в Slack:



Теперь добавляем нотификацию по email. При этом конфигурация alermanager.yml изменится так:


alertmanagerFiles: alertmanager.yml:   global:     slack_api_url: <secret>    route:     receiver: slack-alert     group_by:        redis_group     repeat_interval: 30m     routes:        match:           severity: critical         receiver: slack-alert         continue: true        match:           severity: critical         receiver: email-alert    receivers:      name: slack-alert       slack_configs:          channel: 'general'           send_resolved: true           color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'           title: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing             | len }}{{ end }}] {{ .CommonAnnotations.summary }}'           text: |-             {{ range .Alerts }}               *Alert:* {{ .Annotations.summary }}  *{{ .Labels.severity | toUpper }}* on {{ .Labels.instance }}               *Description:* {{ .Annotations.description }}               *Details:*               {{ range .Labels.SortedPairs }}  *{{ .Name }}:* `{{ .Value }}`               {{ end }}             {{ end }}      name: email-alert       email_configs:        to: alert@agima.ru         send_resolved: true         require_tls: false         from: alert@agima.ru         smarthost: smtp.agima.ru:465         auth_username: "alert@agima.ru"         auth_identity: "alert@agima.ru"         auth_password: <secret>

В блок routes добавляем еще один путь для нотификации: receiver: email-alert. Ниже описываем параметры для email. В этом случае при том или ином событии мы получим уведомления одновременно в Slack и на email:




Blackbox exporter


Теперь рассмотрим, как в Prometheus добавляются targets на примере контейнера blackbox exporter, который позволяет организовать мониторинг внешних сервисов по протоколам HTTP(s), DNS, TCP, ICMP.


Для установки blackbox exporter используем Helm:


helm install blackbox-exporter stable/prometheus-blackbox-exporter --namespace monitoring 

Проверяем, что поды blackbox exporter запущены:


kubectl get pods -n monitoring | grep blackboxblackbox-exporter-prometheus-blackbox-exporter-df9f6d679-tvhrp   1/1     Running   0          20s

Добавляем в файл prometheus/values.yaml следующую конфигурацию:


extraScrapeConfigs: |  job_name: 'prometheus-blackbox-exporter'   metrics_path: /probe   params:     module: [http_2xx]   static_configs:      targets:        https://example.org    relabel_configs:      source_labels: [__address__]       target_label: __param_target      source_labels: [__param_target]       target_label: instance      target_label: __address__       replacement: blackbox-exporter-prometheus-blackbox-exporter.monitoring.svc.cluster.local:9115

Указываем, откуда собирать метрики:


blackbox-exporter-prometheus-blackbox-exporter.monitoring.svc.cluster.local:9115/probe. В качестве targets указываем URL сервиса для мониторинга: https://example.org. Для проверки используется модуль http_2xx, который по умолчанию устанавливается в blackbox exporter. Конфигурация проверки:


secretConfig: falseconfig: modules:   http_2xx:     prober: http     timeout: 5s     http:       valid_http_versions: ["HTTP/1.1", "HTTP/2"]       no_follow_redirects: false       preferred_ip_protocol: "ip4"

Обновляем конфигурацию my-prometheus:


helm upgrade my-prometheus -f prometheus/values.yaml stable/prometheus -n monitoring

В интерфейсе Prometheus http://127.0.0.1:9090/targets проверяем, что у нас появилась конечная точка для сбора метрик:



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


secretConfig: falseconfig: modules:   http_2xx:     prober: http     timeout: 5s     http:       valid_http_versions: ["HTTP/1.1", "HTTP/2"]       no_follow_redirects: false       preferred_ip_protocol: "ip4"       valid_status_codes: [200]   http_2xx_check:     prober: http     timeout: 5s     http:       method: GET       fail_if_body_not_matches_regexp:        "Example Domain"       fail_if_not_ssl: true       preferred_ip_protocol: ip4       valid_http_versions: ["HTTP/1.1", "HTTP/2"]       valid_status_codes: [200]

Обновляем конфигурацию blackbox-exporter/values.yaml:


helm upgrade blackbox-exporter -f blackbox-exporter/values.yaml stable/prometheus-blackbox-exporter --namespace monitoring

Изменяем в файле prometheus/values.yaml модуль http_2xx на http_2xx_check:


extraScrapeConfigs: |  job_name: 'prometheus-blackbox-exporter'   metrics_path: /probe   params:     module: [http_2xx]

Описания проверок, которые можно делать с blackbox exporter, приведены в документации.


Теперь добавим правила для сигнализации в Prometheus в файл prometheus/values.yaml:


   name: http_probe       rules:          alert: example.org_down           expr: probe_success{instance="http://personeltest.ru/aways/example.org",job="prometheus-blackbox-exporter"} == 0           for: 5s           labels:             severity: critical           annotations:             description: '{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes.'             summary: 'Instance {{ $labels.instance }} down'

И обновляем конфигурацию my-prometheus:


helm upgrade my-prometheus -f prometheus/values.yaml stable/prometheus -n monitoring

Для проверки можно изменить в blackbox-exporter/values.yaml значение текста для модуля http_2xx_check, который ищется в теле ответа, и обновить blackbox exporter. Должна сработать нотификация в Slack и Email.



Grafana


Настала очередь визуализации. Для отображения графиков будем использовать
Grafana.


Устанавливаем его уже привычным для нас образом с помощью пакетного менеджера Helm:


helm install my-grafana bitnami/grafana -n monitoring --set=persistence.enabled=false

В параметрах указываем не использовать persistent volume (--set=persistence.enabled=false), чтобы только продемонстрировать работу grafana. В продакшн- среде нужно настроить хранилище, так как поды по своей природе эфемерны, и есть риск потерять настройки Grafana.


Должен получиться вот такой вывод:


2. Get the admin credentials:    echo "User: admin"    echo "Password: $(kubectl get secret my-grafana-admin --namespace monitoring -o jsonpath="{.data.GF_SECURITY_ADMIN_PASSWORD}" | base64 --decode)"

Проверяем, что под Grafana запущен:


$kubectl get pods -n monitoring | grep grafanaNAME                                               READY   STATUS    RESTARTS   AGEmy-grafana-67c9776d7-nwbqj                         1/1     Running   0          55s

Перед тем как открыть интерфейс Grafana, нужно получить пароль от пользователя admin, сделать это можно так:


$echo "Password: $(kubectl get secret my-grafana-admin --namespace monitoring -o jsonpath="{.data.GF_SECURITY_ADMIN_PASSWORD}" | base64 --decode)"

Затем пробрасываем порт Grafana:


kubectl port-forward -n monitoring svc/my-grafana 8080:3000

Открываем http://127.0.0.1:9090/ в браузере и авторизуемся:



Для того чтобы Grafana могла получать значения метрик, хранящихся в базе данных Prometheus, необходимо подключить его. Переходим на http://127.0.0.1:8080/datasources и добавляем data source. В качестве TSDB выбираем Prometheus, который доступен в нашем кластере по адресу my-prometheus-server.monitoring.svc.cluster.local.


Должно получиться примерно так:



После добавления data source нужно добавить dashboard в Grafana чтобы состояния показателей Redis-кластера отображались на графиках. Переходим на http://127.0.0.1:8080/dashboard/import и добавляем id = 763. Итог:



После импорта получаем следующий dashboard с виджетами, которые отображают собранные метрики c кластера Redis:



Вы можете собирать такие дашборды самостоятельно или использовать уже готовые.


Вот, в принципе, и всё. Надеюсь, что сумел рассказать вам что-то новое. А главное убедил, что пользоваться Prometheus просто и удобно!

Подробнее..

Подборка телеграм-каналов для DevOps инженеров

13.03.2021 14:14:35 | Автор: admin

Приветствую, братцы!

Задача получения актуальной информации и совета опытных коллег сегодня актуальна как никогда. С одной стороны, сложно превзойти крупнейшие ИТ-сообщества в Slack. С другой стороны, важно иметь контакт с коллегами в нашей стране, в своем городе. Телеграм за последние годы стал крупнейшей площадкой для русскоязычного ИТ-сообщества, присоединяйтесь, не отставайте :)

Подборка телеграм-каналов и чатов:

Вакансии

Devops Jobs - Вакансии и резюме

Jobs for Devs & Ops - Вакансии для инженеров и разработчиков

Новостные каналы

Mops DevOps - Kubernetes, DevOps, SRE и многое другое

DevOps Deflope News - Новостной канал

Записки админа - Linux и администрировании серверов

k8s (in)security - Канал о (не)безопасности Kubernetes

Мир IT c Антоном Павленко - IT новости, статьи и видео

Конференции

DevOpsConf Channel - Информационный канал профессиональной конференции по эксплуатации и devops DevOpsConf Russia

Meetup Moscow - анонсы конференций

Инструменты DevOps

terraform_ru - Русскоязычный чат Hashicorp Terraform

pro_ansible- Чат для взаимопомощи по Ansible

Docker_ru- Русскоговорящее сообщество по экосистеме Docker (чат)

RU.Docker - Официальное Русское Сообщество (чат)

ru_gitlab- Русскоговорящая группа по GitLab

ru_jenkins- Русскоговорящая группа по Jenkins

Инфраструктура

Kubernetes- Общаемся на темы, посвященные Kubernetes, конфигурации и возможностям

istio_ru - Чат про Mervice Mesh в целом и Istio в частности

Вокруг Kubernetes в Mail.ru Group митапы по Kubernetes, DevOps, открытым технологиям в Mail.ru Group и немного проKubernetes как сервис

Envoy Proxy- Делимся опытом, экспертизой, советами и фэйлами :)

nginx_ru - Сообщество пользователей nginx, новости, обсуждения конфигураций

SDS и Кластерные FS - Обсуждаем Software-defined storage, кластерные файловые системы, блочные хранилища, стратегии построения хранилища и все что с ними связанно (Linstor, DRBD, ZFS, LVM, Ceph, GlusterFS, Lustre, MooseFS, LizardFS, mdadm, S3, iSCSI, NFS, OrangeFS, OCFS, GFS2)

Грефневая Кафка (pro.kafka)- Здесь топят за Кафку (Apache Kafka )

pro.kafka- Чат для добросовестных господ и дам, посвящённый Apache Kafka

DBA- Общаемся и обсуждаем темы, посвященные DBA, PostgreSQL, Redis, MongoDB, MySQL...

Облачные провайдеры

AWS_ru- Чат про Amazon Web Services

AWS notes- Канал про Amazon Web Services

Yandex.Cloud - Новости от команды платформы Yandex.Cloud

IT-журнал Завтра облачно - Блог команды Mail.ru Cloud Solutions (MCS)

Мониторинг и сбор логов

VictoriaMetrics_ru - Чат для обсуждения VictoriaMetrics

Церковь метрик- Канал про Метрики. Метрики. Метрики.

ru_logs - ElasticSearch, Graylog, Mtail, rsyslog и все такое прочее

Мониторим ИТ- Канал о мониторинге ИТ-инфраструктуры и приложений

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

Подробнее..
Категории: Kubernetes , Gitlab , Devops , Nginx , Docker , Monitoring , Istio , Telegram , Aws , Envoy

Перевод Использование переменных Grafana для большей интерактивности дашбордов

20.07.2020 18:22:00 | Автор: admin

Flowers and butterflies by marijeberting

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

Команда Mail.ru Cloud Solutions перевела статью, которая поможет добавить в Grafana функции, позволяющие пользователям создавать собственные интерактивные дашборды, чтобы углубиться в конкретные детали.

Общая проблема унылые статические дашборды


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

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

Решение: сделайте свои дашборды интерактивными (и удобными для пользователей)


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

Вот пример в Grafana инструменте визуализации с открытым исходным кодом, где я создал средства выбора (фильтры), которые позволяют мне и другим пользователям дашборда выбирать значения из выпадающего меню и сразу же видеть изменения на экране, без необходимости копаться в SQL-запросах.


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

Однако включить такие опции, как средства выбора, в пользовательском интерфейсе Grafana может оказаться непросто.

В оставшейся части поста я покажу, как вы сможете использовать функцию переменных Grafana для создания собственных интерактивных дашбордов. Я проиллюстрирую этот процесс на примере мониторинга местоположения автобусов, следующих по разным маршрутам в Нью-Йорке, но шаги, которые я выполняю, будут работать для любого сценария.

Попробуйте сами: реализация интерактивных дашбордов в Grafana


Готовы научиться использовать переменные в дашбордах Grafana для модификации запросов PostgreSQL?

Что нам нужно:

  • инстанс Grafana;
  • PostgreSQL с включенным движком TimescaleDB, подключенный к Grafana как источник данных; (Прим. переводчика: также можно использовать базы данных вроде InfluxDB.)
  • дашборд, использующий PostgreSQL в качестве источника данных.

Я собираюсь использовать пример визуализации местоположения в реальном времени в Нью-Йорке, используя данные столичного транспортного управления.

У меня есть существующая настройка дашборда Grafana World Map, изображенная ниже. Чтобы скопировать мою первоначальную настройку, вы можете клонировать этот репозиторий GitHub и выполнить шаги, описанные в нем.

Вот как выглядел мой дашборд, прежде чем мы сделаем его интерактивным (вы можете скачать JSON дашборда в этом репозитории GitHub).


Дашборд Первоначальная карта, показывающая местоположение автобусов в Нью-Йорке в реальном времени, без каких-либо интерактивных элементов

Вот SQL-запрос, который используется для получения данных для этого дашборда:

SELECT max(time) as "time", vid AS "vehicle_id", route_id, CASE WHEN route_id LIKE 'M%' THEN 1      WHEN route_id LIKE 'B%' THEN 2      WHEN route_id LIKE 'Q%' THEN 3      WHEN route_id LIKE 'S%' THEN 4      ELSE 0  END AS "color", ST_X(geom) AS "longitude", ST_Y(geom) AS "latitude"FROM mta WHERE time > now()-interval '1.5 minutes'GROUP BY vid, route_id, geomORDER BY 1;

В приведенном выше запросе обратите внимание, что я использую переменную цвета, чтобы различать разные типы автобусов в зависимости от их маршрута. Существует четыре типа автобусных маршрутов: M, B, S и Q в соответствии с районами Нью-Йорка: Манхеттен (M), Бронкс и Бруклин (B), Стейтен Айленд (S) и Куинс (Q).

Затем я использую настройки Grafana, чтобы назначить цвет каждому маршруту:



Обратите внимание, что используется пять цветов один для каждого автобусного маршрута M, B, Q и S, а также один для маршрутов, которые не попадают в эти категории.

Стандартный дашборд сообщает нам о местонахождении автобусов в реальном времени. Мы мало что можем сделать, чтобы лучше исследовать данные, кроме увеличения и уменьшения числа маршрутов.

Давайте создадим переменную, которая определяет, какие автобусные маршруты мы отображаем на карте.

Шаг 1. Создаем переменную как запрос


Наша цель создать переменную, которая управляет автобусами, отображаемыми в дашборде, на основе маршрута автобуса.

Для простоты давайте определим четыре типа автобусных маршрутов: M, B, Q и S.

Grafana включает в себя множество типов переменных, и переменные в Grafana работают так же, как переменные в языках программирования. Мы определяем переменную, а затем, когда мы ссылаемся на нее, ссылаемся на то, как мы определили переменную.

Чтобы создать новую переменную, зайдите в настройки панели инструментов Grafana, перейдите к параметру Переменная в боковом меню и нажмите кнопку Добавить переменную.

В этом случае мы используем тип Query, где наша переменная будет определена как результат запроса SQL.


Как создать переменную типа Query

В разделе General мы назовем нашу переменную route. Затем мы присвоим ей метку MTA Bus Route.


Имя, метка и тип нашей переменной route

Метки в Grafana это удобочитаемые дескрипторы, которые отображаются рядом с выпадающим меню в дашборде:



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

Затем напишем запрос, который определяет значение переменной, в разделе Query options.


Настройки для создания переменной route

Нам нужно выбрать источник данных для нашей переменной им будет база данных, в которой будет выполняться запрос. В этом случае мы используем MTA Bus DB, базу данных PostgreSQL, в которой хранятся наши данные MTA Bus.

Теперь мы определим SQL-запрос, результаты которого будут определять нашу переменную route:

SELECT * from (values ('M'),('B'),('Q'),('S')) v;

Этот запрос возвращает буквы M, B, Q, S которые являются типами маршрутов на основе их route_id (для понимания см. запрос SQL в разделе предварительных требований).

Можно использовать более продвинутый запрос, который дает дополнительное преимущество в виде удобочитаемых имен, а не использование символов или аббревиатур:

SELECT k AS "__text", v AS "__value" FROM (VALUES ('Manhattan', 'M'),('Bronx/Brooklyn', 'B'), ('Queens', 'Q'), ('Staten Island', 'S')) v(k, v);

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

  1. Напомним, что эта переменная также могла иметь тип Custom, поскольку у нас есть статический список значений, который никогда не изменяется, что позволяет задавать значения напрямую, без необходимости указывать их через SQL.
  2. Однако если нужно отображение ключ/значение, чтобы отображать как символы, так и понятные человеку имена, требуется запрос SQL. Я использовал SQL-запрос, поскольку на практике часто нужно, чтобы переменные принимали значения, которые не жестко запрограммированы, а изменяются в зависимости от данных в базе данных, таких как имена клиентов, имена кластеров и так далее.

Теперь давайте определим, как использовать нашу переменную.

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

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

Внизу, в разделе Предварительный запрос, можно увидеть предварительный набор результирующих значений. В нашем случае у нас есть Все, M, B, Q, S (то есть, наши четыре отдельных автобусных маршрута и опция Выбрать все).


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

Шаг 2: Измените запрос для построения графиков с учетом новой переменной


В этом пункте мы модифицируем запрос, чтобы использовать переменную из первого шага.

Для запроса SQL мы изменим предложение WHERE, чтобы отфильтровать нежелательные результаты. В нашем случае мы хотим показать только те типы маршрутов, которые выбраны в выпадающем меню в пользовательском интерфейсе дашборда.

Вот модифицированный запрос:

SELECT max(time) as "time", vid AS "vehicle_id", route_id, CASE WHEN route_id LIKE 'M%' THEN 1      WHEN route_id LIKE 'B%' THEN 2      WHEN route_id LIKE 'Q%' THEN 3      WHEN route_id LIKE 'S%' THEN 4      ELSE 0  END AS "color", ST_X(geom) AS "longitude", ST_Y(geom) AS "latitude"FROM mta WHERE time > now()-interval '1.5 minutes'AND substring(route_id,1,1) IN ($route)GROUP BY vid, route_id, geomORDER BY 1;

Соответствующая часть запроса, где мы ссылаемся на нашу новую переменную по имени, которое мы определили на первом шаге, это строки 13 и 14:

SELECT...WHERE time > now()-interval '1.5 minutes'AND substring(route_id,1,1) IN ($route)

Эти строки говорят, что наша визуализация отображается только, если первая буква ее route_id находится в наборе разрешенных маршрутов (выбирается пользователем с помощью раскрывающегося списка, определяемого переменной маршрута). Значения, выбранные в списке, будут определять нашу переменную $route.

Например:

  1. Если пользователь выбирает все маршруты, то route = (M, B, S, Q), набор всех возможных типов маршрутов.
  2. Если пользователь выбирает только маршруты M и B, то route = (M, B). Мы автоматически отфильтровываем маршруты S и Q и отображаем только автобусы с route_id, начинающимся с M и B.

После того как мы изменили запрос, сохраняем наши изменения и проверяем, работает ли наша переменная так, как ожидалось.

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


Наш новый интерактивный дашборд, где карта обновляется на основе маршрутов, которые мы выбираем в выпадающем меню

Как вы можете видеть, карта автоматически меняет типы автобусов, отображаемые на экране, в зависимости от выбора, который мы делаем в раскрывающемся списке. Обратите внимание, что изменения происходят в нескольких панелях, поскольку все они используют переменную $route в своем запросе.

Мы успешно создали интерактивный дашборд Grafana с использованием переменных.

Успехов!

Что еще почитать по теме:

  1. Подборка из 90+ полезных инструментов Kubernetes.
  2. Наблюдаемость SRE: пространство имен и структура метрик.
  3. Наш канал Вокруг Kubernetes в Телеграме.
Подробнее..

Мониторинг NetApp Volumes через SSH

17.09.2020 12:16:31 | Автор: admin

Всем привет, меня зовут Игорь Сидоренко. Одной из основных сфер моей работы, а также моим хобби является мониторинг. Я расскажу о Zabbix и о том, как с его помощью замониторить необходимую нам информацию о томах NetApp, имея доступ только по SSH. Кому интересна тема мониторинга и Zabbix, прошу под кат.

Изначально мы мониторили тома, монтируя их к определенному серверу, на котором висел специальный шаблон, отлавливающий NFS-маунты на ноде и ставящий их на мониторинг, по аналогии с файловыми системами базового шаблона Linux. Маунт надо было прописать в fstab и примонтировать вручную из-за этого многое терялось и забывалось.

Потом мне пришла в голову прекрасная идея: надо всё это автоматизировать. Было несколько вариантов:

  • Есть готовые шаблоны, работающие с SNMP, но доступов нет.
  • Получение списка томов и автоматический маунт на ноде: надо создавать папку, прописывать fstab, маунтить вот это всё, слишком много геморроя.
  • Есть же великолепный API, но в нашей версии ONTAP он урезан и не дает пользователю нужную информацию.
  • Как-то использовать доступ по SSH для получения томов и постановки их на мониторинг.

Выбор пал на SSH-агент.

Низкоуровневое обнаружение (LLD)


Для начала нам необходимо создать низкоуровневое обнаружение (LLD), это будут названия наших томов. Всё это необходимо для того, чтобы вытащить конкретную информацию по нужному нам тому. Сырые данные выглядят примерно так (на момент написания их 114):

set -unit B; volume show -state online



Ну как же без костылей: напишем однострочный bash-скрипт, который будет выводить названия томов в формате JSON (поскольку это внешняя проверка, cкрипты лежат на Zabbix-сервере в директории /usr/lib/zabbix/externalscripts):

netapp_volume_discovery.sh
#!/usr/bin/bashSVM_NAME=""SVM_ADDRESS=""USERNAME=""PASSWORD=""for i in $(sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USERNAME@$SVM_ADDRESS 'set -unit B; volume show -state online' | grep $SVM_NAME | awk {'print $2'}); do echo '{"volume_name":"'$i'"}'; done | jq -s '.




Теперь необходимо создать шаблон и на основе полученных данных создавать элементы данных:





Элементы данных


Для автоматического создания элементов данных необходимо сделать прототип элементов данных:



Мы будем использовать мастер-элементы и несколько зависимых от них элементов. Таким образом, для каждого тома создается один мастер-элемент, в котором выполняется набор команд по SSH:

set -unit B; df -i -volume {#VOLUME_NAME}; volume show-space {#VOLUME_NAME}; statistics volume show -volume {#VOLUME_NAME}

Получаем вот такую простыню:

Get Volume: ackey_media info
Last login time: 9/15/2020 12:42:45Filesystem               iused      ifree  %iused  Mounted on/vol/ackey_media/           96     311191      0%  /ackey_media                      Volume Name: ackey_media                      Volume MSID: 2159592810                      Volume DSID: 1317                     Vserver UUID: 46a00e5d-c22d-11e8-b6ed-00a098d48e6d                   Aggregate Name: NGHF_FAS2720_04                   Aggregate UUID: 7ec21b4d-b4db-4f84-85e2-130750f9f8c3                         Hostname: FAS2720_04                        User Data: 20480B                User Data Percent: 0%                    Deduplication: -            Deduplication Percent: -          Temporary Deduplication: -  Temporary Deduplication Percent: -              Filesystem Metadata: 1150976B      Filesystem Metadata Percent: 0%              SnapMirror Metadata: -      SnapMirror Metadata Percent: -             Tape Backup Metadata: -     Tape Backup Metadata Percent: -                   Quota Metadata: -           Quota Metadata Percent: -                           Inodes: 12288B                   Inodes Percent: 0%                   Inodes Upgrade: -           Inodes Upgrade Percent: -                 Snapshot Reserve: -         Snapshot Reserve Percent: -        Snapshot Reserve Unusable: -Snapshot Reserve Unusable Percent: -                   Snapshot Spill: -           Snapshot Spill Percent: -             Performance Metadata: 28672B     Performance Metadata Percent: 0%                       Total Used: 1212416B               Total Used Percent: 0%         Total Physical Used Size: 1212416B         Physical Used Percentage: 0%                Logical Used Size: 1212416B             Logical Used Percent: 0%                Logical Available: 10736205824BDOMCLIC_SVM : 9/15/2020 12:42:51                        *Total Read Write Other  Read Write Latency      Volume     Vserver    Ops  Ops   Ops   Ops (Bps) (Bps)    (us) ----------- ----------- ------ ---- ----- ----- ----- ----- ------- ackey_media DOMCLIC_SVM      0    0     0     0     0     0       0


Из этой простыни необходимо отобрать нужные нам метрики.

Магия регулярных выражений


Изначально для препроцессинга я хотел использовать JavaScript, но как-то не осилил, не зашло. Поэтому остановился на регулярках, да и использую их практически везде.

Количество используемых инод


Отберем информацию только о инодах по каждому тому в два этапа:





Сначала вся информация:

\/vol\/\w+\/.*





Потом конкретно по метрикам:

(\d+)\s+(\d+)\s+(\d+)





Вывод шаблон форматирования вывода. \N (где N=1..9) управляющая последовательность заменяется N-ной совпадающей группой. Управляющая последовательность \0 заменяется совпадающим текстом:

  • \1 - Inode used on {#VOLUME_NAME} количество использованных инод;
  • \2 - Inode free on {#VOLUME_NAME} количество свободных инод;
  • \3 - Inode used percentage on {#VOLUME_NAME} использованные иноды в процентах;
  • Inode total on {#VOLUME_NAME} вычислямый элемент, количество доступных инод.

last(inode_free[{#VOLUME_NAME}])+last(inode_used[{#VOLUME_NAME}])

Количество используемого места


Здесь всё проще, данные и регулярки в более приятном формате:





Выдергиваем нужную нам метрику и берем только число:

(?<=Logical Available:\s)\d+





Собираемые метрики:

  • Logical available on {#VOLUME_NAME} количество доступного логического места;
  • Logical used percent on {#VOLUME_NAME} использованное логическое место в процентах;
  • Logical used size on {#VOLUME_NAME} количество использованного логического места;
  • Physical used percentage on {#VOLUME_NAME} использованное физическое место в процентах;
  • Total physical used size on {#VOLUME_NAME} количество использованного физического места;
  • Total used on {#VOLUME_NAME} всего использовано места;
  • Total used percent on {#VOLUME_NAME} всего использовано места в процентах;
  • Logical size on {#VOLUME_NAME} вычисляемый элемент, количество доступного логического места.

last(logical_available[{#VOLUME_NAME}])+last(total_used[{#VOLUME_NAME}])

Производительность томов


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

statistics volume show -volume {#VOLUME_NAME}





Из общей простыни первой регуляркой мы отбираем метрики по производительности:

.DOMCLIC_SVM.*





Второй группируем числа:

(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)



Где:

  • \1 - Total number of operations per second on {#VOLUME_NAME} общее количество операций в секунду;
  • \2 - Read operations per second on {#VOLUME_NAME} операций чтения в секунду;
  • \3 - Write operations per second on {#VOLUME_NAME} операций записи в секунду;
  • \4 - Other operations per second on {#VOLUME_NAME} другие операции в секунду (не знаю, что это, но зачем-то снимаю);
  • \5 - Read throughput in bytes per second on {#VOLUME_NAME} скорость чтения в байтах в секунду;
  • \6 - Write throughput in bytes per second on {#VOLUME_NAME} скорость записи в байтах в секунду;
  • \7 - Average latency for an operation in microseconds on {#VOLUME_NAME} средняя задержка операций в микросекундах.

Алертинг


Набор триггеров стандартный, место и иноды:



  • Free disk space less than 1% on {#VOLUME_NAME}
  • Free disk space less than 5% on {#VOLUME_NAME}
  • Free disk space less than 10% on {#VOLUME_NAME}
  • Free inodes less than 1% on {#VOLUME_NAME}
  • Free inodes less than 5% on {#VOLUME_NAME}
  • Free inodes less than 10% on {#VOLUME_NAME}

Визуализация


Визуализация приходится, в основном, на Grafana, это красиво и удобно. На примере одного тома выглядит примерно так:



В правом верхнем углу есть кнопка Show in Zabbix, с помощью которой можно провалиться в Zabbix и увидеть все метрики по выбранному тому.

Итоги


  • Автоматическая постановка томов на мониторинг.
  • Автоматическое удаление томов из мониторинга, в случае удаление тома с NetApp.
  • Избавились от привязки к одному серверу и ручному монтированию томов.
  • Добавились метрики производительности по каждому тому. Теперь мы реже дергаем поддержку датацентра ради графиков с NetApp.

Скоро обещают обновить ONTAP и завезти расширенный API, шаблон переедет на HTTP-агент.

Шаблон, скрипт и дашборд


github.com/domclick/netapp-volume-monitoring

Полезные ссылки


docs.netapp.com/ontap-9/index.jsp
www.zabbix.com/documentation/current
Подробнее..

SaaS и ALEPIZ мониторинг и управление инфраструктурой

20.05.2021 12:07:50 | Автор: admin

Я системный администратор, более 20 лет занимаюсь управлением и мониторингом критичной в масштабах страны инфраструктуры. Услуги, которые я администрирую, предоставляются по модели SaaS (Software as a Service аренда ПО). Это моя первая публикация, я решил поделиться своими наработками в этой области, возможно кому-то это будет полезно.

ALEPIZ распространяется бесплатно по лицензии GPL v3ALEPIZ распространяется бесплатно по лицензии GPL v3

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

Хочу заметить, что эта статья не является рекламой. Я пишу ее как частное лицо и не представляю какую-либо организацию. Решение доступно вместе с исходным кодом и находится в свободном доступе. Вы можете использовать его совершенно бесплатно по своему усмотрению.

История

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

В начале 2000 мы начали внедрять, как тогда казалось подходящую нам и довольно распространенную систему мониторинга. В процессе её адаптации через некоторое время стало понятно, что использовать систему как есть не получится. Пришлось заниматься доработкой. В результате, за 10 лет эксплуатации и разработки мы получили систему по управлению и мониторингу с организацией рабочих процессов между подразделениями. В качестве ядра системы использовалась выбранная нами система мониторинга и ее БД.

Обновить ее мы не могли, потому что разработчики системы мониторинга меняли структуру БД, к которой было жестко привязано наше ПО. Несколько лет назад производительности системы стало существенно не хватать. Появилось много неудобств, связанных с недостаточно проработанной архитектурой как системы мониторинга, так и наших доработок.

Я решил учесть ошибки и разработать новую систему. Большинство продуктов создаются разработчиками ПО, а я системный администратор. Я хуже знаю процесс разработки, но проектирование и реализация системы для системных администраторов в данном случае сделана системным администратором, с учетом нюансов нашей работы. Считаю, что это положительно сказалось на конечном результате

В своей организации я разрабатывать систему не мог, потому что у меня на это нет времени и в мои обязанности не входит разработка какого-либо ПО. Я решил сделать создание системы своим хобби и занимался ей в свободное от работы время. Начал заниматься разработкой в 2014 году. Когда я все это планировал, я не думал, что это хобби потребует от меня столько времени и ресурсов. Несмотря на все сложности, я все-таки смог довести процесс до конца. В настоящее время у системы есть реальные внедрения и большая часть запланированных функций реализована.

ALEPIZ

Новая система получила название ALEPIZ. Я не планировал ее распространять, но создание системы затянулось. Чтобы не платить за средства разработки я выполнил условия для их бесплатного использования: выложил ПО на GitHub под лицензией GPL v3 и создал сайт alepiz.com.

Data Browser служит для отображения собранных исторических данныхData Browser служит для отображения собранных исторических данных

Архитектура системы

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

Тестирование и эксплуатация ведется под ОС Microsoft Windows. Выбор ОС продиктован архитектурой программного обеспечения, которое используется в моей организации.

Для возможности портирования в будущем на другие архитектуры, в качестве платформы были выбраны JavaScript и NodeJS. Это так же позволило унифицировать разработку backend и frontend и использовать асинхронность JavaScript для достижения требуемой производительности. Применение потоков (threads) в NodeJS невозможно из-за отсутствия поддержки во многих модулях, поэтому используется схема с запуском нескольких процессов.

В ALEPIZ встроен Web сервер и сервер БД на основе быстрой и простой SQLITE. При развертывании системы нет необходимости в установке дополнительного ПО: ALEPIZ включает все требуемые компоненты. Для ускорения работы с БД реализована система кэширования, разработанная специально для ALEPIZ.

Есть периодическая очистка старых исторических данных, которая позволяет сделать размер БД близким к постоянному. Реализованы встроенная репликация и резервное копирование БД, система интеллектуального пропуска похожих данных, автоматическая ротация логов, система настройки прав ролевого доступа для пользователей и многое другое.

Сейчас ALEPIZ обслуживает одновременно более 250 000 метрик. Их количество постоянно увеличивается. Сбор данных по метрике происходит примерно раз в 3060 секунд. Исторические данные хранятся три месяца и база данных занимает около 1Тб. Для работы используется сервер с двумя процессорами Intel, по двенадцать ядер в каждом. Суммарная загрузка процессоров около 40% и зависит от количества расчетов, выполняемых ALEPIZ. Потребление памяти 64Gb. В качестве дисковой подсистемы используется RAID10 из 8 HDD 10 000 Rpms. Репликация и резервное копирование БД производится по сети на другой сервер.

Системные требования

Для работы ALEPIZ требуется компьютер архитектуры Intel x64 с установленной ОС Microsoft Windows версии не ниже Windows Server 2012 или Windows 10. После установки ALEPIZ использует 200Mb дискового пространства. Потребление оперативной памяти на сервере с 12 ядрами CPU составляет 1Gb. При меньшем количестве ядер потребление памяти будет уменьшено.

Описание возможностей

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

Кроме сбора данных ALEPIZ позволяет генерировать события. Обычно это какие-то пороговые значения. Например, мало свободной памяти или повышенное использование процессора. Это стандартная функция для большинства систем мониторинга. В случае с ALEPIZ, модуль для обработки событий реализован так, чтобы обеспечить организацию рабочих процессов в подразделениях компании.

Dashboard позволяет обрабатывать произошедшие событияDashboard позволяет обрабатывать произошедшие события

ALEPIZ является не только системой мониторинга, но и системой для управления инфраструктурой. Для этого существуют специальные модули - действия. Например, действием может быть запуск или остановка внешнего сервиса, редактирование файла настроек, выполнения запросов к БД или копирование файлов для обновления ПО. Можно разрабатывать собственные действия.

Действия можно объединять в задачи и запускать их в определенное время, либо в зависимости от различных условий. Например, обновление сервиса должно запускаться только если он остановлен. Таким образом можно автоматизировать управление инфраструктурой.

Описание возможностей системы есть на сайте ALEPIZ и доступно на русском языке.

Сущности системы

Чтобы получить больше информации о принципах работы системы и ее возможностях, немного погрузимся в ALEPIZ.

Коллекторы

Для сбора данных используются модули, которые называются коллекторами (collectors). Например, коллектор PING используется для проверки доступности хостов по протоколу ICMP. Коллектор SNMP необходим для сбора данных по одноименному протоколу. MSSQL служит для выполнения запросов к БД MSSQL и т.п. На момент написания статьи в ALEPIZ реализован 21 коллектор. Можно разработать собственный. Информация о разработке коллектора и средства для разработки встроены в ALEPIZ.

Counter settings служит для настройки каунтераCounter settings служит для настройки каунтера

Каунтеры

Каунтеры (counters) это коллекторы с параметрами, которые определяют, какие данные необходимо собирать. Например, для того чтобы коллектор PING начал собирать информацию, ему в качестве параметра необходимо передать имя хоста, доступность которого требуется проверять. Параметры для коллекторов настраиваются в каунтерах.

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

Активные и пассивные коллекторы. Зависимости в каунтерах

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

Например, каунтер с активным коллектором Timer генерирует данные через определенные интервалы времени. Если от него сделать зависимым каунтер с пассивным коллектором SNMP, то данные по протоколу SNMP будут собираться через определенные каунтером интервалы времени. Если от каунтера с SNMP сделать зависимым каунтер с коллектором Events generator, то в случае превышения установленного порогового значения, в Dashboard появится предупреждение о возможной проблеме.

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

Объекты

Объекты (objects) это сущность с именем. Объектом может быть хост, сервис, исполняемый файл, база данных, дата центр и т. д. Объекты могут включать другие объекты, выступая в качестве каталогов.

Object editor необходим для редактирования объектов и их привязки к каунтерамObject editor необходим для редактирования объектов и их привязки к каунтерам

Связь объектов и каунтеров

Каунтеры не могут существовать сами по себе. Каждый каунтер должен быть привязан к одному или нескольким объектам. У объектов можно настроить свойства, которые будут использовать каунтеры для сбора или генерации информации. Например, объект хост может содержать свойство IP адрес, который будет использован каунтером с коллектором PING для проверки доступности этого хоста. Каунтер с коллектором PING можно привязать к нескольким объектам- хостам и он будет собирать данные в зависимости от настроенных свойств (IP адреса) для каждого из объектов.

Действия

Действия (actions) это модули ALEPIZ, которые используются для управления как непосредственно сущностями ALEPIZ, так и внешней инфраструктурой. Например, действием может быть модуль для создания нового объекта или каунтера ALEPIZ, или для запуска и остановки сервиса Windows, или для просмотра собранной исторической информации, или данных по различным событиям и т. п.

Можно разработать собственные действия. Информация и средства для разработки встроены в ALEPIZ.

Задачи

Задачи (tasks) это несколько действий, объединенных в группу. Задачи могут запускаться вручную, или в определенное время. A так же в зависимости от состояния определенных каунтеров и даже непосредственно из каунтеров.

С помощью задач можно автоматизировать управление инфраструктурой и организовать процессы для взаимодействия между различными подразделениями организации.

Tasks maker используется для управления задачамиTasks maker используется для управления задачами

Остальные возможности

Кроме того, в ALEPIZ есть такие модули, как лаунчеры для различных способов запуска действий, средства связи для передачи информации по email, SMS и т.п. Есть встроенный процессор с набором функций для обработки полученных данных, условий в каунтерах и формирования зависимостей на основе этих условий, система обработки произошедших событий с возможностью организации рабочих процессов в организации, средства отладки и т.д. Полное описание возможностей есть на сайте или в справке по ALEPIZ на русском языке.

Заключение

На мой взгляд, ALEPIZ может удовлетворить потребности как в мониторинге, так и в автоматизации управления для очень разных инфраструктур. При необходимости расширения, возможна разработка собственных модулей, ориентированных на конкретные условия эксплуатации.

Не обязательно использовать сразу все возможности ALEPIZ. Если у Вас небольшая инфраструктура, или в настоящее время нет потребности в автоматическом управлении, можно использовать только часть функций, например, только мониторинг. В дальнейшем у Вас будет возможность расширения и внедрения автоматизации в систему управления инфраструктурой.

Хотел бы еще раз повторить: ALEPIZ распространяется бесплатно по лицензии GPL v3. Вы можете использовать его на свое усмотрение. Я не знаю способов монетизации системы, поэтому принял решение сделать его доступным для всех.

Если Вы решили поставить систему у себя, проще всего скачать и запустить установочный пакет для ОС Microsoft Windows со страницы https://alepiz.com/help/download.pug. В этом случае установка и первичная настройка системы произойдет автоматически. ALEPIZ можно поставить даже на персональный компьютер или ноутбук под управлением Windows 10.

Несмотря на то, что ALEPIZ эксплуатируется, он продолжает разрабатываться и находится в статусе beta тестирования. Если Вы обнаружите дефект или у Вас будут какие-либо пожелания к дальнейшему развитию системы, можете написать мне.

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

Спасибо за прочтение, надеюсь, ALEPIZ поможет Вам и Вашему бизнесу в достижении новых целей.

Подробнее..

Перевод Знакомство с PromQL Cheatsheet

13.06.2021 12:23:01 | Автор: admin

Скачать Cheatsheet по запросам PromQL

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

Поскольку Prometheus хранит данные в виде временных рядов (time-series data model), запросы PromQL радикально отличаются от привычного SQL. Понимание, как работать с данными в Prometheus, является ключом к тому, чтобы научиться писать эффективные запросы.

Не забудьте скачать Cheatsheet по запросам PromQL!

Как работают time-series databases

Временные ряды это потоки значений, связанных с меткой времени.

Каждый временной ряд можно идентифицировать по названию метрики и меткам, например:

mongodb_up{}

или

kube_node_labels{cluster="aws-01", label_kubernetes_io_role="master"}

В приведенном выше примере присутствует имя метрики (kube_node_labels) и метки (cluster и label_kubernetes_io_role). На самом деле, метрики тоже являются метками. Приведенный выше запрос можно записать так:

{__name__ = "kube_node_labels", cluster="aws-01", label_kubernetes_io_role="master"}

В Prometheus есть четыре типа метрик:

  • Gauges(Измеритель) значения, которые могут меняться. Например, метрика mongodb_up позволяет узнать, есть ли у exporter соединение с экземпляром MongoDB.

  • Counters(Счетчик) показывают суммарные значения и обычно имеют суффикс _total. Например, http_requests_total.

  • Histogram (Гистограмма) это комбинация различных счетчиков, используется для отслеживания размерных показателей и их продолжительности, таких как длительность запросов.

  • Summary (Сводка)работает как гистограмма, но также рассчитывает квантили.

Знакомство с выборкой данных PromQL

Выбрать данные в PromQL так же просто, как указать метрику, из которой вы хотите получить данные. В этом примере мы будем использовать метрику http_requests_total.

Допустим, мы хотим узнать количество запросов по пути / api на хосте 10.2.0.4. Для этого мы будем использовать метки host и path из этой метрики:

http_requests_total{host="10.2.0.4", path="/api"}

Запрос вернет следующие значения:

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

98

http_requests_total

10.2.0.4

/api

503

20

http_requests_total

10.2.0.4

/api

401

1

Каждая строка в этой таблице представляет собой поток с последним доступным значением. Поскольку http_requests_total содержит определенное количество запросов, сделанных с момента последнего перезапуска счетчика, мы видим 98 успешных запросов.

Это называетсяinstant vector, самое раннее значение для каждого потока на указанный в запросе момент времени. Поскольку семплы берутся в случайное время, Prometheus округляет результаты. Если длительность не указана, то возвращается последнее доступное значение.

Кроме того, вы можете получить instant vector из другого отрезка времени (например, день назад).

Для этого вам нужно добавить offset (смещение), например:

http_requests_total{host="10.2.0.4", path="/api", status_code="200"} offset 1d

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

http_requests_total{host="10.2.0.4", path="/api"}[10m]

Запрос вернет следующие значения:

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

641309@1614690905.515

641314@1614690965.515

641319@1614691025.502

http_requests_total

10.2.0.5

/api

200

641319@1614690936.628

641324@1614690996.628

641329@1614691056.628

http_requests_total

10.2.0.2

/api

401

368736@1614690901.371

368737@1614690961.372

368738@1614691021.372

Запрос возвращает несколько значений для каждого временного ряда потому, что мы запросили данные за определенный период времени, а каждое значение связано с отметкой времени.

Это называется range vector все значения для каждой серии в пределах указанного временного интервала.

Знакомство с агрегаторами и операторами PromQL

Как видите, селекторы PromQL помогают получить данные метрик. Но что, если вы хотите получить более сложные результаты?

Представим, что у нас есть метрика node_cpu_cores с меткой cluster. Мы могли бы, например, суммировать результаты, объединяя их по определенной метке:

sum by (cluster) (node_cpu_cores)

Запрос вернет следующие значения:

cluster

value

foo

100

bar

50

С помощью этого простого запроса мы видим, что имеется 100 ядер ЦП для кластера cluster_foo и 50 для cluster_bar.

Кроме того, мы можем использовать в запросах PromQL арифметические операторы. Например, используя метрику node_memory_MemFree_bytes, которая возвращает объем свободной памяти в байтах, мы могли бы получить это значение в мегабайтах с помощью оператора деления:

node_memory_MemFree_bytes / (1024 * 1024)

Мы также можем получить процент доступной свободной памяти, сравнив предыдущую метрику с node_memory_MemTotal_bytes, которая возвращает общий объем памяти, доступной на узле:

(node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100

Теперь мы можем использовать этот запрос для создания оповещения, когда на узле остается менее 5% свободной памяти:

(node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100 < 5

Знакомство с функциями PromQL

PromQL поддерживает большое количество функций, которые мы можем использовать для получения более сложных результатов. Например, в предыдущем примере мы могли бы использовать функцию topk, чтобы определить, какой из двух узлов имеет больший объем свободной памяти (в процентах):

topk(2, (node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100)

Prometheus позволяет не только получить информацию о прошедших событиях, но даже строить прогнозы. Функция pred_linear предсказывает, где будет временной ряд через заданный промежуток времени.

Представьте, что вы хотите узнать, сколько свободного места будет доступно на диске в следующие 24 часа. Вы можете применить функцию pred_linear к результатам за прошлую неделю из метрики node_filesystem_free_bytes, которая возвращает доступное свободное место на диске. Это позволяет прогнозировать объем свободного дискового пространства в гигабайтах в ближайшие 24 часа:

predict_linear(node_filesystem_free_bytes[1w], 3600 * 24) / (1024 * 1024 * 1024) < 100

При работе со счетчиками Prometheus удобно использовать функцию rate. Она вычисляет среднюю скорость увеличения временного ряда в векторе диапазона в секунду, сбросы счетчика автоматически корректируются. Кроме того, вычисление экстраполируется к концам временного диапазона.

Что делать, если нам нужно создать оповещение, которое срабатывает, если мы не получали запрос в течение 10 минут. Мы не можем просто использовать метрику http_requests_total, потому что при сбросе счетчика в течение указанного временного диапазона результаты были бы неточными:

http_requests_total[10m]

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

100@1614690905.515

300@1614690965.515

50@1614691025.502

В приведенном выше примере после сброса счетчика мы получаем отрицательные значения от 300 до 50, поэтому нам недостаточно только этой метрики. Мы можем решить проблему с помощью функции rate. Поскольку он считает сбросы счетчика, результаты фиксируются, как если бы они были такими:

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

100@1614690905.515

300@1614690965.515

350@1614691025.502

rate(http_requests_total[10m])

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

0.83

Независимо от сбросов за последние 10 минут в среднем было 0,83 запроса в секунду. Теперь мы можем настроить оповещение:

rate(http_requests_total[10m]) = 0

Что дальше?

В этой статье мы узнали, как Prometheus хранит данные, рассмотрели примеры запросов PromQL для выборки и агрегирования данных.

Вы можете скачать Cheatsheet по PromQL, чтобы узнать больше об операторах и функциях PromQL. Вы также можете проверить все примеры из статьи и Cheatsheet с нашим сервисом Prometheus playground.

Подробнее..

Мониторинг демон на Asyncio Dependency Injector руководство по применению dependency injection

09.08.2020 08:06:15 | Автор: admin
Привет,

Я создатель Dependency Injector. Это dependency injection фреймворк для Python.

Это еще одно руководство по построению приложений с помощью Dependency Injector.

Сегодня хочу показать как можно построить асинхронный демон на базе модуля asyncio.

Руководство состоит из таких частей:

  1. Что мы будем строить?
  2. Проверка инструментов
  3. Структура проекта
  4. Подготовка окружения
  5. Логирование и конфигурация
  6. Диспетчер
  7. Мониторинг example.com
  8. Мониторинг httpbin.org
  9. Тесты
  10. Заключение

Завершенный проект можно найти на Github.

Для старта желательно иметь:

  • Начальные знания по asyncio
  • Общее представление о принципе dependency injection

Что мы будем строить?


Мы будем строить мониторинг демон, который будет следить за доступом к веб-сервисам.

Демон будет посылать запросы к example.com и httpbin.org каждые несколько секунд. При получении ответа он будет записывать в лог такие данные:

  • Код ответа
  • Количество байт в ответе
  • Время, затраченное на выполнение запроса



Проверка инструментов


Мы будем использовать Docker и docker-compose. Давайте проверим, что они установлены:

docker --versiondocker-compose --version

Вывод должен выглядеть приблизительно так:

Docker version 19.03.12, build 48a66213fedocker-compose version 1.26.2, build eefe0d31

Если Docker или docker-compose не установлены, их нужно установить перед тем как продолжить. Следуйте этим руководствам:


Инструменты готовы. Переходим к структуре проекта.

Структура проекта


Создаем папку проекта и переходим в нее:

mkdir monitoring-daemon-tutorialcd monitoring-daemon-tutorial

Теперь нам нужно создать начальную структуру проекта. Создаем файлы и папки следуя структуре ниже. Все файлы пока будут пустыми. Мы наполним их позже.

Начальная структура проекта:

./ monitoringdaemon/    __init__.py    __main__.py    containers.py config.yml docker-compose.yml Dockerfile requirements.txt

Начальная структура проекта готова. Мы расширим ее с следующих секциях.

Дальше нас ждет подготовка окружения.

Подготовка окружения


В этом разделе мы подготовим окружение для запуска нашего демона.

Для начала нужно определить зависимости. Мы будем использовать такие пакеты:

  • dependency-injector dependency injection фреймворк
  • aiohttp веб фреймворк (нам нужен только http клиент)
  • pyyaml библиотека для парсинга YAML файлов, используется для чтения конфига
  • pytest фреймворк для тестирования
  • pytest-asyncio библиотека-помогатор для тестирования asyncio приложений
  • pytest-cov библиотека-помогатор для измерения покрытия кода тестами

Добавим следующие строки в файл requirements.txt:

dependency-injectoraiohttppyyamlpytestpytest-asynciopytest-cov

И выполним в терминале:

pip install -r requirements.txt

Далее создаем Dockerfile. Он будет описывать процесс сборки и запуска нашего демона. Мы будем использовать python:3.8-buster в качестве базового образа.

Добавим следующие строки в файл Dockerfile:

FROM python:3.8-busterENV PYTHONUNBUFFERED=1WORKDIR /codeCOPY . /code/RUN apt-get install openssl \ && pip install --upgrade pip \ && pip install -r requirements.txt \ && rm -rf ~/.cacheCMD ["python", "-m", "monitoringdaemon"]

Последним шагом определим настройки docker-compose.

Добавим следующие строки в файл docker-compose.yml:

version: "3.7"services:  monitor:    build: ./    image: monitoring-daemon    volumes:      - "./:/code"

Все готово. Давайте запустим сборку образа и проверим что окружение настроено верно.

Выполним в терминале:

docker-compose build

Процесс сборки может занять несколько минут. В конце вы должны увидеть:

Successfully built 5b4ee5e76e35Successfully tagged monitoring-daemon:latest

После того как процесс сборки завершен запустим контейнер:

docker-compose up

Вы увидите:

Creating network "monitoring-daemon-tutorial_default" with the default driverCreating monitoring-daemon-tutorial_monitor_1 ... doneAttaching to monitoring-daemon-tutorial_monitor_1monitoring-daemon-tutorial_monitor_1 exited with code 0

Окружение готово. Контейнер запускается и завершает работу с кодом 0.

Следующим шагом мы настроим логирование и чтение файла конфигурации.

Логирование и конфигурация


В этом разделе мы настроим логирование и чтение файла конфигурации.

Начнем с добавления основной части нашего приложения контейнера зависимостей (дальше просто контейнера). Контейнер будет содержать все компоненты приложения.

Добавим первые два компонента. Это объект конфигурации и функция настройки логирования.

Отредактируем containers.py:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )

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

Сначала используем, потом задаем значения.

Настройки логирования будут содержаться в конфигурационном файле.

Отредактируем config.yml:

log:  level: "INFO"  format: "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"

Теперь определим функцию, которая будет запускать наш демон. Её обычно называют main(). Она будет создавать контейнер. Контейнер будет использован для чтения конфигурационного файла и вызова функции настройки логирования.

Отредактируем __main__.py:

"""Main module."""from .containers import ApplicationContainerdef main() -> None:    """Run the application."""    container = ApplicationContainer()    container.config.from_yaml('config.yml')    container.configure_logging()if __name__ == '__main__':    main()

Контейнер первый объект в приложении. Он используется для получения всех остальных объектов.

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

Диспетчер


Пришло время добавить диспетчер мониторинговых задач.

Диспетчер будет содержать список мониторинговых задач и контролировать их выполнение. Он будет выполнять каждую задачу в соответствии с расписанием. Класс Monitor базовый класс для мониторинговых задач. Для создания конкретных задач нужно добавлять дочерние классы и реализовывать метод check().


Добавим диспетчер и базовый класс мониторинговой задачи.

Создадим dispatcher.py и monitors.py в пакете monitoringdaemon:

./ monitoringdaemon/    __init__.py    __main__.py    containers.py    dispatcher.py    monitors.py config.yml docker-compose.yml Dockerfile requirements.txt

Добавим следующие строки в файл monitors.py:

"""Monitors module."""import loggingclass Monitor:    def __init__(self, check_every: int) -> None:        self.check_every = check_every        self.logger = logging.getLogger(self.__class__.__name__)    async def check(self) -> None:        raise NotImplementedError()

и в файл dispatcher.py:

""""Dispatcher module."""import asyncioimport loggingimport signalimport timefrom typing import Listfrom .monitors import Monitorclass Dispatcher:    def __init__(self, monitors: List[Monitor]) -> None:        self._monitors = monitors        self._monitor_tasks: List[asyncio.Task] = []        self._logger = logging.getLogger(self.__class__.__name__)        self._stopping = False    def run(self) -> None:        asyncio.run(self.start())    async def start(self) -> None:        self._logger.info('Starting up')        for monitor in self._monitors:            self._monitor_tasks.append(                asyncio.create_task(self._run_monitor(monitor)),            )        asyncio.get_event_loop().add_signal_handler(signal.SIGTERM, self.stop)        asyncio.get_event_loop().add_signal_handler(signal.SIGINT, self.stop)        await asyncio.gather(*self._monitor_tasks, return_exceptions=True)        self.stop()    def stop(self) -> None:        if self._stopping:            return        self._stopping = True        self._logger.info('Shutting down')        for task, monitor in zip(self._monitor_tasks, self._monitors):            task.cancel()        self._logger.info('Shutdown finished successfully')    @staticmethod    async def _run_monitor(monitor: Monitor) -> None:        def _until_next(last: float) -> float:            time_took = time.time() - last            return monitor.check_every - time_took        while True:            time_start = time.time()            try:                await monitor.check()            except asyncio.CancelledError:                break            except Exception:                monitor.logger.exception('Error executing monitor check')            await asyncio.sleep(_until_next(last=time_start))

Диспетчер нужно добавить в контейнер.

Отредактируем containers.py:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersfrom . import dispatcherclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )    dispatcher = providers.Factory(        dispatcher.Dispatcher,        monitors=providers.List(            # TODO: add monitors        ),    )

Каждый компонент добавляется в контейнер.

В завершении нам нужно обновить функцию main(). Мы получим диспетчер из контейнера и вызовем его метод run().

Отредактируем __main__.py:

"""Main module."""from .containers import ApplicationContainerdef main() -> None:    """Run the application."""    container = ApplicationContainer()    container.config.from_yaml('config.yml')    container.configure_logging()    dispatcher = container.dispatcher()    dispatcher.run()if __name__ == '__main__':    main()

Теперь запустим демон и проверим его работу.

Выполним в терминале:

docker-compose up

Вывод должен выглядеть так:

Starting monitoring-daemon-tutorial_monitor_1 ... doneAttaching to monitoring-daemon-tutorial_monitor_1monitor_1  | [2020-08-08 16:12:35,772] [INFO] [Dispatcher]: Starting upmonitor_1  | [2020-08-08 16:12:35,774] [INFO] [Dispatcher]: Shutting downmonitor_1  | [2020-08-08 16:12:35,774] [INFO] [Dispatcher]: Shutdown finished successfullymonitoring-daemon-tutorial_monitor_1 exited with code 0

Все работает верно. Диспетчер запускается и выключается так как мониторинговых задач нет.

К концу этого раздела каркас нашего демона готов. В следующем разделе мы добавим первую мониторинговую задачу.

Мониторинг example.com


В этом разделе мы добавим мониторинговую задачу, которая будет следить за доступом к http://example.com.

Мы начнем с расширения нашей модели классов новым типом мониторинговой задачи HttpMonitor.

HttpMonitor это дочерний класс Monitor. Мы реализуем метод check(). Он будет отправлять HTTP запрос и логировать полученный ответ. Детали выполнения HTTP запроса будут делегированы классу HttpClient.


Сперва добавим HttpClient.

Создадим файл http.py в пакете monitoringdaemon:

./ monitoringdaemon/    __init__.py    __main__.py    containers.py    dispatcher.py    http.py    monitors.py config.yml docker-compose.yml Dockerfile requirements.txt

И добавим в него следующие строки:

"""Http client module."""from aiohttp import ClientSession, ClientTimeout, ClientResponseclass HttpClient:    async def request(self, method: str, url: str, timeout: int) -> ClientResponse:        async with ClientSession(timeout=ClientTimeout(timeout)) as session:            async with session.request(method, url) as response:                return response

Далее нужно добавить HttpClient в контейнер.

Отредактируем containers.py:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersfrom . import http, dispatcherclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )    http_client = providers.Factory(http.HttpClient)    dispatcher = providers.Factory(        dispatcher.Dispatcher,        monitors=providers.List(            # TODO: add monitors        ),    )

Теперь мы готовы добавить HttpMonitor. Добавим его в модуль monitors.

Отредактируем monitors.py:

"""Monitors module."""import loggingimport timefrom typing import Dict, Anyfrom .http import HttpClientclass Monitor:    def __init__(self, check_every: int) -> None:        self.check_every = check_every        self.logger = logging.getLogger(self.__class__.__name__)    async def check(self) -> None:        raise NotImplementedError()class HttpMonitor(Monitor):    def __init__(            self,            http_client: HttpClient,            options: Dict[str, Any],    ) -> None:        self._client = http_client        self._method = options.pop('method')        self._url = options.pop('url')        self._timeout = options.pop('timeout')        super().__init__(check_every=options.pop('check_every'))    @property    def full_name(self) -> str:        return '{0}.{1}(url="{2}")'.format(__name__, self.__class__.__name__, self._url)    async def check(self) -> None:        time_start = time.time()        response = await self._client.request(            method=self._method,            url=self._url,            timeout=self._timeout,        )        time_end = time.time()        time_took = time_end - time_start        self.logger.info(            'Response code: %s, content length: %s, request took: %s seconds',            response.status,            response.content_length,            round(time_took, 3)        )

У нас все готово для добавления проверки http://example.com. Нам нужно сделать два изменения в контейнере:

  • Добавить фабрику example_monitor.
  • Передать example_monitor в диспетчер.

Отредактируем containers.py:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersfrom . import http, monitors, dispatcherclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )    http_client = providers.Factory(http.HttpClient)    example_monitor = providers.Factory(        monitors.HttpMonitor,        http_client=http_client,        options=config.monitors.example,    )    dispatcher = providers.Factory(        dispatcher.Dispatcher,        monitors=providers.List(            example_monitor,        ),    )

Провайдер example_monitor имеет зависимость от значений конфигурации. Давайте добавим эти значения:

Отредактируем config.yml:

log:  level: "INFO"  format: "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"monitors:  example:    method: "GET"    url: "http://example.com"    timeout: 5    check_every: 5

Все готово. Запускаем демон и проверяем работу.

Выполняем в терминале:

docker-compose up

И видим подобный вывод:

Starting monitoring-daemon-tutorial_monitor_1 ... doneAttaching to monitoring-daemon-tutorial_monitor_1monitor_1  | [2020-08-08 17:06:41,965] [INFO] [Dispatcher]: Starting upmonitor_1  | [2020-08-08 17:06:42,033] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET http://example.commonitor_1  |     response code: 200monitor_1  |     content length: 648monitor_1  |     request took: 0.067 secondsmonitor_1  |monitor_1  | [2020-08-08 17:06:47,040] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET http://example.commonitor_1  |     response code: 200monitor_1  |     content length: 648monitor_1  |     request took: 0.073 seconds

Наш демон может следить за наличием доступа к http://example.com.

Давайте добавим мониторинг https://httpbin.org.

Мониторинг httpbin.org


В этом разделе мы добавим мониторинговую задачу, которая будет следить за доступом к http://example.com.

Добавление мониторинговой задачи для https://httpbin.org будет сделать легче, так как все компоненты уже готовы. Нам просто нужно добавить новый провайдер в контейнер и обновить конфигурацию.

Отредактируем containers.py:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersfrom . import http, monitors, dispatcherclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )    http_client = providers.Factory(http.HttpClient)    example_monitor = providers.Factory(        monitors.HttpMonitor,        http_client=http_client,        options=config.monitors.example,    )    httpbin_monitor = providers.Factory(        monitors.HttpMonitor,        http_client=http_client,        options=config.monitors.httpbin,    )    dispatcher = providers.Factory(        dispatcher.Dispatcher,        monitors=providers.List(            example_monitor,            httpbin_monitor,        ),    )

Отредактируем config.yml:

log:  level: "INFO"  format: "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"monitors:  example:    method: "GET"    url: "http://example.com"    timeout: 5    check_every: 5  httpbin:    method: "GET"    url: "https://httpbin.org/get"    timeout: 5    check_every: 5

Запустим демон и проверим логи.

Выполним в терминале:

docker-compose up

И видим подобный вывод:

Starting monitoring-daemon-tutorial_monitor_1 ... doneAttaching to monitoring-daemon-tutorial_monitor_1monitor_1  | [2020-08-08 18:09:08,540] [INFO] [Dispatcher]: Starting upmonitor_1  | [2020-08-08 18:09:08,618] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET http://example.commonitor_1  |     response code: 200monitor_1  |     content length: 648monitor_1  |     request took: 0.077 secondsmonitor_1  |monitor_1  | [2020-08-08 18:09:08,722] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET https://httpbin.org/getmonitor_1  |     response code: 200monitor_1  |     content length: 310monitor_1  |     request took: 0.18 secondsmonitor_1  |monitor_1  | [2020-08-08 18:09:13,619] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET http://example.commonitor_1  |     response code: 200monitor_1  |     content length: 648monitor_1  |     request took: 0.066 secondsmonitor_1  |monitor_1  | [2020-08-08 18:09:13,681] [INFO] [HttpMonitor]: Checkmonitor_1  |     GET https://httpbin.org/getmonitor_1  |     response code: 200monitor_1  |     content length: 310monitor_1  |     request took: 0.126 seconds

Функциональная часть завершена. Демон следит за наличием доступа к http://example.com и https://httpbin.org.

В следующем разделе мы добавим несколько тестов.

Тесты


Было бы неплохо добавить несколько тестов. Давайте сделаем это.

Создаем файл tests.py в пакете monitoringdaemon:

./ monitoringdaemon/    __init__.py    __main__.py    containers.py    dispatcher.py    http.py    monitors.py    tests.py config.yml docker-compose.yml Dockerfile requirements.txt

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

"""Tests module."""import asyncioimport dataclassesfrom unittest import mockimport pytestfrom .containers import ApplicationContainer@dataclasses.dataclassclass RequestStub:    status: int    content_length: int@pytest.fixturedef container():    container = ApplicationContainer()    container.config.from_dict({        'log': {            'level': 'INFO',            'formant': '[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s',        },        'monitors': {            'example': {                'method': 'GET',                'url': 'http://fake-example.com',                'timeout': 1,                'check_every': 1,            },            'httpbin': {                'method': 'GET',                'url': 'https://fake-httpbin.org/get',                'timeout': 1,                'check_every': 1,            },        },    })    return container@pytest.mark.asyncioasync def test_example_monitor(container, caplog):    caplog.set_level('INFO')    http_client_mock = mock.AsyncMock()    http_client_mock.request.return_value = RequestStub(        status=200,        content_length=635,    )    with container.http_client.override(http_client_mock):        example_monitor = container.example_monitor()        await example_monitor.check()    assert 'http://fake-example.com' in caplog.text    assert 'response code: 200' in caplog.text    assert 'content length: 635' in caplog.text@pytest.mark.asyncioasync def test_dispatcher(container, caplog, event_loop):    caplog.set_level('INFO')    example_monitor_mock = mock.AsyncMock()    httpbin_monitor_mock = mock.AsyncMock()    with container.example_monitor.override(example_monitor_mock), \            container.httpbin_monitor.override(httpbin_monitor_mock):        dispatcher = container.dispatcher()        event_loop.create_task(dispatcher.start())        await asyncio.sleep(0.1)        dispatcher.stop()    assert example_monitor_mock.check.called    assert httpbin_monitor_mock.check.called

Для запуска тестов выполним в терминале:

docker-compose run --rm monitor py.test monitoringdaemon/tests.py --cov=monitoringdaemon

Должен получиться подобный результат:

platform linux -- Python 3.8.3, pytest-6.0.1, py-1.9.0, pluggy-0.13.1rootdir: /codeplugins: asyncio-0.14.0, cov-2.10.0collected 2 itemsmonitoringdaemon/tests.py ..                                    [100%]----------- coverage: platform linux, python 3.8.3-final-0 -----------Name                             Stmts   Miss  Cover----------------------------------------------------monitoringdaemon/__init__.py         0      0   100%monitoringdaemon/__main__.py         9      9     0%monitoringdaemon/containers.py      11      0   100%monitoringdaemon/dispatcher.py      43      5    88%monitoringdaemon/http.py             6      3    50%monitoringdaemon/monitors.py        23      1    96%monitoringdaemon/tests.py           37      0   100%----------------------------------------------------TOTAL                              129     18    86%

Обратите внимание как в тесте test_example_monitor мы подменяем HttpClient моком с помощью метода .override(). Таким образом можно переопределить возвращаемое значения любого провайдера.

Такие же действия выполняются в тесте test_dispatcher для подмены моками мониторинговых задач.


Заключение


Мы построили мониторинг демон на базе asyncio применяя принцип dependency injection. Мы использовали Dependency Injector в качестве dependency injection фреймворка.

Преимущество, которое вы получаете с Dependency Injector это контейнер.

Контейнер начинает окупаться, когда вам нужно понять или изменить структуру приложения. С контейнером это легко, потому что все компоненты приложения и их зависимости в одном месте:

"""Application containers module."""import loggingimport sysfrom dependency_injector import containers, providersfrom . import http, monitors, dispatcherclass ApplicationContainer(containers.DeclarativeContainer):    """Application container."""    config = providers.Configuration()    configure_logging = providers.Callable(        logging.basicConfig,        stream=sys.stdout,        level=config.log.level,        format=config.log.format,    )    http_client = providers.Factory(http.HttpClient)    example_monitor = providers.Factory(        monitors.HttpMonitor,        http_client=http_client,        options=config.monitors.example,    )    httpbin_monitor = providers.Factory(        monitors.HttpMonitor,        http_client=http_client,        options=config.monitors.httpbin,    )    dispatcher = providers.Factory(        dispatcher.Dispatcher,        monitors=providers.List(            example_monitor,            httpbin_monitor,        ),    )


Контейнер как карта вашего приложения. Вы всегда знайте что от чего зависит.

Что дальше?


Подробнее..

Пушим метрики Prometheus с помощью pushgateway

06.12.2020 04:20:10 | Автор: admin

Всё тоже, только у pushgateway пламя голубенькое в favicon


Предисловие


Данная заметка в целом о пуше метрик в pushgateway, однако, предупрежу и признаюсь сразу, что в тексте будет пример анти-паттерна пуша метрик, так как использование pushgateway рекомендуется в случае, когда сервис работает не постоянно (или у сервиса/запускаемого задания вообще нет никакого интерфейса), а значит и prometheus'у лучше в закрытые двери постоянно не стучать и не заниматься лишней работой.


Введение


Итак, pushgateway это сервис куда можно скидывать метрики, когда стандартная pull-модель prometheus'а не применима (в предисловии, я в общем описал, как такая ситуация может возникнуть и выглядеть). После того, как метрики попали в pushgateway оттуда их уже забирает prometheus и из этого вытекает несколько ограничений, связанных с пушем метрик, например, отсутствие метрики up, так как она формируется самим prometheus для опрашиваемого инстанса, а в данном случае это только pushgateway.


p.s. Хотя, если говорить о up метрике, то она и не нужна, в случае, если вы используете pushgateway бестпрактайс-способом.


Готовим prometheus к опросу pushgateway


Допустим, у нас есть вот такой compose с prometheus и pushgateway:


# ....(тут какие-нибудь графаны и т.д.)   prometheus:      restart: always      image: bitnami/prometheus:latest      links:          - pushgateway      volumes:          - ./.prom.yml:/opt/bitnami/prometheus/conf/prometheus.yml  pushgateway:      restart: always      image: bitnami/pushgateway:latest      ports:          - 9091:9091  

В данном случае prom.yml должен выглядеть как-то так, чтобы собирать данные с pushgateway:


global: nullscrape_interval: 5sscrape_timeout: 2sevaluation_interval: 15sscrape_configs:  - job_name: pushgateway    honor_labels: true    static_configs:      - targets:          - 'pushgateway:9091'

Тут всё достаточно понятно, добавили только honor_lables, который, если вкратце разрешает конфликты имён лэйблов, то есть например, если у вашего сервиса есть метрика с лэблом "X" и у pushgateway, есть лэйбл "X", то при honor_lables=false у вас будет лэйбл "X" с pushgateway и "exported_X" с вашего сервиса, который запушил метрики в pushgateway, а при значении true будут отображаться только лэйблы вашего сервиса (опять же, если будет конфликт).


p.s. Незабываем о безопасности pushgateway дока по-умолчанию рекомендует, например, использовать basic_auth.


Пушим метрики


Я бы мог привести красивый пример, соответствующий нормальной практике, однако, я подумал и решил, что давно мне минусов не ставили, потому будет пример пуша метрик из-за того, что настройка service_discovery отсутствует (в прод, понятное дело, это низя).


Итак, допустим, у нас есть воркеры Faust их много и они не в кластере (нет ни swarm, ни куберов), так же нет consul и иных способов в которые умеет prometheus, они просто спокойно запускаются в docker compose и размножаются параметром scale.


Больший ужас и крамолу, помимо пуша метрик, можно сделать рэйджировав порты, например, так:


ports:  - "9100-9200:6066"  

И загонять в конфиг prometheus таргеты со всем множеством портов.


Продолжим по коду коду. Для метрик с воркеров можно использовать уже готовое решение. Всё, что мы в данном случае сделаем это напишем небольшой таймер для того, чтобы с помощью стандартной push_to_gateway функции отправлять метрики.


async def push_metrics():      def auth_handler(url, method, timeout, headers, data):          return basic_auth_handler(url, method, timeout, headers, data, PUSHGATEWAY_USERNAME, PUSHGATEWAY_PASSWORD)      push_to_gateway(PUSHGATEWAY_URI, job=f"{WORKERS_APP_NAME}-{ENV}", registry=registry_metrics, handler=auth_handler)  @app.timer(interval=PUSH_METRICS_INTERVAL)  async def push_metrics_cron():      await push_metrics()  

Как видите тут всё достаточно просто указываем job name (при пуле метрик это делается в конфиге prometheus'а), подставляем handler для аутентификации и указываем registry из которого будут пушиться метрики. Ну и собственно всё, запускаем и при открытии pushgateway веб-морды видим, что у нас через интервал загрузились метрики, далее оттуда их заберёт ранее настроенный prometheus.


Послесловие


Заметку я решил написать, так как столкнулся с подобным в работе, сразу скажу, что способ из примера в прод не пойдёт, однако, как применение pushgateway при отсутствии service discovery, для тестирования это сойти может.

Подробнее..
Категории: Python , Devops , Monitoring , Prometheus , Metrics , Faust , Pushgateway

PostgreSQL, RED, Golden Signals руководство к действию

24.09.2020 16:22:36 | Автор: admin

Методы наблюдения Golden Signals и RED являются шаблонами при построении мониторинга сервисов и определяют ключевые метрики которые нужны при наблюдении. Раньше об этих методах знали исключительно администраторы мониторинга или SRE-инженеры. Сейчас тема инструментирования приложений уже не является чем-то новым и об этих методах знают более-менее все.

В этом посте я порассуждаю о том как в мониторинге покрыть PostgreSQL используя методы RED и Golden Signals. Подсистема мониторинга в Postgres реализована в те времена когда RED и Golden Signals еще не было и на мой скромный взгляд в ней есть некоторые недостатки и с ходу натянуть RED или Golden Signals на Postgres может показаться непростой задачей. В этом посте я постараюсь коротко рассмотреть возможности которые предоставляет Postgres для реализации наблюдения по методам RED/Golden Signals и дам конкретные направления к тому чтобы реализовать это. К тому же это на так сложно как можно подумать.

Я относительно давно знаком с RED и Golden Signals и есть несколько причин почему стоит использовать эти методы:

  • мониторинг по этим методам позволяет быстро (но при этом поверхностно) определить все ли в порядке с сервисом.

  • при наличии широкого покрытия другими метриками, при исследовании проблемы можно углубляться в нужном направлении исключая менее важные.

  • они более-менее универсальны и применимы как к веб-сервисам, так и к системным сервисам которые не ориентированы на прямую работу с пользователем.

  • являются хорошим началом чтобы закрыть базовые потребности в мониторинге для любого сервиса.

В общем случае, если перед тобой непонятный сервис который надо замониторить, то просто берем RED или Golden Signals и как по списку настраиваем сбор нужной информации и отдачу метрик. На выходе получаем базовый минимум (в виде дашборда) который в целом дает достаточное представление о том хорошо или плохо работает сервис. Далее уже можно реализовать более детальные или сервис-специфичные вещи. Но впрочем у этих методов есть и недостатки, поэтому не стоит думать что эти методы закроют все возможные потребности в метриках.

Что ж надеюсь получилось убедительно, давайте перейдем к Postgres'у.

Суть RED и Golden Signals это измерение количественных характеристик проходящего через сервис трафика, на примере RED это:

  • Request rate - количество запросов в секунду.

  • Request errors - количество ошибочных запросов в секунду.

  • Request duration - время затраченное на выполнение запросов (в идеале гистограмма с распределением количества запросов по времени выполнения).

В Golden Signals примерно всё тоже самое (и вообще он появился первым), но другими словами (Latency, Traffic, Errors), плюс там присутствует Saturation - объем работы который не может быть обслужен в данный момент, но его надо сделать, поэтому он поставлен в очередь.

Несмотря на то что оба этих метода были предложены для наблюдения за HTTP (микро)сервисами, их можно использовать и для наблюдения за другими запросо-ориентированными сервисами, включая и СУБД. Любую СУБД можно представить как сервис который обслуживает запросы от клиентов (Requests), запросы могут выполняться как успешно так и с ошибками (Errors), запросы выполняются определенное время (Duration), доступ к ресурсам осуществляется конкурентно с использованием блокировок и доступ может быть ограничен в результате чего выстроится очередь ожидающих (Saturation).

Небольшое отступление. Перед тем как продолжить, стоит определиться что будет подразумеваться под "запросом". Обычный SQL-запрос или SQL-транзакция? Под отдельным запросом будет считаться SQL-запрос, т.к. приложение оперирует именно отдельными командами и лишь при необходимости может выстраивать их в транзакции, следовательно 1 запрос = 1 SQL-команда. Также с точки зрения собственной наблюдаемости приложение может должно иметь собственные RED метрики и дополнительно снабжать каждую SQL-команду метаданными о ней (request_id, информация об отправителе, метод/контроллер и т.п.).

Requests

Начнем по порядку, R - requests. Запросы это клиентская активность, нет клиентов - нет запросов. Для наблюдения за клиентской активностью в Postgres есть несколько представлений (views). Но пока интерес представляет лишь одна из них.

pg_stat_statements. Это отдельное расширение которое нужно отдельно настроить и включить. В этом представлении собрана per-statement статистика, и для каждого statement (запроса) есть поле calls которое показывает количество вызовов этого конкретного запроса. Сумма всех calls показывает количество обработанных запросов. Важно отметить что в pg_stat_statements фиксируются только успешно выполненные запросы.

Однако с pg_stat_statements есть нюанс. У расширения есть настраиваемый режим трекинга - параметр pg_stat_statements.track указывает о том как выполнять подсчет. У параметра доступно 2 значения. Первое значение "top" указывает считать только прямые вызовы запросов. И второе значение "all" указывает считать вызовы вложенные в хранимые процедуры и функции. С точки зрения наблюдения за запросами предпочтительно иметь значение "top", т.к. если клиент отправляет запрос на вызов хранимой функции, то все вложенные в функцию запросы, выполняются на стороне СУБД и не могут считаться отдельными запросами от приложения.

Чтобы получить данные достаточно сделать довольно простой запрос к pg_stat_statements.

SELECT sum(calls) FROM pg_stat_statements;

Полученную цифру нужно обернуть в метрику с помощью тех инструментов которые приняты в конкретной экосистеме мониторинга. Например в случае Prometheus, это задача реализуется экспортером, в Zabbix это будет UserParameter.

А еще в голову может прийти мысль использовать pg_stat_activity или pg_stat_database. Отбрасываем эту мысль, pg_stat_activity не подходит для подсчета запросов, т.к. показывает снимки (snapshot) активности в момент обращения к ней, и то что происходит между обращениями остается неизвестным. Во второй же хоть и есть интересное поля типа xact_commit, но оно не совсем подходит для нашей задачи т.к. оперирует транзакциями. Впрочем, мы воспользуемся этим представлением дальше.

Errors

Для оценки количества ошибок или там скажем "запросов которые завершились ошибкой" вернемся к ранее упомянутой pg_stat_database. В этом представлении есть поле xact_rollback которое является счетчиком откатов транзакций. Откат как правило случается из-за ошибки запроса внутри транзакции, либо приложение может вызвать откат явно. Поэтому достаточно всего лишь одной ошибки внутри транзакции чтобы привести к откату всей транзакции. А сейчас важный момент, отдельно выполненная SQL-команда (даже если она явно не обернута в блок BEGIN .. END) также считается транзакцией и ошибка при выполнении команды также будет фиксироваться в xact_rollback. Отсюда следует что поля xact_rollback достаточно чтобы фиксировать ошибки при выполнении запросов.

Для получения информации опять же не требуется глубоких познаний в SQL.

SELECT sum(xact_rollback) FROM pg_stat_database;

Однако тут есть небольшой недостаток, такой подход показывает ошибки только связанные с обработкой запросов. Но в течение всего времени функционирования СУБД, могут возникать и другие ошибки не связанные с обработкой запросов. Хотя такие ошибки случаются редко, но всё равно важно знать о них. К сожалению пока в Postgres нет представления которое бы предоставляло удобный интерфейс к статистике ошибок и такая информация может быть получена только из журналов.

Duration

Для подсчета времени выполнения запросов нам снова понадобится pg_stat_statements и конкретно поле total_time. Это поле показывает в миллисекундах время выполнения (включая ожидание) для каждого типа запросов. Соответственно чтобы получить суммарное время выполнения запросов нужно сложить total_time всех запросов.

SELECT sum(total_time) FROM pg_stat_statements;

Значение будет в миллисекундах, при желании можно домножить, т.к. например в Prometheus принято приводить время к секундам. В идеале конечно хотелось бы иметь гистограмму с распределением количества запросов по временным диапазонам, но pg_stat_statements под капотом выполняется свою агрегацию и наружу отдает только агрегаты. Помимо total_time еще есть min_time, max_time, mean_time, stddev_time. Начиная с версии 13 добавлены новые поля которые показывают время планирования запросов. Но это уже DBA-specific вещи, о них может как-нибудь в другой раз.

Saturation

Последний пункт это насыщенность (saturation), которого нет в RED методе, но который присутствует в Golden Signals. Напомню что насыщенность (она же сатурация) это ситуация когда выполнение запроса отложено в очередь, следовательно в контексте обработки запросов в СУБД нам важно видеть ситуации когда запросы не обрабатываются (при этом нет и ошибок).

Немного теории

Количество одновременных подключений к базе ограничено значением параметра max_connections. Однако на практике редко кто доходит до этого ограничения, обычно проблемы начинаются раньше. Чтобы достичь состояния сатурации, достаточно выполнить два условия: 1) нужны idle транзакции 2) нужен более-менее устойчивый tps с запросами на запись внутри. Если выполнить эти два условия, то проблемная ситуация как правило выглядит так: приложение в транзакции обновляет строки в таблице, оставляет транзакцию открытой (чтоб вернуться к ней позже), но уже не возвращается. Конкурентные обновления встают в очередь и ждут когда завершится первая транзакция. Новые запросы приходят и встают в очередь вытесняя всех остальных, до тех пор пока не будет достигнут лимит max_connections, после чего все новые запросы будут отклонены с ошибкой. Либо пока первая транзакция не завершит работу сама или принудительно администратором.

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

Почему не самое лучшее?

До этого момента для снятия статистики рассматривались счетчики (COUNTER) которые в фоновом режиме накапливают информацию. Счетчики удобны тем что "не теряют" информацию (сброс счетчика или его переполнение не в счет, это явление все-таки редкое). Если значение счетчика менялось быстро или наоборот медленно это можно увидеть построив частотный график. Представление pg_stat_activity по сути представляет собой набор GAUGES (шкала) и показывает актуальные данные только в момент обращения. Следовательно неизвестно что происходило в момент между обращениями. А происходить могло много чего - например при OLTP нагрузке, в одной секунде могут быть выполнены тысячи запросов/транзакций и при работе с GAUGE мы просто этого не узнаем. Это существенный недостаток метрик типа GAUGES.

Если закрыть глаза на недостатки GAUGE, то в целом минутной гранулярности при снятии значений нам хватит чтобы фиксировать проблемы. А если есть возможность снимать значения чаще, то это хорошо. Итак нам понадобится:

  • количество и состояние клиентов (active, idle in transaction, waiting).

SELECTcount(*) FILTER (WHERE state IS NOT NULL) AS total,count(*) FILTER (WHERE state = 'idle') AS idle,count(*) FILTER (WHERE state IN ('idle in transaction', 'idle in transaction (aborted)')) AS idle_in_xact,count(*) FILTER (WHERE state = 'active') AS active,count(*) FILTER (WHERE wait_event_type = 'Lock') AS waiting,count(*) FILTER (WHERE state IN ('fastpath function call','disabled')) AS othersFROM pg_stat_activity WHERE backend_type = 'client backend';

Также потребуется информация о том как долго транзакции находятся в простое и как долго находится в ожидании самый первый в очереди. Для этого потребуются поля xact_start - время начала транзакции, и state_change - время перехода из предыдущего состояния в текущее - по сути это время перехода в active режим с последующим ожиданием.

  • максимальное время простоя внутри транзакции.

SELECT coalesce(max(extract(epoch FROM clock_timestamp() - xact_start)),0) AS max_idle_secondsFROM pg_stat_activityWHERE state IN ('idle in transaction', 'idle in transaction (aborted)');
  • максимальное время ожидания клиентов.

SELECT coalesce(max(extract(epoch FROM clock_timestamp() - state_change)),0) AS max_idle_secondsFROM pg_stat_activityWHERE wait_event_type = 'Lock';

Как вы могли заметить здесь запросы уже чуть подлиннее предыдущих, но в целом ничего сложного. Все полученные значения также нужно обернуть в метрики. Через метрики насыщенности важно:

  • отслеживать массовые появления состояний idle in transactions и waiting и оперативно устранять причины их появления.

  • отслеживать любое даже единичное появления долгих idle транзакций.

  • отслеживать появление долгого ожидания клиентов.

Итого

Чтобы добавить метрики для наблюдения за Postgres'ом по методам RED или Golden Signals понадобится базовое знание SQL и несколько представлений. Нужные источники данных находятся в разных представлениях, что слегка неудобно, но и не так страшно. Итак, request rate берется на основе pg_stat_statements.calls. Request errors на основе pg_stat_database.xact_rollback. Request duration на основе pg_stat_statements.total_time. Saturation на основе state, wait_event_type, xact_start, state_change из pg_stat_activity.

На выходе у вас должно получиться 6 метрик, на основе которых можно составить небольшой обзорный дашборд из пары-тройки панелей и графиков которые в будущем можно снабдить drilldown-ссылками на более детальные дашборды/графики. По сути это отправная точка начиная с которой можно двигаться дальше и постепенно расширять мониторинг Postgres'а.

Примерно в таком ключе можно организовать дашборд.Примерно в таком ключе можно организовать дашборд.

Как пользоваться таким дашбордом?

  1. смотрим на Requests. Если их меньше или больше обычного, ищем причины почему так. Откуда и почему пришла нагрузка, не сломался ли кэш или наоборот почему так мало нагрузки, живы ли приложения.

  2. смотрим на Errors. Нету ошибок хорошо, есть ошибки - повод заглянуть в кибану/логи и посмотреть что за ошибки и устранить их.

  3. смотрим на Duration. Если растет время, идем разбираться с запросами. Какие запросы выполняются дальше остальных и почему.

  4. смотрим на Saturation. Появились idle транзакции или waiting и ползут вверх, идем в БД и разбираемся откуда они. Для системного решения скорей всего придется чинить приложение, в качестве временного ad-hoc решения принудительно завершаем idle транзакции.

Вот как-то так.

Еще добавлю что мы в Weaponry отслеживаем эти вещи и если ваш Postgres злоупотребляет ошибками, idle транзакциями или блокировками, то Weaponry подскажет что делать.

Если вы еще хотите узнать что-то о мониторинге около-Postgres'а, пишите об этом в комментариях.

Подробнее..
Категории: Postgresql , Monitoring , Sre , Admin , Golden signals , Red method

PgSCV экспортер метрик для PostgreSQL

27.05.2021 12:14:32 | Автор: admin

Всем привет. В этом посте я расскажу про pgSCV - новый экспортер метрик для PostgreSQL (и не только), чем он так хорош и какие проблемы решает.

Наверняка все кто используют Prometheus и PostgreSQL сталкивались и с postgres_exporter. Этот экспортер довольно легко запуститьи начать им пользоваться. Также у него есть возможности для расширения, на основе своего запроса можно описать метрики иснимать их. Если есть хорошие знания о том как устроена постгресовая статистика можно собрать довольнобольшое количество метрик. Но как известно кроме метрик самого Postgres, еще желательно собирать метрики системы, а если винфраструктуре есть вспомогательные сервисы, например пулеры соединений (pgbouncer, odyssey и т.п.), то и с них также нужно сниматьметрики. Выходит что нужно поставить еще экспортеров.

В pgSCV я постарался решить обе этих проблемы.

Решение первое. pgSCV сразу умеет снимать очень большое количество метрик с PostgreSQL без необходимости дополнительной настройки. На мой взгляд это сильно облегчает задачу первоначального запуска. Вместо траты времени на написание кастомной конфигурации для съема дополнительных метрик их сразу можно получить из коробки. Возможности конфигурации кастомных метрик также присутствует. Возникает резонный вопрос - а что если метрик слишком много и не все они нужны? В таком случае, можно отключить сбор метрик или ограничить список БД с которых требуется снимать метрики.

Второе решение. На данный момент pgSCV умеет снимать метрики с системы, PostgreSQL и Pgbouncer. Для этого он автоматически ищет эти сервисы и начинает собирать с них метрики. Очевидно что для сбора метрик с сетевых служб нужны реквизиты для подключения. Съем метрик не ограничивается только локальными службами. При желании можно указать сбор метрик и с сервисов размещенных на других узлах.

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

curl -O -L https://github.com/weaponry/pgscv/releases/download/v0.5.0/pgscv_0.5.0_linux_amd64.tar.gztar xvzf pgscv_0.5.0_linux_amd64.tar.gzcat << EOF > pgscv.yamldefaults:    postgres_username: "monitoring"    postgres_password: "supersecretpassword"EOF./pgscv --config-file pgscv.yaml

После запуска можно открыть вторую консоль и с помощью curl -s 127.0.0.1:9890/metrics получить список метрик.

Отмечу, что pgSCV создавался для нужд Weaponry (проект по мониторингу PostgreSQL и всего вокруг него), теперь pgSCV на мой взгляд стабилизировался и мне не стыдно его показать.

На этом всё, спасибо за внимание! Если есть идеи, пожелания или нашлись баги, то пишите в discussions или issues. Напоследок немного ссылок:

Подробнее..

Перевод RED-метод для анализа производительности MySQL

12.08.2020 18:08:51 | Автор: admin
Перевод статьи подготовлен в преддверии старта курса DevOps практики и инструменты.



Метод RED (Rate, Errors, Duration) является одним из популярных подходов к мониторингу производительности. Он часто применяется для мониторинга микросервисов, хотя ничего не мешает использовать его для баз данных, таких как MySQL.

В Percona Monitoring and Management (PMM) v2 вся необходимая информация собирается в базу данных ClickHouse, и дальше уже дело техники с помощью встроенного источника данных ClickHouse создать дашборд для визуализации метрик.

При создании дашборда помимо панелей для RED были добавлены несколько дополнительных панелей, чтобы показать некоторые интересные вещи, которые можно сделать с Grafana + ClickHouse в качестве источника данных и информацией, которую мы храним о производительности запросов MySQL.

Давайте посмотрим на дашборд внимательнее.



Мы видим классические панели RED-метода, показывающие Query Rate (количество запросов в секунду), Error Rate (количество ошибок), а также среднее значение и 99ый процентиль Query Latency (время выполнения запросов) для всех узлов системы. На панелях ниже отображается информация по конкретным узлам, что очень полезно для сравнения их производительности. Если один из узлов начнет работать не так, как остальные аналогичные узлы, то это повод для расследования.

С помощью фильтров (Filters в верхней части дашборда) вы можете просматривать только нужные вам данные. Например, можно выбрать только запросы схемы sbtest для хостов, расположенных в регионе datacenter4:



Такая ad-hoc фильтрация очень удобна. Вы можете использовать в фильтрах регулярные выражения, искать по конкретному QueryID, анализировать запросы от конкретных клиентских хостов и т. д. Описание колонок, доступных в ClickHouse, есть в посте Advanced Query Analysis in Percona Monitoring and Management with Direct ClickHouse Access.

Из большинства панелей вы можете быстро перейти в Query Analytics (анализ запросов) для просмотра подробной информации о производительности запросов, или, если вы заметили у одного из хостов что-то необычное, то через Data Links можете посмотреть запросы этого хоста нажмите на график и перейдите по выделенной ссылке:



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

Мы познакомились с панелями RED-метода. Теперь давайте посмотрим на дополнительные панели (Additional Dashboards) в этом дашборде.



Row Based Efficiency (эффективность на основе строк) показывает, сколько строк было проанализировано на каждую возвращенную или измененную строку. Как правило, значения больше 100 указывают на плохие индексы или на очень сложные запросы, которые считывают много данных, а возвращают только несколько строк. Оба этих случая требуют анализа.

Time-Based Efficiency (эффективность на основе времени) основана на той же математике, но смотрит на время выполнения запроса, а не на количество сканированных строк. Это позволяет выявлять проблемы, связанные с медленным диском или конфликтующими запросами. Как правило, от высокопроизводительной системы следует ожидать доли миллисекунды на отправку строки клиенту или на ее изменение. Запросы, которые возвращают или изменяют много строк, будут иметь более низкое значение.

Queries Per Host (количество запросов по хостам) говорит само за себя и рядом с ним очень полезно видеть Query Load Per Host (нагрузку по хостам), которая показывает количество одновременных активных запросов. Здесь мы можем видеть, что несмотря на то, что у mysql4 не самое большое количество запросов (query rate), но у него самая большая нагрузка и наибольшее среднее количество активных запросов.
Размышляя о том, какие еще метрики могут быть полезны, я добавил следующие дополнительные панели:



Эти панели разделяют Query Processing Efficiency на READ-запросы (которые возвращают строки) и WRITE-запросы (у которых есть row_affected).

QueryTime Based Efficiency это то же самое, что описано выше, только с акцентом на определенные виды запросов.

Data Crunching Efficiency (эффективность обработки данных) это несколько другой взгляд на те же данные. Здесь показано сколько строк анализируется (examined) запросом в сравнении с временем выполнения запроса. Это, с одной стороны, показывает вычислительную мощность системы. Система с большим количеством ядер, имеющая все данные в памяти, может обрабатывать миллионы строк в секунду и выполнять много работы. Но это не говорит об эффективности запросов. На самом деле, системы, которые быстро обрабатывают много данных, часто выполняют много операций полного сканирования таблиц.

Наконец, есть несколько списков с запросами.



Частые запросы, самые медленные запросы (по среднему времени выполнения), запросы, вызывающие наибольшую нагрузку, и запросы, которые завершились с ошибкой или предупреждением. Вы также можете увидеть эти запросы и в Query Analytics, но я хотел показать их здесь для примера.

Заинтересовались? Вы можете установить дашборд в Percona Monitoring and Management (PMM) v2 с Grafana.com.



От кода до kubernetes


Подробнее..

Профилирование в продакшене для поиска узких мест на сервере

08.02.2021 16:12:50 | Автор: admin

Я работаю техлидом в команде System, которая отвечает за производительность и стабильность сервиса. С марта по ноябрь 2020 года Miro вырос в семь раз до 600+ тысяч уникальных пользователей за сутки. Сейчас наш монолит работает на 350 серверах, около 150 инстансов мы используем для хранения данных пользователей.

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

Часть первая: постановка задачи и вводные

В моем понимании любое приложение можно представить в виде модели: она состоит из задач и обработчиков. Задачи выстраиваются в очереди и исполняются последовательно, как на рисунке ниже:

Не все согласны с такой постановкой проблемы: кто-то скажет, что на RESTful серверах нет очередей только хэндлеры, методы обработки запросов.

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

В Miro для поддержки коллаборации на доске мы используем WebSocket соединение, а сам сервер состоит из множества очередей задач. Есть очередь на прием данных, на процессинг, на запись обратно в сокеты или персистент. Соответственно, есть очереди и есть обработчики.

Опыт показывает, что очереди всегда есть на этом фундаменте строится весь кейс.

Что мы искали и что нашли

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

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

Вторая ошибка: искали среднее время выполнения задачи. Если измерять размер очереди смысла нет, можно рассчитать среднее время на выполнение задачи. Но в результате мы получаем цифру, которая не несет в себе полезной информации. Ниже объясню, почему.

Анализ ошибок показал, что искать нужно не среднее арифметическое, а медианное значение времени, за которое выполняется задача. Медиана помогает очертить круг задач, которые заслуживают внимания, и отбросить аномальные отклонения.

В нашем случае больше подошел перцентиль. Он помог разбить все процессы на два типа: аномалии (1%) и задачи, которые укладываются в общую картину (99%).

Перцентиль помог осознать третью ошибку: не нужно пытаться решить все проблемы с очередями. Нужно сосредоточиться только на тех, которые напрямую влияют на пользовательские действия (users action).

Поясню: отсечение 2% аномалий помогло нам сосредоточиться на оптимизации процессов, с которыми сталкивается абсолютное большинство пользователей, а не единицы тех, кто зашел с медленного интернета. В результате мы улучшили UX повысили продуктовую метрику, а не техническую. Это очень важный момент.

Часть вторая: решение проблемы

В предыдущем разделе мы определили метод поиска узких мест. Теперь найдём самую медленную часть задачи.

Опыт показывает, что время, за которое задача выполняется, можно разбить на две части: когда мы что-то считаем и когда процессор ждет завершения операции input/output (IO).

Ошибки происходят и в первой части процесса, но в этом кейсе речь не о них. Интерес представляет вторая часть период ожидания ответа от базы данных. К нему, например, относится отправка данных по сети и ожидание выполнения SQL-запросов от базы данных.

На этом этапе у нас должна быть возможность вклиниться в слой абстракции (data access layer, DAL) и написать участок кода, который может быть вызван перед началом операции и по ее завершении. Другими словами, функция должна быть наблюдаемой (observable).

Рассмотрим пример: в Miro мы используем jOOQ для работы с SQL. В библиотеке есть листенеры: они позволяют написать код на каждый SQL-запрос, который будет выполняться перед запросом и после него. В Redis используется сторонняя библиотека, которая не позволяет добавлять листнеры. В этом случае можно написать свой DAL для доступа. Другими словами, вместо прямого использование библиотеки к коде, можно прикрыть её своим интерфейсом. А у же в его реализации обеспечить вызовы необходимых нам обработчиков.

Тот же паттерн хорошо работает с RESTful приложением, когда функциональный или бизнес-метод обернуты в листенеры. В этом случае

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

Проиллюстрируем этот процесс на примере нашего дашборда. Мы профилируем конкретную задачу и получаем как общее время ее выполнения, так и время, которое было потрачено на запросы в SQL и в Redis. Мы также можем поставить различные time-counters: например, в разрезе команд, отправляемых в Redis .

Информация по выполнению каждого запроса дублируется в Prometheus и Jaeger. Зачем нам две системы? Графики наглядные, а логи детальные. Системы дополняют друг друга.

Разберем на примере: есть команда на открытие доски Miro, ее длительность напрямую зависит от размера доски. На графике мы технически не можем показать, что маленькие доски открываются быстро, а большие медленно. Зато Prometheus в реальном времени показывает аномалии, на которые можно быстро среагировать.

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

Stack trace для частных случаев

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

Добавление data access layers дало возможность снимать stack trace. Это позволяет трейсить запросы только от определенной базы данных, для конкретного end point или команды Redis.

Мы можем снимать stack trace с каждой десятой или сотой операции и написать логи, тем самым снизив нагрузку. Выборочно обрабатывать отчеты нетрудно сложность в том, как визуализировать полученную информацию в понятном виде, чтобы ей было удобно пользоваться.

В Miro мы отправляем stack traces в Grafana, предварительно удаляя из dump все third-party библиотеки и формируем значение метрики как результат конкатенации части дампа. Выглядит это так: после перечисленных манипуляций лог projects.pt.server.RepositoryImpl.findUser (RepositoryImpl.java:171) превращается в RepositoryImpl.findUser:171.

WatchDog для постоянного мониторинга

Снятие stack trace дорогое исследование, держать его активным постоянно не получится. Кроме того, в отчетах генерируется слишком много информации, обработать которую сложно.

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

Иногда задачи зависают вместо 100 миллисекунд выполняются 5 секунд. Для таких случаев у WatchDog есть свой thread, который периодически проверяет статус задачи и снимает stack trace.

На практике это выглядит так: если через 5 секунд задача еще висит, мы видим это в логе stack trace. Кроме того, система посылает alert, если задача висит слишком долго например, из-за deadlock на сервере.

Вместо заключения

В марте 2020 года, когда началась самоизоляция, число пользователей Miro росло на 20% каждый день. Все описанные фичи мы написали за несколько дней, они не были очень трудоемкими.

По сути, мы создали велосипед на рынке есть готовые продукты, которые решают нашу проблему. Но все они стоят дорого. Главная цель этого текста показать простой инструмент, который можно быстро собрать на коленке. Он не уступает большим и дорогим решениям и поможет небольшим проектам пережить быстрое масштабирование.

Подробнее..
Категории: Java , Monitoring , Observability

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru