Мониторинг базы данных Oracle через ODBC в Zabbix

    image
    В статье будет рассмотрена возможность мониторинга база данных по средствам встроенной в Zabbix поддержке ODBC, c использованием автообнаружения объектов.

    Для начала рассмотрим доступные для Zabbix методы мониторинга БД, которые использовались до поддержки ODBC.
    Так как статья про мониторинг Oracle, то и будем смотреть в этом разрезе.

    1. Использования скрипта zabora

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

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

    2. Orabbix или DBforBIX

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

    Недостатки:
    — не поддерживает параметры, то есть на каждую метрику создается отдельный запрос.
    Представьте у вас 10 tablespace'ов и вам нужно снимать с каждого 4 параметра — получается 40 запросов в файле. Интервал запроса получение метрики, так же выставляется в конфиге, что не очень удобно.

    Попробовав все эти решения решил использовать поддержку ODBC в Zabbix, и вот почему:
    • запрос к БД — стандартный ключ Zabbix, из этого следует, что мы настраиваем такие параметры как частота опроса в самом интерфейсе
    • редактирование запросов в интерфейсе Zabbix
    • позволяет использовать макросы
    • самое главное позволяет автоматизировать процесс добавления новых объектов на мониторинг


    Сначала опишу, что имеется в хозяйстве:

    1. 6 баз данных Oracle — 1 БД — 1 сервер + 1 резервный сервер под БД итого: получается 12 серверов.
    2. Сервера для каждой БД объединены в кластер — итого 6 кластеров
    3. На каждом сервера установлен Zabbix agent для AIX
    4. На каждом сервере по скрипту zabora

    Конфигурация Zabbix мониторинга:
    1. Zabbix сервер на CentOS 6.5 + TokuDB — 20 000 элементов — 380 nps (новых значений в секунду)
    2. Специально для мониторинга БД, был поднят Zabbix Proxy, так как запросы могут выполнятся достаточно долго, то не хотелось бы из-них подвешивать процессы сбора данных основного Zabbix'a — тоже CentOS 6.5 + TokuDB


    В этой статье я не буду касаться настройки TokuDB, так как планирую еще одну статью почему мы перешли с InnoDB на TokuDB, и что нам это дало.

    Установка Oracle Instant Client



    Сначала необходимо установить Oracle Instant Client на машину с Zabbix Proxy:

    У нас используется Oracle 11g, поэтому скачиваем RMP пакеты соответствующей версии с сайта Oracle.
    Нам необходимы:
    • oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm — основные библиотеки
    • oracle-instantclient11.2-jdbc-11.2.0.4.0-1.x86_64.rpm — драйвера для java, для нашей задачи не нужны, но в хозяйстве пригодиться :)
    • oracle-instantclient11.2-sqlplus-11.2.0.4.0-1.x86_64.rpm — клиент SQLplus
    • oracle-instantclient11.2-odbc-11.2.0.4.0-1.x86_64.rpm — библиотека для работы через ODBC
    • можно еще до кучи: oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm :)


    в той папке в которую скачали все эти файлы делаем:
    # rpm -i oracle-*.rpm


    Настройка SQLplus для доступа к БД Oracle.



    Для того чтобы клиент работал, необходимо в параметры окружение выставить необходимые переменные, для начала выставим их в своем профиле, прописав в файл $HOME/.bash_profile:
    ORACLE_HOME=/usr/lib/oracle/11.2/client64
    LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib64:$LD_LIBRARY_PATH
    TNS_ADMIN=$ORACLE_HOME/network/admin>
    
    PATH=$PATH:$ORACLE_HOME/bin:$HOME/bin
    
    export ORACLE_HOME
    export LD_LIBRARY_PATH
    export TNS_ADMIN
    export PATH
    


    Перелогиниваемся и смотрим есть ли наши переменные в
    # env

    Обратим внимание на переменную TNS_ADMIN=$ORACLE_HOME/network/admin
    Этот путь необходимо создать, туда мы положим файл tnsnames.ora который используется библиотеками клиента для подключения к БД.

    Создадим подключение к БД с именем TESTDB например.
    #cat $ORACLE_HOME/network/admin/tnsnames.ora

    TESTDB =
      (DESCRIPTION =
          (ADDRESS = (PROTOCOL = TCP)(HOST = oratestdb)(PORT = 1521))
          (CONNECT_DATA =
            (SERVER = DEDICATED)
            (SERVICE_NAME = testdb)
          )
    )
    


    Необходимо подставить нужные значения в HOST и SERVICE_NAME.
    HOST — можно прописывать IP адрес или DNS имя (проверьте только, что оно ресолвится в IP)

    Проверим настройку клиента, только предварительно создайте учетную запись zabbix в Oracle.
    # sqlplus zabbix/zabbix@TESTDB

    SQL*Plus: Release 11.2.0.4.0 Production on Sat May 24 10:47:09 2014
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    
    Connected to:</code>
    Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    
    SQL>
    


    Видим, что клиент выдал приглашение, значит соединение прошло успешно, и совсем чтобы быть уверенными сделаем простенький запрос:
    SQL> select banner from v$version where rownum=1;

    BANNER
    --------------------------------------------------------------------------------
    Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    
    SQL>
    


    Конфигурация ODBC.



    Официальные пакеты Zabbix Server и Zabbix Proxy в СentoOS скомпилированы с поддержкой unixODBC, поэтому после их установки у вас должен быть установленный пакет unixODBC, проверяем:
    # yum info *ODBC

    Вывод должен содержать следующие пакеты: unixODBC и oracle-instantclient11.2-odbc.

    Правим файлы:
    # cat /etc/odbcinst.ini

    [OracleDriver]
    Description=Oracle ODBC driver for Oracle 11g
    Driver=/usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1
    

    И сразу делаем такую проверку:
    # ldd /usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1

    ldd: warning: you do not have execution permission for `/usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1`
          linux-vdso.so.1 =>  (0x00007fff1a58f000)
          libdl.so.2 => /lib64/libdl.so.2 (0x00007f89d6d4d000)
          libm.so.6 => /lib64/libm.so.6 (0x00007f89d6ac8000)
          libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f89d68ab000)
          libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f89d6692000)
          libclntsh.so.11.1 => /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1 (0x00007f89d3d22000)
          libodbcinst.so.1 => /lib64/libodbcinst.so.1 (0x00007f89d3b11000)
          libc.so.6 => /lib64/libc.so.6 (0x00007f89d377d000)
          /lib64/ld-linux-x86-64.so.2 (0x00007f89d711c000)
          libnnz11.so => /usr/lib/oracle/11.2/client64/lib/libnnz11.so (0x00007f89d33af000)
          libaio.so.1 => /lib64/libaio.so.1 (0x00007f89d31ae000)
          libltdl.so.7 => /usr/lib64/libltdl.so.7 (0x00007f89d2fa5000)
    


    C большой долей вероятностью, вы получите libodbcinst.so.1 => not found, поэтому нужно сделать сим-линк:
    # ls -lah /lib64 | grep odbc 

    lrwxrwxrwx.  1 root root    31 May 18 00:45 libodbcinst.so.1 -> /usr/lib64/libodbcinst.so.2.0.0 
    lrwxrwxrwx.  1 root root    16 May 20 11:41 libodbcinst.so.2 -> libodbcinst.so.1 
    


    Дальше редактируем файл:
    # cat /etc/odbc.ini

    [ORA_TESTDB]
    Driver= OracleDriver
    DSN= TESTDB
    ServerName= TESTDB
    UserID= zabbix
    Password= zabbix
    


    После этого у нас должно получится подключится к БД Oracle через клиент ODBC (всегда используйте параметр -v, если будет ошибка подключения, скажет детально в чем проблема):
    # isql -v ORA_TESTDB

    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  
    |                                       |
    +---------------------------------------+
    SQL>
    


    Так же для очистки совести, что у нас все работает, делаем запрос:
    SQL> select banner from v$version where rownum=1;
    +---------------------------------------------------------------------------------+
    | BANNER                                                                          |
    +---------------------------------------------------------------------------------+
    | Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production    |
    +---------------------------------------------------------------------------------+
    SQLRowCount returns -1
    1 rows fetched
    SQL>
    


    Поздравляю, Вы настроили ODBC.

    Теперь нам необходимо добиться, чтобы Zabbix Proxy так же мог делать запросы через ODBC.

    Для этого необходимо, чтобы в окружение процесса zabbix_proxy были доступны переменные, указанные выше, для это добавим в файл:
    # cat /etc/init.d/functions

    # Set up a default search path.
    PATH="/sbin:/usr/sbin:/bin:/usr/bin"
    
    ORACLE_HOME=/usr/lib/oracle/11.2/client64
    LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib64:$LD_LIBRARY_PATH
    TNS_ADMIN=$ORACLE_HOME/network/admin</code>
    
    PATH=$PATH:$ORACLE_HOME/bin:$HOME/bin</code>
    
    export ORACLE_HOME
    export LD_LIBRARY_PATH
    export TNS_ADMIN
    export PATH
    


    После этого обязательно перезапускаем zabbix_proxy:
    # service zabbix-proxy restart


    Теперь мы сразу перейдем к настройке правил автообнаружения в терминологии Zabbix — это low level discovery rule.

    Что такое LLD?
    В принципе это любой элемент в Zabbix который может вернуть данные в JSON формате.
    Так встроенный мониторинг баз данных в Zabbix всегда возвращает только 1 колонку и 1 строку. Почему-то в команде Zabbix до сиз пор не напишут для БД генератор LLD.

    Кому нужна эта фича, просьба проголосовать.

    Придется написать скрипт который будет выдавать нам список объектов в JSON формате.

    Шаблон и скрипт можно взять на GitHub

    Скрипт написан на php, поэтому любителям bash прошу отвернуться в сторону :)
    Комментировать сам скрипт не буду, думаю по коду все понятно, скажу только, что его нужно положить в папку которая задана в конфиге zabbix_proxy.conf (или zabbix_server.conf):
     ExternalScripts=/usr/lib/zabbix/externalscripts

    Скрипт oracle.odbc.discovery
    #!/usr/bin/php
    <?php
    
      if(!isset($argv[1]) && !isset($argv[2])) exit("ZBX_NOTSUPPORTED");
    
      $connected_dsn = odbc_connect($argv[1],"","");
    
      if(!$connected_dsn) exit('SQL connection erorr | ZBX_NOTSUPPORTED');
    
      switch ($argv[2]) {
          case "tablespaces":
              $result=odbc_exec($connected_dsn,"SELECT tablespace_name FROM dba_tablespaces;");
              $tablespaces = array("data"=>array());
    
              while(odbc_fetch_row($result)){
                   $tablespaces['data'][]=array('{#TBSNAME}'=>odbc_result($result,1));
              }
    
              echo json_encode($tablespaces);
              break;
    
          case "jobs":
              $result=odbc_exec($connected_dsn,"SELECT job_name, owner FROM dba_scheduler_jobs WHERE state != 'DISABLED';");
    
              $jobs = array("data"=>array());
    
              while(odbc_fetch_row($result)){
                   $jobs['data'][]=array(
                                            '{#JOBNAME}'=>odbc_result($result,1),
                                            '{#JOBOWNER}'=>odbc_result($result,2));
              }
    
              echo json_encode($jobs);
              break;
      }
    
    exit();
    ?>
    



    Скрипту передаются два параметра:
    1. DSN — который вы указали в файле /etc/odbc.ini в квадратных скобках, в случае примера это ORA_TESTDB
    2. тип объектов, список которых нужно вернуть: tablespaces или jobs

    В случае jobs, скрипт вернет так же и {#JOBOWNER}, то есть владельца job'a.

    Добавьте права на выполнения на скрипт и попробуйте его запустить:
    # /usr/lib/zabbix/externalscripts/oracle.odbc.discovery ORA_TESTDB tablespaces, скрипт вернет примерно вот такой массив:
    {
        "data": [
            {
                "{#TBSNAME}": "SYSTEM"
            },
            {
                "{#TBSNAME}": "SYSAUX"
            },
            {
                "{#TBSNAME}": "UNDOTBS1"
            },
            {
                "{#TBSNAME}": "TEMP"
            },
            {
                "{#TBSNAME}": "USERS"
            }
        ]
    }
    


    # /usr/lib/zabbix/externalscripts/oracle.odbc.discovery ORA_TESTDB jobs

    {
        "data": [
            {
                "{#JOBNAME}": "PURGE_LOG",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "ORA$AUTOTASK_CLEAN",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "DRA_REEVALUATE_OPEN_FAILURES",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "BSLN_MAINTAIN_STATS_JOB",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "RSE$CLEAN_RECOVERABLE_SCRIPT",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "SM$CLEAN_AUTO_SPLIT_MERGE",
                "{#JOBOWNER}": "SYS"
            },
            {
                "{#JOBNAME}": "RLM$EVTCLEANUP",
                "{#JOBOWNER}": "EXFSYS"
            },
            {
                "{#JOBNAME}": "RLM$SCHDNEGACTION",
                "{#JOBOWNER}": "EXFSYS"
            }
        ]
    }
    


    Наконец-то переходим к добавлению мониторинга БД Oracle в Zabbix.

    Для начала пару слов о шаблоне:
    1. общие ключи мониторинга Oracle взяты из скрипта zabora
    2. чтобы шаблона заработал необходимо во вкладе Макросы самого хоста, добавить 3 пользовательских макроса:
    — {$DSN1} — DSN который прописан в квадратных скобках файла /etc/odbc.ini (в примере ORA_TESTDB)
    — {$ORA_USER} — пользователь с правами которого будет подключение к БД Oracle
    — {$ORA_PASSWORD } — пароль для подключения к БД Oracle





    Итак список правил LLD:


    Чтобы правила отработали в первый раз, выставите в самих правила интервал, предположим 300 секунд, и через 5 минут у вас в элементах данных должны создаться новые.

    Рассмотри сами правила и начнем с Tablespaces.


    В принципе здесь все понятно, хочу обратить внимание на поле «Фильтр».
    С помощью этого поля можно производить фильтрацию списка который возвращает нам сам элемент, в нашем примере нам не нужно добавлять на мониторинг системные tablespaces. Фильтрация происходит на основе правила regexp. Как видно на картинки поле {#TBSNAME} должно соответствовать правилу regexp Oracle System Excluded Tablespaces. Общие правила regexp описываются в Администрирование > Общие > Регулярные выражения и вызываются в фильтре через символ @.



    Аналогично все и для job'ов:



    Переходим к прототипам данных



    Сам прототип


    Картинка говорит сама за себя, но хочу обратить на один нюанс, а именно на поле «Единица измерения», по умолчанию в Zabbix используется 10-тичная система исчисления, что и следовало ожидать, поэтому все приставки Кило, Мега, Гига и т.д. это деление на 1000, что с точки зрения исчисления объема данных не совсем корректно, поэтому чтобы вы получали во вкладке «Последние данные» адекватные значения в Zabbix используется «специальные» единицы измерения: B и Bps — байт и байт в секунду (подробнее).
    Но есть забавный момент (баг), в последних данных приставки K(ilo), M(ega), G(iga) переводятся в K, М, Г, а вот сама единица нет, поэтому в случае с гигабайтами у Ваc будет ГB.

    Прототипы триггеров для tablespaces:


    Диапазоны следующие:
    • при размере меньше 3ТБ ограничение в процентах
    • от 3ТБ до 10ТБ в гигабайтах
    • от 10ТБ в гигабайтах


    Обратить внимание, что значения в условиях используется в байтах, а также обратить на порядок и используемых значений.
    На первый взгляд может показаться лишним условие «Максимальный размер > 0»

    Но это сделано для того чтобы приходило более информативное письмо для DBA.
    В действиях вы указываете:
    1. {ITEM.NAME1} ({HOSTNAME1}:{TRIGGER.KEY1}): {ITEM.VALUE1}
    2. {ITEM.NAME2} ({HOSTNAME1}:{TRIGGER.KEY2}): {ITEM.VALUE2}
    3. {ITEM.NAME3} ({HOSTNAME1}:{TRIGGER.KEY3}): {ITEM.VALUE3}
    


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

    При таких настройках действия, Вам будет приходить нечто подобное:
    1. Текущий размер tablespace BG_Z_LOB_TBS (ODB.odbc.select[tbs_size_BG_Z_LOB_TBS,ORA_ODB]): 2 GB 
    2. Осталось свободного места в процентах в tablespace BG_Z_LOB_TBS (ODB.odbc.select[tbs_used_percent_BG_Z_LOB_TBS,ORA_ODB]): 99 %
    3. Максимально возможный размер tablespace BG_Z_LOB_TBS (ODB.odbc.select[tbs_maxsize_BG_Z_LOB_TBS,ORA_ODB]): 32 GB
    


    Прототипы данных для job'ов:


    Прототипы триггеров для job'ов:


    Триггеры срабатывают если:
    • время выполнения job'a более 720 минут
    • если job завершился со статусом не равным «SUCCEEDED»


    Приятных Вам обнаружений в БД Oracle :)
    • +9
    • 35.6k
    • 7
    Share post

    Comments 7

      +1
      Как и обещал на Zabbix Meetup, выкладываю SQL-запрос для дискавери, например, табличных пространств:
      WITH tablespaces AS (
        SELECT DISTINCT '{"{#TBSNAME}":"' || tablespace_name || '"}' AS json FROM dba_data_files
      )
      SELECT '{"data":[' || (
        SELECT LISTAGG(json, ',') WITHIN GROUP (ORDER BY 1) FROM tablespaces
      ) || ']}' from  dual;
      

      Следует иметь в виду, что функция listagg появилась только в Oracle 11.2, поэтому с более ранними версиями такой фокус не пройдёт.
        +1
        Антон, спасибо!

        Согласись, что родная функция в Zabbix 3.0 будет удобнее и не во всех базах такое можно будет провернуть, а ODBC это как раз попытка универсального доступа к разным базам?
          +1
          Конечно, соглашусь. Я и позиционирую это решение как временное, пока не выйдет Zabbix 3.0. Учитывая, что контекстные макросы дадут возможность более гибко настраивать пороги триггеров, в третьей версии мониторинг через ODBC шагнёт далеко вперёд. Всего-то и останется желать, что persistent connection и bulk requests. =)
            +1
            Тогда жмякай support.zabbix.com/browse/ZBXNEXT-2485 — vote :)
            А bulk requests это как ты себе представляешь? просто если процесс не будет закрывать коннект, он просто последовательно их фигарить
              0
              Пожмякал =)
              Под bulk request я имею в виду одновременный сбор нескольких однотипных данных, чтобы:
              1) получать консистентные «срезы»;
              2) уменьшить количество запросов (чтобы не бегать по одной и той же таблице несколько раз, например).
              Persistent connection избавит нас от проблемы большого количества соединений к базе, но не от перечисленного выше.

              Сейчас я скриптом запрашиваю что-то типа
              SELECT tablespace_name, SUM(bytes) FROM dba_data_files GROUP BY tablespace_name;
              

              а потом zabbix_sender'ом отсылаю на trapper items, сгенерированные LLD. Хочется нативного механизма, причём не только для ODBC проверок.
                +1
                Это вопрос поднимал Илья Аблеев, когда Алексей приезжал месяца полтора назад. Он просил его сделать пассивный zabbix multi Item.
                То есть когда ты дергаешь например system.run[], а он тебе возвращает данные в формате которые ты формируешь для zabbix sender.
                Но понимаешь какая тут проблема именно в архитектуре заббикса, что метрика должна быть создана, то есть тебе предварительно все равно траппер элементы создавать надо — этой какой костыль получается. И предположим как тут считать когда элемент стал не поддерживаемым когда например он вернул несколько метрик которые пришли и сервер их принял, а одну он не принял например

                Короче тут есть на чем подумать архитектурно
                  0
                  Да, я над этим думал. Если сбор данных — это отдельный item, то его надо делать неподдерживаемым, если он не смог забрать данные. Возвращать он может количество значений, отправка которых зафейлилась, тогда на это можно сделать отдельный триггер.
                  Если же реализовано это будет как-то по-другому, надо уже думать отдельно. Например, в порядке общего бреда:
                  Имеем item prototype.
                  ключ: db.odbc.select[tbs_bytes,{#TBS_NAME},{HOST.NAME}]
                  запрос:
                  SELECT tablespace_name as TBS_NAME, SUM(bytes) FROM dba_data_files GROUP BY tablespace_name;
                  

                  Новый чекбокс Bulk request . Если он установлен, то для выполняется одна проверка для всех айтемов, сгенерированных из этого прототипа. Полученные значения раскладываются по айтемам, исходя из значения поля, заголовок которого совпадет с LLD макросом в ключе (в данном случае — TBS_NAME).

      Only users with full accounts can post comments. Log in, please.