• Sy chevron_right

      Настройки таймаута и количества попыток для запросов SNMP в Zabbix 3.4

      pubsub.slavino.sk / sysadmblog · Sunday, 27 September, 2020 - 08:00 edit · 4 minutes

    До версии 2.2.0 в Zabbix для опроса по SNMP использовались настройки опроса по умолчанию. По умолчанию в библиотеке SNMP таймаут опроса составлял 1 секунду, а в случае неудачи делалось до 5 дополнительных попыток опроса. В Zabbix 2.2 для опроса по SNMP используется значение опции Timeout из файла конфигурации и делается только одна попытка опроса.

    Ранее, чтобы уменьшить количество вызовов скриптов внешнего опроса, в конфигурации моих сереров Zabbix было выставлено максимально возможное значение таймаута - 30 секунд, а каждый такой скрипт запрашивал как можно больше значений у устройства и отправлял полученные значения в Zabbix при помощи утилиты zabbix_sender. Если скрипт успевал снять все необходимые данные, укладываясь в отведённые для его работы 30 секунд, то всё хорошо. Если скрипт не укладывался в 30 секунд, то процедуру опроса делили на несколько частей, так чтобы каждая из них уложилась в 30 секунд. Затем в Zabbix'е заводили по отдельному элементу данных для вызова скрипта, указывая ему какую именно часть данных нужно снять с устройства.

    При переходе с Zabbix 2.0 на 2.2 изменение настроек таймаута SNMP привело к большим проблемам: использование процессов Poller выросло до 100% и сервер перестал успевать опрашивать оборудование в необходимом темпе. Происходило это потому, что первый же запрос SNMP к недоступному устройству растягивался до 30 секунд, в течение которых процесс просто ждал ответа от устройства, не занимаясь больше ничем.

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

    Получившиеся исправления ранее уже были описаны в рамках более крупной статьи Установка и настройка Zabbix 2.2.0 в Debian Wheezy , но там им не уделялось достаточного внимания. На этот раз я опишу заплатку более подробно.

    Задеклалируем изменения, которые собираемся внести, отредактировав пример файла конфигурации conf/zabbix_server.conf:
    Index: zabbix-3.4.12-1+buster/conf/zabbix_server.conf
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/conf/zabbix_server.conf
    +++ zabbix-3.4.12-1+buster/conf/zabbix_server.conf
    @@ -439,6 +439,26 @@ DBUser=zabbix

    Timeout=4

    +### Option: SNMPTimeout
    +# Specifies how long we wait for SNMP device (in seconds).
    +#
    +# Mandatory: no
    +# Range: 1-30
    +# Default:
    +# SNMPTimeout=1
    +
    +SNMPTimeout=1
    +
    +### Option: SNMPRetries
    +# Specifies how many times to trying request for SNMP device
    +#
    +# Mandatory: no
    +# Range: 1-10
    +# Default:
    +# SNMPRetries=3
    +
    +SNMPRetries=3
    +
    ### Option: TrapperTimeout
    # Specifies how many seconds trapper may spend processing new data.
    #
    Объявим переменные CONFIG_SNMP_TIMEOUT и CONFIG_SNMP_RETRIES в том же файле, где объявлена переменная CONFIG_TIMEOUT. Это файл src/libs/zbxconf/cfg.c:
    Index: zabbix-3.4.12-1+buster/src/libs/zbxconf/cfg.c
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/libs/zbxconf/cfg.c
    +++ zabbix-3.4.12-1+buster/src/libs/zbxconf/cfg.c
    @@ -31,6 +31,8 @@ char *CONFIG_LOG_FILE = NULL;
    int CONFIG_LOG_FILE_SIZE = 1;
    int CONFIG_ALLOW_ROOT = 0;
    int CONFIG_TIMEOUT = 3;
    +int CONFIG_SNMP_TIMEOUT = 1;
    +int CONFIG_SNMP_RETRIES = 3;

    static int __parse_cfg_file(const char *cfg_file, struct cfg_line *cfg, int level, int optional, int strict);

    Пропишем эти же объявления в заголовочный файл include/cfg.h, на этот раз - как внешние объявления:
    Index: zabbix-3.4.12-1+buster/include/cfg.h
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/include/cfg.h
    +++ zabbix-3.4.12-1+buster/include/cfg.h
    @@ -46,6 +46,8 @@ extern char *CONFIG_LOG_FILE;
    extern int CONFIG_LOG_FILE_SIZE;
    extern int CONFIG_ALLOW_ROOT;
    extern int CONFIG_TIMEOUT;
    +extern int CONFIG_SNMP_TIMEOUT;
    +extern int CONFIG_SNMP_RETRIES;

    struct cfg_line
    {
    Теперь нужно научить сервер Zabbix и Zabbix-прокси извлекать значения из файлов конфигурации в эти переменные. Отредактируем файлы src/zabbix_server/server.c и src/zabbix_proxy/proxy.c следующим образом:
    Index: zabbix-3.4.12-1+buster/src/zabbix_server/server.c
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/zabbix_server/server.c
    +++ zabbix-3.4.12-1+buster/src/zabbix_server/server.c
    @@ -602,6 +602,10 @@ static void zbx_load_config(ZBX_TASK_EX
    PARM_OPT, 0, 0},
    {"Timeout", &CONFIG_TIMEOUT, TYPE_INT,
    PARM_OPT, 1, 30},
    + {"SNMPTimeout", &CONFIG_SNMP_TIMEOUT, TYPE_INT,
    + PARM_OPT, 1, 30},
    + {"SNMPRetries", &CONFIG_SNMP_RETRIES, TYPE_INT,
    + PARM_OPT, 1, 10},
    {"TrapperTimeout", &CONFIG_TRAPPER_TIMEOUT, TYPE_INT,
    PARM_OPT, 1, 300},
    {"UnreachablePeriod", &CONFIG_UNREACHABLE_PERIOD, TYPE_INT,
    Index: zabbix-3.4.12-1+buster/src/zabbix_proxy/proxy.c
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/zabbix_proxy/proxy.c
    +++ zabbix-3.4.12-1+buster/src/zabbix_proxy/proxy.c
    @@ -623,6 +623,10 @@ static void zbx_load_config(ZBX_TASK_EX
    PARM_OPT, 0, 0},
    {"Timeout", &CONFIG_TIMEOUT, TYPE_INT,
    PARM_OPT, 1, 30},
    + {"SNMPTimeout", &CONFIG_SNMP_TIMEOUT, TYPE_INT,
    + PARM_OPT, 1, 30},
    + {"SNMPRetries", &CONFIG_SNMP_RETRIES, TYPE_INT,
    + PARM_OPT, 1, 10},
    {"TrapperTimeout", &CONFIG_TRAPPER_TIMEOUT, TYPE_INT,
    PARM_OPT, 1, 300},
    {"UnreachablePeriod", &CONFIG_UNREACHABLE_PERIOD, TYPE_INT,
    Реализация функций опроса по SNMP находится в файле src/zabbix_server/poller/checks_snmp.c, но прежде чем редактировать его, заменим в заголовочном файле src/zabbix_server/poller/checks_snmp.h объявление внешней переменной CONFIG_TIMEOUT на объявления внешних переменных CONFIG_SNMP_TIMEOUT и CONFIG_SNMP_RETRIES:
    Index: zabbix-3.4.12-1+buster/src/zabbix_server/poller/checks_snmp.h
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/zabbix_server/poller/checks_snmp.h
    +++ zabbix-3.4.12-1+buster/src/zabbix_server/poller/checks_snmp.h
    @@ -26,7 +26,8 @@
    #include "sysinfo.h"

    extern char *CONFIG_SOURCE_IP;
    -extern int CONFIG_TIMEOUT;
    +extern int CONFIG_SNMP_TIMEOUT;
    +extern int CONFIG_SNMP_RETRIES;

    #ifdef HAVE_NETSNMP
    void zbx_init_snmp(void);
    А теперь можно отредактировать сам файл src/zabbix_server/poller/checks_snmp.c:
    Index: zabbix-3.4.12-1+buster/src/zabbix_server/poller/checks_snmp.c
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/zabbix_server/poller/checks_snmp.c
    +++ zabbix-3.4.12-1+buster/src/zabbix_server/poller/checks_snmp.c
    @@ -456,8 +456,10 @@ static struct snmp_session *zbx_snmp_ope
    break;
    }

    - session.timeout = CONFIG_TIMEOUT * 1000 * 1000; /* timeout of one attempt in microseconds */
    - /* (net-snmp default = 1 second) */
    + session.timeout = CONFIG_SNMP_TIMEOUT * 1000 * 1000; /* timeout of one attempt in microseconds */
    + /* (net-snmp default = 1 second) */
    + session.retries = CONFIG_SNMP_RETRIES - 1; /* number of retries after failed attempt */
    + /* (net-snmp default = 5) */

    #ifdef HAVE_IPV6
    if (SUCCEED != get_address_family(item->interface.addr, &family, error, max_error_len))
    @@ -1095,7 +1097,7 @@ static int zbx_snmp_walk(struct snmp_ses
    pdu->max_repetitions = max_vars;
    }

    - ss->retries = (0 == bulk || (1 == max_vars && == level) ? 1 : 0);
    + ss->retries = (0 == bulk || (1 == max_vars && 0 == level) ? 1 : 0) * (CONFIG_SNMP_RETRIES - 1);

    /* communicate with agent */
    status = snmp_synch_response(ss, pdu, &response);
    @@ -1304,7 +1306,7 @@ static int zbx_snmp_get_values(struct sn
    goto out;
    }

    - ss->retries = (1 == mapping_num && 0 == level ? 1 : 0);
    + ss->retries = (1 == mapping_num && 0 == level ? 1 : 0) * (CONFIG_SNMP_RETRIES - 1);
    retry:
    status = snmp_synch_response(ss, pdu, &response);

    При помощи команды «grep -R CONFIG_TIMEOUT | grep -i snmp» в исходных текстах можно найти ещё один любопытный фрагмент в файле libs/zbxdbcache/dbconfig.c, где можно увидеть отключение повторных попыток опроса по SNMP всего узла, если он не отвечает по SNMP:
    static void DCincrease_disable_until(const ZBX_DC_ITEM *item, ZBX_DC_HOST *host, int now)
    {
    switch (item->type)
    {
    case ITEM_TYPE_ZABBIX:
    if (0 != host->errors_from)
    host->disable_until = now + CONFIG_TIMEOUT;
    break;
    case ITEM_TYPE_SNMPv1:
    case ITEM_TYPE_SNMPv2c:
    case ITEM_TYPE_SNMPv3:
    if (0 != host->snmp_errors_from)
    host->snmp_disable_until = now + CONFIG_TIMEOUT;
    break;
    case ITEM_TYPE_IPMI:
    if (0 != host->ipmi_errors_from)
    host->ipmi_disable_until = now + CONFIG_TIMEOUT;
    break;
    case ITEM_TYPE_JMX:
    if (0 != host->jmx_errors_from)
    host->jmx_disable_until = now + CONFIG_TIMEOUT;
    break;
    default:
    /* nothing to do */;
    }
    }
    Вопрос, стоит ли исправлять значение таймаута для проверок SNMP в этой функции, я оставлю на размышление. Если значение CONFIG_SNMP_TIMEOUT меньше CONFIG_TIMEOUT, то опрос по SNMP после временных перебоев будет приостанавливаться на меньшее время и, соответственно, восстанавливаться быстрее. Нагрузка на процессы Poller при этом может слегка повыситься, т.к. доступность узлов SNMP будет проверяться чаще. Если вы всё же решитесь поменять значение таймаута в этой функции, то вот очевидный патч для файла libs/zbxdbcache/dbconfig.c:
    Index: zabbix-3.4.12-1+buster/src/libs/zbxdbcache/dbconfig.c
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/src/libs/zbxdbcache/dbconfig.c
    +++ zabbix-3.4.12-1+buster/src/libs/zbxdbcache/dbconfig.c
    @@ -448,7 +448,7 @@ static void DCincrease_disable_until(con
    case ITEM_TYPE_SNMPv2c:
    case ITEM_TYPE_SNMPv3:
    if (0 != host->snmp_errors_from)
    - host->snmp_disable_until = now + CONFIG_TIMEOUT;
    + host->snmp_disable_until = now + CONFIG_SNMP_TIMEOUT;
    break;
    case ITEM_TYPE_IPMI:
    if (0 != host->ipmi_errors_from)
    Полную версию описанной здесь заплатки можно взять по ссылке zabbix3_4_12_snmp_timeout_retries.patch .

    Značky: #zabbix, #debian, #3.4, #Linux, #buster, #linux

    • Sy chevron_right

      Исправление доступа к периодам обслуживания в Zabbix 3.4

      pubsub.slavino.sk / sysadmblog · Sunday, 20 September, 2020 - 08:00 edit · 1 minute

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

    Чтобы избежать подобных злоупотреблений, может быть лучше выдать права создавать и редактировать периоды обслуживания всем пользователям, имеющим права на просмотр соответствующей группы узлов. Именно такое изменение внёс в исходный код веб-интерфейса Zabbix мой коллега Кирилл. Изменил он два файла: frontends/php/include/classes/api/services/CMaintenance.php и frontends/php/maintenance.php. Первый файл исправляет права доступа в методах API maintenance , причём права удалять периоды обслуживания при помощи метода delete пользователю, не имеющему доступа к группе узлов, не предоставляется. Второй файл исправляет права доступа к периодам обслуживания непосредственно через сам веб-интерфейс Zabbix. Получившаяся заплатка выглядит следующим образом:
    Index: zabbix-3.4.12-1+buster/frontends/php/include/classes/api/services/CMaintenance.php
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/frontends/php/include/classes/api/services/CMaintenance.php
    +++ zabbix-3.4.12-1+buster/frontends/php/include/classes/api/services/CMaintenance.php
    @@ -276,7 +276,6 @@ class CMaintenance extends CApiService {
    // hosts permissions
    $options = [
    'hostids' => $hostids,
    - 'editable' => true,
    'output' => ['hostid'],
    'preservekeys' => true
    ];
    @@ -289,7 +288,6 @@ class CMaintenance extends CApiService {
    // groups permissions
    $options = [
    'groupids' => $groupids,
    - 'editable' => true,
    'output' => ['groupid'],
    'preservekeys' => true
    ];
    @@ -458,7 +456,6 @@ class CMaintenance extends CApiService {
    'selectGroups' => ['groupid'],
    'selectHosts' => ['hostid'],
    'selectTimeperiods' => API_OUTPUT_EXTEND,
    - 'editable' => true,
    'preservekeys' => true
    ]);

    @@ -580,7 +577,6 @@ class CMaintenance extends CApiService {
    $db_hosts = API::Host()->get([
    'output' => [],
    'hostids' => $hostids,
    - 'editable' => true,
    'preservekeys' => true
    ]);

    @@ -598,7 +594,6 @@ class CMaintenance extends CApiService {
    $db_groups = API::HostGroup()->get([
    'output' => [],
    'groupids' => $groupids,
    - 'editable' => true,
    'preservekeys' => true
    ]);

    Index: zabbix-3.4.12-1+buster/frontends/php/maintenance.php
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/frontends/php/maintenance.php
    +++ zabbix-3.4.12-1+buster/frontends/php/maintenance.php
    @@ -105,7 +105,6 @@ if (isset($_REQUEST['maintenanceid'])) {
    $dbMaintenance = API::Maintenance()->get([
    'output' => API_OUTPUT_EXTEND,
    'selectTimeperiods' => API_OUTPUT_EXTEND,
    - 'editable' => true,
    'maintenanceids' => getRequest('maintenanceid'),
    ]);
    if (empty($dbMaintenance)) {
    @@ -412,7 +411,6 @@ if (!empty($data['form'])) {
    'maintenanceids' => $data['maintenanceid'],
    'real_hosts' => true,
    'output' => ['hostid'],
    - 'editable' => true
    ]);
    $data['hostids'] = zbx_objectValues($data['hostids'], 'hostid');

    @@ -458,7 +456,6 @@ if (!empty($data['form'])) {

    // get groups
    $data['all_groups'] = API::HostGroup()->get([
    - 'editable' => true,
    'output' => ['groupid', 'name'],
    'real_hosts' => true,
    'preservekeys' => true
    @@ -475,7 +472,6 @@ if (!empty($data['form'])) {
    $data['hosts'] = API::Host()->get([
    'output' => ['hostid', 'name'],
    'real_hosts' => true,
    - 'editable' => true,
    'groupids' => $data['twb_groupid']
    ]);

    @@ -483,7 +479,6 @@ if (!empty($data['form'])) {
    $hostsSelected = API::Host()->get([
    'output' => ['hostid', 'name'],
    'real_hosts' => true,
    - 'editable' => true,
    'hostids' => $data['hostids']
    ]);
    $data['hosts'] = array_merge($data['hosts'], $hostsSelected);
    @@ -532,7 +527,6 @@ else {
    'search' => [
    'name' => ($filter['name'] === '') ? null : $filter['name']
    ],
    - 'editable' => true,
    'sortfield' => $sortField,
    'sortorder' => $sortOrder,
    'limit' => $config['search_limit'] + 1
    Эту заплатку можно взять по ссылке zabbix3_4_12_permit_edit_maintenances.patch .

    Značky: #zabbix, #Linux

    • Sy chevron_right

      Местонахождение устройства в панели проблем Zabbix 3.4

      pubsub.slavino.sk / sysadmblog · Sunday, 13 September, 2020 - 08:00 edit · 1 minute

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

    В Zabbix'е к каждому устройству можно прикрепить так называемые «инвентарные данные», среди которых есть поле адреса. Было бы неплохо показывать это поле в списке проблем, чтобы можно было без лишних телодвижений определить адрес устройства. К сожалению, Zabbix не предоставляет для этого штатных средств. Но к счастью, это можно сделать, внеся в исходный текст веб-интерфейса Zabbix небольшую правку.

    Интересующий нас виджет находится в файле frontends/php/app/views/monitoring.widget.problems.view.php

    Этот виджет фигурирует в списке маршрутов в файле frontends/php/include/classes/mvc/CRouter.php:
    'widget.problems.view'  => ['CControllerWidgetProblemsView',    'layout.widget',                'monitoring.widget.problems.view'],
    Класс CControllerWidgetProblemsView описан в файле frontends/php/app/controllers/CControllerWidgetProblemsView.php. Именно в этом классе готовятся данные, которые потом будут использованы в виджете для отображения. Данные об узлах, связанных с триггерами, в этом классе формируется при помощи функции getTriggersHostsList.

    Определение функции getTriggersHostsList находится в файле frontends/php/include/triggers.inc.php, для получения списка узлов с триггерами используется метод API host.get :
    $db_hosts = $hostids
    ? API::Host()->get([
    'output' => ['hostid', 'name', 'status', 'maintenanceid', 'maintenance_status', 'maintenance_type'],
    'selectGraphs' => API_OUTPUT_COUNT,
    'selectScreens' => API_OUTPUT_COUNT,
    'hostids' => array_keys($hostids),
    'preservekeys' => true
    ])
    : [];
    Внесём правку, которая добавит в этот список строку местоположения устройства из его инвентарных данных:
    Index: zabbix-3.4.12-1+buster/frontends/php/include/triggers.inc.php
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/frontends/php/include/triggers.inc.php
    +++ zabbix-3.4.12-1+buster/frontends/php/include/triggers.inc.php
    @@ -2170,6 +2170,7 @@ function getTriggersHostsList(array $tri
    'output' => ['hostid', 'name', 'status', 'maintenanceid', 'maintenance_status', 'maintenance_type'],
    'selectGraphs' => API_OUTPUT_COUNT,
    'selectScreens' => API_OUTPUT_COUNT,
    + 'selectInventory' => ['location'],
    'hostids' => array_keys($hostids),
    'preservekeys' => true
    ])
    Теперь эти данные нужно отобразить в виджете. Внесём соответствующую правку в файл frontends/php/app/views/monitoring.widget.problems.view.php:
    Index: zabbix-3.4.12-1+buster/frontends/php/app/views/monitoring.widget.problems.view.php
    ===================================================================
    --- zabbix-3.4.12-1+buster.orig/frontends/php/app/views/monitoring.widget.problems.view.php
    +++ zabbix-3.4.12-1+buster/frontends/php/app/views/monitoring.widget.problems.view.php
    @@ -54,6 +54,7 @@ $table = (new CTableInfo())
    $show_recovery_data ? _('Status') : null,
    _('Info'),
    ($data['sortfield'] === 'host') ? [_('Host'), $sort_div] : _('Host'),
    + ($data['sortfield'] === 'location') ? [_('Location'), $sort_div] : _('Location'),
    [
    ($data['sortfield'] === 'problem') ? [_('Problem'), $sort_div] : _('Problem'),
    ' • ',
    @@ -198,11 +199,19 @@ foreach ($data['data']['problems'] as $e
    ];
    }

    + $trigger_hosts = array_values($data['data']['triggers_hosts'][$trigger['triggerid']]);
    + $locations = array();
    + foreach($trigger_hosts as $host)
    + {
    + $locations[] = $host['inventory']['location'];
    + }
    +
    $table->addRow(array_merge($row, [
    $show_recovery_data ? $cell_r_clock : null,
    $show_recovery_data ? $cell_status : null,
    makeInformationList($info_icons),
    $triggers_hosts[$trigger['triggerid']],
    + join(', ', $locations),
    $description,
    (new CCol(
    ($problem['r_eventid'] != 0)
    Как видно, в правке:
    1. в таблицу был добавлен заголовок новой колонки Location,
    2. по каждому из триггеров формируется строка со списком адресов узлов, на значения элементов данных из которых опирается этот триггер,
    3. строки с адресами через запятую с пробелом склеиваются в одну строку,
    4. полученная строка добавляется в строку таблицы, в колонку Location.
    Готовую заплатку можно взять по ссылке zabbix3_4_12_frontend_location.patch .

    Značky: #3.4, #debian, #zabbix, #linux, #Linux, #buster, #php

    • Sy chevron_right

      Оптимизация Linux при использовании SSD

      pubsub.slavino.sk / sysadmblog · Sunday, 6 September, 2020 - 08:00 edit · 1 minute

    В прошлых статьях были описаны процедура обновления прошивки твердотельного накопителя Micron модели SSD 5200 MAX и шаблон Zabbix для контроля основных показателей его состояния. В этой статье пойдёт речь о том, какие дополнительные настройки Linux можно сделать для того, чтобы увеличить производительность системы при работе с твердотельными накопителями и увеличить срок службы самих накопителей.

    Изменение планировщика ввода-вывода

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

    Изменить планировщик диска sda можно при помощи следующей команды:
    # echo "deadline" > /sys/block/sda/queue/scheduler
    Для того, чтобы выбранный планировщик диска применялся при загрузке системы, можно поставить пакет sysfsutils:
    Оптимизация Linux при использовании SSD
    # apt-get install sysfsutils
    И прописать планировщик в файл /etc/sysfs.conf:
    block/sda/queue/scheduler = deadline
    Другой способ сделать изменения постоянными - создать файл /etc/udev/rules.d/60-ssd.rules со следующими правилами udev:
    ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="deadline"
    Это правило для всех не вращающихся дисков с именем sd* будет устанавливать планировщик deadline.

    Размер страницы

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

    Например, по данным SMART размер логического сектора диска равен 512 байтам, а размер страницы равен 4096 байт:
    # smartctl -i /dev/sda | grep Sector
    Sector Sizes: 512 bytes logical, 4096 bytes physical
    Убедиться в том, что ядро операционной системы Linux знает о размере физического сектора, можно следующим образом:
    # cat /sys/block/sda/queue/physical_block_size 
    4096

    Увеличение резерва страниц

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

    Часть общего объёма страниц диска закладывается в резерв. Напрмер, SSD объёмом 480 Гигабайт может иметь реальный объём 512 Гигабайт, а разница используется как раз для равномерного использования ресурса всех страниц.

    Кроме того, в файловой системе может иметься свободное место, не занятое никакими данными. Это свободное место на SSD можно приобщить к резерву. Для этого операционная система может сообщать диску о неиспользуемых ею страницах при помощи ATA-команды TRIM . Для этого SSD должен поддерживать операцию TRIM, а файловая система должна поддерживать опцию монитрования discard.

    Проверить наличие поддержки TRIM в SSD можно при помощи утилиты hdparm:
    # hdparm -I /dev/sda | grep TRIM
    * Data Set Management TRIM supported (limit 8 blocks)
    * Deterministic read ZEROs after TRIM
    Вторая строчка означает, что секторы, над которыми произведена команда TRIM, при попытке чтения будут возвращать нули. Другим возможным режимом может быть «Deterministic read after TRIM», когда при чтении возвращаются не нули, а какая-то другая всегда одинаковая последовательность данных.

    Если на странице руководства man mount среди опций интересующей файловой системы имеется опция discard, то файловую систему можно перемонтировать с поддержкой этой опции.

    Сначала посмотрим, с какими опциями смонтирована файловая система:
    # findmnt /
    TARGET SOURCE FSTYPE OPTIONS
    / /dev/md0 ext4 rw,relatime,errors=remount-ro,data=ordered
    Перемонтируем файловую систему, добавив к списку опций remount и discard:
    # mount -o remount,rw,relatime,errors=remount-ro,data=ordered,discard /
    Убеждаемся, что новая опция добавилась к текущему списку:
    # findmnt /
    TARGET SOURCE FSTYPE OPTIONS
    / /dev/md0 ext4 rw,relatime,discard,errors=remount-ro,data=ordered
    Чтобы отключить опцию discard, можно повторить процедуру перемонтирования, указав вместо опции discard опцию nodiscard.

    Чтобы при перезагрузке операционная система монтировала файловую систему с опцией discard, нужно добавить её к списку опций монитрования в файле /etc/fstab. Например, строчка монтирования может выглядеть следующим образом:
    UUID=324f1a70-5229-4376-afbb-eb274c8e60aa /               ext4    errors=remount-ro,discard 0       1
    Чтобы сообщить диску о неиспользуемых секторах, которые были освобождены до включения опции discard, или при отключенной опции discard, можно воспользоваться командой fstrim:
    # fstrim -v /
    /: 146,6 MiB (153755648 bytes) trimmed
    Кроме увеличения ресурса диска, использование TRIM и discard может приводить к увеличению скорости операций записи и чтения. Т.к. у контроллера есть в распоряжении много очищенных блоков, ему не придётся тратить время на их очистку для записи новых данных. При этом операция очистки блока может выполняться в фоновом режиме, когда SSD не занят выполнением операций чтения или записи.

    Если на пути между файловой системой и диском имеются менеджер томов LVM или RAID-массив, то информация о неиспользуемых секторах может застревать в этих подсистемах и не доходить до SSD. Чтобы LVM сообщал о неиспользуемых секторах на нижележащий уровень, нужно в секции devices из файла конфигурации /etc/lvm/lvm.conf выставить следующую опцию:
    issue_discards = 1
    Убедиться в том, что TRIM корректно передаётся нижележащему хранилищу, можно при помощи команды:
    # lsblk -D
    Если TRIM поддерживается на всех уровнях, то в столбцах DISC-GRAN и DISC-MAX будут ненулевые значения:
    NAME    DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
    sda 0 4K 2G 0
    └─sda1 0 4K 2G 0
    └─md0 0 4K 2G 0
    sdb 0 4K 2G 0
    └─sdb1 0 4K 2G 0
    └─md0 0 4K 2G 0
    Если же TRIM не используется, то можно увидеть такую картину:
    NAME                     DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
    sda 0 0B 0B 0
    ├─sda1 0 0B 0B 0
    │ └─md0 0 0B 0B 0
    └─sda2 0 0B 0B 0
    └─md1 0 0B 0B 0
    ├─vg0-mon--disk 0 0B 0B 0
    └─vg0-mon--swap 0 0B 0B 0
    sdb 0 0B 0B 0
    ├─sdb1 0 0B 0B 0
    │ └─md0 0 0B 0B 0
    └─sdb2 0 0B 0B 0
    └─md1 0 0B 0B 0
    ├─vg0-mon--disk 0 0B 0B 0
    └─vg0-mon--swap 0 0B 0B 0
    Возможны промежуточные варианты, когда файловая система отправляет операции TRIM на нижележащий уровень, но дальше эти операции не проходят.

    Файловые системы в оперативной памяти

    Т.к. интенсивный ввод-вывод снижает ресурс SSD, лучше избегать использовать SSD для хранения временных файлов. Например, раздел /tmp можно расположить в оперативной памяти. Временно это можно сделать при помощи такой команды:
    # mount -t tmpfs tmpfs -o relatime,nodev,nosuid,noexec,mode=1777 /tmp
    Если нужно ограничить максимальный размер файлов во временной файловой системе, к опциям noatime и nosuid можно добавить опцию size с указанием этого размера:
    # mount -t tmpfs tmpfs -o relatime,nodev,nosuid,noexec,mode=1777,size=1G /tmp
    Если временную файловую систему нужно монтировать автоматически при загрузке системы, нужно добавить в файл /etc/fstab соответствующую строчку:
    tmpfs /tmp tmpfs relatime,nodev,nosuid,noexec,mode=1777,size=1G 0 0
    Если файловая система уже не смонтирована, то теперь смонтировать её можно простой командоу:
    # mount /tmp
    Аналогичным образом можно монтировать другие временные файловые системы. Например:
    tmpfs /var/tftp tmpfs relatime,nodev,nosuid,noexec,uid=tftp,gid=tftp,mode=0760,size=32M 0 0

    Использованные материалы


    Značky: #hdparm, #buster, #linux, #ssd, #Linux, #tmpfs, #debian

    • Sy chevron_right

      Контроль параметров S.M.A.R.T. накопителей SSD через Zabbix

      pubsub.slavino.sk / sysadmblog · Sunday, 30 August, 2020 - 08:00 edit · 1 minute


    В этой статье описывается доработка шаблона Zabbix из статьи Контроль параметров S.M.A.R.T. жёстких дисков через Zabbix . Имеющийся шаблон пригоден только для контроля жётских дисков, а в этой статье я опишу доработки, которые позволят контролировать как состояние жёстких дисков, так и накопителей SSD Micron 5200 MAX. Этот шаблон может подойти и для других моделей накопителей, если они поддерживают необходимые атрибуты S.M.A.R.T., но на других накопителях не тестировался.

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

    Атрибуты S.M.A.R.T. и коэффициент усиления записи

    Документация на атрибуты S.M.A.R.T. доступна по ссылке TN-FD-22: Client SATA SSD SMART Attribute Reference

    С точки зрения контроля состояния накопителей SSD наиболее интересны следующие атрибуты:
    202 Percent_Lifetime_Used Процент использования ресурса диска (100% - полностью изношен)
    246 Total_Host_Sector_Write Количество записанных секторов
    247 Host_Program_Page_Count Количество записанных страниц
    248 Bckgnd_Program_Page_Cnt Количество страниц, записанных контроллером
    На твердотельных накопителях единицей чтения и записи является страница, размер которой обычно больше логического размера сектора диска. По мере повторных перезаписей страница изнашивается и запись на неё становится всё менее надёжной. Количество гарантированных производителем успешных перезаписей страницы называется ресурсом. Чтобы снизить вероятность потери информации, контроллер накопителя ведёт учёт количества операций перезаписи каждой страницы. При любом изменении информации в логическом секторе диска контроллер выбирает из всех имеющихся свободных страниц наименее изношенные и копирует данные на неё. Контроллер имеет возможность посчитать изношенность всего накопителя в целом и отражает это значение в атрибуте Percent_Lifetime_Used.

    Также производитель регламентирует в технических характеристиках накопителя гарантированный объём записанных на диск данных - TBW, Total Bytes Written. Например, исходя из технических характеристик накопителей, указанных на странице Micron 5200 series of SATA SSDs , на SSD Micron модели 5200 MAX 480Gb можно записать 4.38 петабайт данных. Контроллер накопителя ведёт учёт количества записанных 512-байтных секторов в атрибуте Total_Host_Sector_Write.

    Страницы группируются в блоки. Для того, чтобы записать в страницу новое содержимое, необходимо выполнить операцию очистки всего блока. Из-за этого перезапись одного логического сектора может приводить к перезаписи в несколько раз большего объёма данных на SSD. Отношение реально записанного объёма данных к объёму, который просила записать операционная система, называется коэффициентом усиления записи (Write Amplification Factor). Посчитать его можно воспользовавшись значениями атрибутов S.M.A.R.T. Host_Program_Page_Count и Bckgnd_Program_Page_Cnt по следующей формуле:
    WAF = (Host_Program_Page_Count + Bckgnd_Program_Page_Cnt) / Host_Program_Page_Count

    Доработка конфигурации агента Zabbix

    Во-первых, нам полезно определять тип накопителя: жёсткий диск или твердотельный накопитель.

    Для этого я воспользовался полем Rotation Rate, в котором содержится частота вращения диска в оборотах в минуту. Если это поле не содержит числа, то будем считать накопитель твердотельным. В таком случае частота вращения диска равняется нулю. Добавим в файл конфигурации Zabbix-агента /etc/zabbix/zabbix_agentd.conf «пользовательский параметр» для определения частоты вращения диска:
    UserParameter=smart.rpm[*],/usr/bin/sudo /usr/sbin/smartctl -i $1 2>&1 | /usr/bin/awk -F: '$$1 ~ /^Rotation Rate$/ { match($$2, /[0-9]+/); if (RSTART > 0) { print substr($$2, RSTART, RLENGTH); } else { print 0 } }'
    Для контроля процента использованного ресурса, объёма записанных данных и коэффициента усиления записи добавим в конфигурацию Zabbix-агента /etc/zabbix/zabbix_agentd.conf ещё три «пользовательских параметра»:
    UserParameter=smart.ssd.used[*],/usr/bin/sudo /usr/sbin/smartctl -A $1 2>&1 | /usr/bin/awk 'BEGIN { p = 0; } /^202 / { p = $$10; } END { print p; }'
    UserParameter=smart.ssd.written[*],/usr/bin/sudo /usr/sbin/smartctl -A $1 2>&1 | /usr/bin/awk 'BEGIN { w = 0; } /^246 / { w = $$10 * 512; } END { print w; }'
    UserParameter=smart.ssd.waf[*],/usr/bin/sudo /usr/sbin/smartctl -A $1 2>&1 | /usr/bin/awk 'BEGIN { hw = 1; cw = 0; } /^247 / { hw = $$10; } /^248 / { cw = $$10; } END { print (hw + cw) / hw; }'
    После внесения изменений в конфигурацию Zabbix-агента, не забудьте его перезапустить:
    # systemctl restart zabbix-agent

    Доработка шаблонов для Zabbix

    Я обновил два шаблона, описанных ранее, для контроля параметров S.M.A.R.T. твердотельных накопителей. Взять их можно по прежним ссылкам:
    В обоих шаблонах имеется элемент данных для низкоуровневого обнаружения, который находит все имеющиеся в системе диски, поддерживающие S.M.A.R.T.:
    smart2_lld.png.png
    Есть прототипы элементов данных, с помощью которых контролируется: статус здоровья диска, количество перемещённых секторов, секторов, ожидающих перемещения, температура жёсткого диска. Значения этих данных для каждого из жёстких дисков снимаются раз в 10 минут. Раз в час для каждого жёсткого диска запрашивается модель и серийный номер - они могут пригодиться, когда понадобится заменить один из жёстких дисков:
    smart2_itemprototypes.png
    Имеется три прототипа триггеров, который будут созданы для каждого обнаруженного жёсткого диска. Самый главный триггер срабатывает в том случае, когда S.M.A.R.T. явным образом сообщает о неисправности диска. Два других триггера срабатывают при превышении лимита неисправных секторов или секторов, ожидающих перемещения:
    smart2_triggerprototypes.png
    Лимиты для двух последних триггеров можно задать через соответствующие макросы - {$SMART_REALLOCATED_LIMIT} и {$SMART_PENDING_LIMIT}:
    smart_macros.png
    На картинке заданы нулевые лимиты, поэтому триггеры будут срабатывать при появлении хотя бы одного подозрительного сектора на диске. Если вы посчитали, что проблемных секторов не так уж и много, то можно задать новые значения макросов индивидуально в самом наблюдаемом узле Zabbix.

    Как можно заметить, в выражениях триггеров эти макросы используются в виде {$SMART_REALLOCATED_LIMIT:"{#SMART}"}. Макросы такого вида описаны в Руководстве по Zabbix, 7 Настройка, 10 Макросы, 2 Пользовательские макросы, Контекст пользовательских макросов .

    При срабатывании триггера вида «/dev/sda: Количество перемещённых секторов 13 > 0» можно переопределить значение макроса для конкретного диска. Чтобы погасить этот триггер, на уровне узла можно определить макрос {$SMART_REALLOCATED_LIMIT:"/dev/sda"} со значением 13. Порог срабатывания триггеров на других жёстких дисках останется прежним - будет использоваться значение по умолчанию, взятое из шаблона.

    Наконец, снимаемые данные в случае упомянутых твердотельных накопителей Micron SSD 5200 MAX выглядят следующим образом:
    smart2_lastdata.png

    Značky: #smart, #linux, #ssd, #debian, #buster, #3.4, #zabbix, #Linux

    • Sy chevron_right

      Обновление прошивок на SSD Micron 5200 MAX

      pubsub.slavino.sk / sysadmblog · Sunday, 23 August, 2020 - 08:00 edit · 6 minutes

    После перевода таблиц истории и тенденций Zabbix, хранившихся в MySQL, с движка InnoDB на TokuDB, базы данных на всех серверах Zabbix ужались примерно в 10 раз. Проблемы с нехваткой места на дисках решены и больше не приходится урезать глубину хранения истории или тенденций.

    Т.к. базы данных стали значительно меньше, появился смысл использовать накопители SSD меньшего объёма с программным RAID вместо SAS-дисков и аппаратных RAID-контроллеров. При сравнимой цене накопителей SSD и SAS-дисков, SSD позволяют обеспечить более высокую скорость работы дисковой подсистемы.

    После консультации с более опытным коллегой (привет, Рамиль), уже имеющим опыт использования накопителей SSD, выбор остановился на накопителе SSD 480GB SATA 2.5« 5200 MAX Micron (MTFDDAK480TDN-1A T1ZABYY).

    Накопители SSD содержат микросхемы флеш-памяти, в которых читать или записывать можно только страницу целиком. При этом записывать данные можно только в пустую страницу. Страницы группируются в блоки и очистить можно только блок целиком. У каждой страницы количество перезаписей ограничено, по достижении которого данные могут начать записываться с ошибками. Если страницу долгое время не читать, то данные на ней могут исказиться и пропасть. Контроллеру флеш-памяти в SSD приходится учитывать все эти ограничения. Для каждой страницы он должен вести учёт, содержит ли страница данные или она пустая, сколько раз её перезаписывали, как давно её последний раз читали. Прежде чем очистить блок, контроллеру нужно скопировать страницы с данными из этого блока в пустые страницы другого блока. Записывать данные лучше всего в те страницы, которые имеют меньшее количество перезаписей. При каждом перемещении данных из одной страницы в другую контроллеру нужно отметить соответствие линейного адреса страницы, которым манипулирует контроллер SATA, реальному положению страницы во флеш-памяти. Страницы, которые давно не читались, нужно периодически перечитывать, чтобы информация на них не пропала.

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

    Эта инструкция по обновлению прошивок SSD была написана по просьбе менее опытного коллеги (привет, Кирилл), которому придётся продолжить работу, начатую мной.

    Сайт производителя

    На сайте производителя www.micron.com доступны утилита, прошивки и документация. Для их получения нужно зарегистрироваться на сайте. Список субъектов федерации на сайте довольно забавен. В частности, в выпадающем списке нет Башкирии, зато есть «Пермякия», которую я и выбрал по сочетанию сходства с реальным названием и близости географического расположения.

    На странице Enterprise SSD Downloads в разделе msecli Software for Linux Systems можно найти установщик фирменной утилиты msecli для Linux. В этом разделе есть ссылка на скачивание Download .

    На той же странице Enterprise SSD Downloads в разделе Storage Executive Command Line Interface можно найти документацию на фирменную утилиту msecli. В этом разделе есть ссылка на скачивание Download .

    На странице Software and Drivers в разделе 5200 D1MU020/D1MU420/D1MU520/D1MU820 Storage Executive Firmware Update можно найти свежие прошивки для дисков. В нём есть ссылка на скачивание Download .

    Подготовка загрузочной флешки для обновления прошивок

    На странице Clonezilla Live on USB flash drive or USB hard drive описана процедура подготовки загрузочной флешки с Clonezilla. На странице Clonezilla Live Download можно скачать zip-архив для распаковки на флешку. Я выбрал стабильную версию на основе Debian и попал на страницу Downloads . В меню выбрал архитектуру amd64, формат zip, репозитории auto и нажал кнопку Download.

    После скачивания zip-архива нужно разметить флешку, распаковать на неё этот архив и установить загрузчик.

    Не вставляя флешку, определяем имена имеющихся в системе дисков:
    ~# ls /dev/sd*
    /dev/sda /dev/sda1 /dev/sda2 /dev/sdb /dev/sdb1 /dev/sdb2
    Теперь вставляем флешку и повторяем операцию:
    ~# ls /dev/sd*
    /dev/sda /dev/sda1 /dev/sda2 /dev/sdb /dev/sdb1 /dev/sdb2 /dev/sdc /dev/sdc1
    Видно, что в системе появилось новое блочное устройство /dev/sdc, на котором определился один раздел.

    Запустим утилиту fdisk для изменения разделов на блочном устройстве /dev/sdc:
    ~# fdisk /dev/sdc

    Welcome to fdisk (util-linux 2.29.2).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    Создадим на диске пустую таблицу разделов типа DOS командой o:
    Command (m for help): o
    Created a new DOS disklabel with disk identifier 0x2806276a.
    Посмотрим на список имеющихся разделов, введя команду p:
    Command (m for help): p
    Disk /dev/sdc: 14,4 GiB, 15502147584 bytes, 30277632 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x2806276a
    Создаём новый первичнй раздел от начала до конца свободного места на флешке. Вводим команду создания нового раздела n:
    Command (m for help): n
    Partition type
    p primary (0 primary, 0 extended, 4 free)
    e extended (container for logical partitions)
    Утилита спрашивает, раздел какого типа нужно создать: первичный или расширенный. В качестве загрузочного раздела можно использовать только первичный. Расширенный раздел может быть только один. Максимальное количество первичных и расширенных разделов в сумме может быть не больше 4. Внутри расширенного раздела можно создавать практически не ограниченное количество логических разделов, но ни один из них не может быть загрузочным. Т.к. нам нужно загрузить Clonezilla с этой флешки, выбираем первичный раздел, нажимая букву p:
    Select (default p): p
    Выбираем номер раздела, по умолчанию предлагается создать раздел с номером 1. Соглашаемся на предложение нажатием Enter:
    Partition number (1-4, default 1): 
    Выбираем сектор, начиная с которого должен начаться раздел. Соглашаемся с предложением по умолчанию начать раздел с сектора 2048 нажатием Enter:
    First sector (2048-30277631, default 2048): 
    Выбираем сектор, которым должен заканчиваться раздел. Можно ввести номер сектора, а можно указать размер раздела в секторах, килобайтах, мегабайтах, гигабайтах, терабайтах или петабайтах. По умолчанию предлагается последний сектор из неразмеченного пространства.

    Clonezilla требует создавать раздел размером не менее 200 мегабайт. На самом деле это ложь и раздела размером 200 мегабайт не хватит, т.к. даже zip-архив больше 200 мегабайт. Кроме того, нужно создать раздел с запасом для размещения утилиты для msecli_Linux.run и прошивок для SSD. Подойдёт раздел размером 512 мегабайт, но стоит сделать его меньше на зарезервированные в начале 2048 секторов. Поступим проще, просто посчитаем номер последнего сектора: 512*1024*1024/512=1048576. Введём получившееся число:
    Last sector, +sectors or +size{K,M,G,T,P} (2048-30277631, default 30277631): 1048576

    Created a new partition 1 of type 'Linux' and of size 511 MiB.
    Раздел нужного размера создан, но нужно поменять его тип. Для этого введём команду t:
    Command (m for help): t
    Selected partition 1
    Программа не спрашивает у нас номер раздела, т.к. он всего один, а сразу предлагает ввести номер типа раздела или ввести команду L, чтобы увидеть список всех возможных идентификаторов типов разделов. После ввода L получаем такой список:
    Partition type (type L to list all types): L

    0 Empty 24 NEC DOS 81 Minix / old Lin bf Solaris
    1 FAT12 27 Hidden NTFS Win 82 Linux swap / So c1 DRDOS/sec (FAT-
    2 XENIX root 39 Plan 9 83 Linux c4 DRDOS/sec (FAT-
    3 XENIX usr 3c PartitionMagic 84 OS/2 hidden or c6 DRDOS/sec (FAT-
    4 FAT16 <32m 40 Venix 80286 85 Linux extended c7 Syrinx
    5 Extended 41 PPC PReP Boot 86 NTFS volume set da Non-FS data
    6 FAT16 42 SFS 87 NTFS volume set db CP/M / CTOS / .
    7 HPFS/NTFS/exFAT 4d QNX4.x 88 Linux plaintext de Dell Utility
    8 AIX 4e QNX4.x 2nd part 8e Linux LVM df BootIt
    9 AIX bootable 4f QNX4.x 3rd part 93 Amoeba e1 DOS access
    a OS/2 Boot Manag 50 OnTrack DM 94 Amoeba BBT e3 DOS R/O
    b W95 FAT32 51 OnTrack DM6 Aux 9f BSD/OS e4 SpeedStor
    c W95 FAT32 (LBA) 52 CP/M a0 IBM Thinkpad hi ea Rufus alignment
    e W95 FAT16 (LBA) 53 OnTrack DM6 Aux a5 FreeBSD eb BeOS fs
    f W95 Ext'd (LBA) 54 OnTrackDM6 a6 OpenBSD ee GPT
    10 OPUS 55 EZ-Drive a7 NeXTSTEP ef EFI (FAT-12/16/
    11 Hidden FAT12 56 Golden Bow a8 Darwin UFS f0 Linux/PA-RISC b
    12 Compaq diagnost 5c Priam Edisk a9 NetBSD f1 SpeedStor
    14 Hidden FAT16 <3 61 SpeedStor ab Darwin boot f4 SpeedStor
    16 Hidden FAT16 63 GNU HURD or Sys af HFS / HFS+ f2 DOS secondary
    17 Hidden HPFS/NTF 64 Novell Netware b7 BSDI fs fb VMware VMFS
    18 AST SmartSleep 65 Novell Netware b8 BSDI swap fc VMware VMKCORE
    1b Hidden W95 FAT3 70 DiskSecure Mult bb Boot Wizard hid fd Linux raid auto
    1c Hidden W95 FAT3 75 PC/IX bc Acronis FAT32 L fe LANstep
    1e Hidden W95 FAT1 80 Old Minix be Solaris boot ff BBT
    Нам нужен раздел для размещения файловой системы FAT 32, флешка имеет линейную адресацию секторов, поэтому наиболее подходящим выбором будет вариант «W95 FAT32 (LBA)». Вводим тип c и нажимаем Enter:
    Partition type (type L to list all types): c
    Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.
    Осталось пометить раздел как загрузочный. Вводим команду a:
    Command (m for help): a
    Selected partition 1
    The bootable flag on partition 1 is enabled now.
    Раздел 1 помечен как загрузочный. Посмотрим на список разделов снова. Для этого введём команду p:
    Command (m for help): p
    Disk /dev/sdc: 14,4 GiB, 15502147584 bytes, 30277632 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x2806276a

    Device Boot Start End Sectors Size Id Type
    /dev/sdc1 * 2048 1048576 1046529 511M c W95 FAT32 (LBA)
    Всё верно, вводим команду w для записи изменений на флешку:
    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.
    fdisk сообщает, что таблица разделов записана. Теперь можно создать пустую файловую систему FAT 32 на флешке в разделе 1. Для этого воспользуемся такой командой:
    ~# mkfs.vfat -F 32 /dev/sdc1
    mkfs.fat 4.1 (2017-01-24)
    Готово. Теперь нужно смонтировать раздел в какой-нибудь пустой каталог. У меня для подобных целей имеется каталог /mnt:
    ~# mount /dev/sdc1 /mnt/
    Теперь нужно распаковать содержимое zip-архива с Clonezilla в этот каталог:
    ~# cd /mnt
    /mnt# unzip /home/stupin/Downloads/clonezilla-live-2.6.6-15-amd64.zip
    Полный вывод второй команды не привожу, т.к. в нём перечисляются все извлечённые файлы, которых много. Теперь переходим в каталог utils/linux и запускаем команду установки загрузчика:
    /mnt# cd utils/linux/
    /mnt/utils/linux# bash makeboot.sh /dev/sdc1
    This command will install MBR and syslinux/extlinux bootloader on /dev/sdc
    Clonezilla files are assumed to be on /dev/sdc1
    --------------------------------------------
    Machine: Unknown product name:
    Model: Kingston DataTraveler 3.0 (scsi)
    Disk /dev/sdc: 15.5GB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags:

    Number Start End Size Type File system Flags
    1 1049kB 537MB 536MB primary fat32 boot, lba

    --------------------------------------------
    Are you sure you want to continue?
    Установщик загрузчика показал нам информацию о разделе, загрузчик для которого мы хотим установить и спрашивает у нас подтверждения. Подтверждаем выбор буквой y:
    [y/n] y
    OK! Let's do it!
    --------------------------------------------
    File system of /dev/sdc1: vfat
    --------------------------------------------
    Do you want to install MBR on /dev/sdc on this machine "Unknown product name" ?
    Установщик спрашивает, хотим ли мы устновить главную загрузочную запись на диск /dev/sdc. Соглашаемся нажатием y:
    [y/n] y
    OK! Let's do it!
    Running: cat "/mnt/utils/mbr/mbr.bin" > /dev/sdc
    --------------------------------------------
    Do you want to install the syslinux boot files on /dev/sdc1 on this machine "Unknown product name" ?
    Установщик спрашивает, хотим ли мы установить файлы загрузчика syslinux в раздел /dev/sdc1. Подтверждаем наше желание нажатием y:
    [y/n] y
    OK! Let's do it!
    A filesystem supporting Unix file mode for syslinux is required. Copying syslinux to /tmp/linux_tmp.fZmDyo
    '/mnt/utils/linux/x64/syslinux' -> '/tmp/linux_tmp.fZmDyo/syslinux'
    Running: "/tmp/linux_tmp.fZmDyo/syslinux" -d syslinux -f -i "/dev/sdc1"
    //NOTE// If your USB flash drive fails to boot (maybe buggy BIOS), try to use "syslinux -d syslinux -fs /dev/sdc1", i.e. running with "-fs".
    syslinux ran successfully in installation mode.
    Done!
    Флешка готова. Осталось поместить на неё утилиту и файлы с прошивок. Перейдём в корневой каталог флешки, создадим каталог ssd, поместим в него установщик утилиты msecli и распакованные прошивки:
    /mnt/utils/linux# cd ../..
    /mnt# mkdir ssd
    /mnt# cd ssd
    /mnt/ssd# cp /home/stupin/Downloads/msecli_Linux.run .
    /mnt/ssd# unzip /home/stupin/Downloads/5200_D1MU_020_420_520_820_fwbin.zip
    Archive: /home/stupin/Downloads/5200_D1MU_020_420_520_820_fwbin.zip
    inflating: D1MU020/1.bin
    inflating: D1MU420/1.bin
    inflating: D1MU520/1.bin
    inflating: D1MU820/1.bin
    inflating: firmware.properties
    Выставим права исполнимости на установщик утилиты msecli_Linux.run:
    /mnt/ssd# chmod +x msecli_Linux.run
    Теперь можно выйти из каталога, в который смонтирована флешка, отмонтировать его и на всякий случай снять с флешки образ:
    /mnt/ssd# cd 
    ~# umount /mnt
    ~# dd bs=1M count=512 if=/dev/sdc of=/home/stupin/Downloads/clonezilla-live-2.6.6-15-amd64.img
    Т.к. образ снят под пользователем root, не забываем поменять владельца файла, чтобы потом можно было без проблем удалить его или переместить в другое место:
    ~# chown stupin:stupin /home/stupin/Downloads/clonezilla-live-2.6.6-15-amd64.img
    В файле /home/stupin/Downloads/clonezilla-live-2.6.6-15-amd64.img будет сохранён образ, который в дальнейшем можно будет записать на любую флешку размером не менее 512 мегабайт. Например, для записи образа на флешку /dev/sdc можно будет воспользоваться такой командой:
    ~# dd if=/home/stupin/Downloads/clonezilla-live-2.6.6-15-amd64.img of=/dev/sdc

    Обновление прошивок

    После загрузки с флешки нужно выбрать в меню загрузку в командную строку. Прежде чем приступить непосредственно к обновлению прошивок, нужно устанавить в систему утилиту msecli. Запускаем установщик:
    # /usr/lib/live/mount/medium/ssd/msecli_Linux.run
    Читаем лицензию, принимаем, соглашаемся на установку утилиты. Узнаём текущие версии прошивок:
    # msecli -F
    Device Name FW-Rev
    /dev/sda D1MU004
    /dev/sdb D1MU004
    /dev/sdс D1MU004

    Firmware version retrieved successfully
    CMD_STATUS : Success
    STATUS_CODE : 0

    Copyright (C) 2019 Micron Technology, Inc.
    Как видно, на трёх имеющихся в системе накопителях SSD определилась прошивка версии D1MU004. При подготовке флешки содержимое zip-архива с прошивками мы распаковали в каталог /ssd. В файле firmware.properties можно найти информацию о совместимости прошивок с моделями накопителей. Для Micron 5200MAX подходит прошивка, находящаяся в каталоге D1MU020. Обновляем прошивки до свежих версий:
    # msecli -U -i D1MU020 -n /dev/sda
    This will update the 5200MAX drive in the system
    Are you sure you want to continue(Y|N):Y

    Updating firmware on drive /dev/sda (Serial No. XXXXXXXXXXXX)
    ..................
    Device Name : /dev/sda
    Firmware Update on /dev/sda Succeded!
    CMD_STATUS : Success
    STATUS_CODE : 0

    Copyright (C) 2019 Micron Technology, Inc.

    # msecli -U -i D1MU020 -n /dev/sdb
    This will update the 5200MAX drive in the system
    Are you sure you want to continue(Y|N):Y

    Updating firmware on drive /dev/sdb (Serial No. XXXXXXXXXXXX)
    ..................
    Device Name : /dev/sdb
    Firmware Update on /dev/sdb Succeded!
    CMD_STATUS : Success
    STATUS_CODE : 0

    Copyright (C) 2019 Micron Technology, Inc.

    # msecli -U -i D1MU020 -n /dev/sdс
    This will update the 5200MAX drive in the system
    Are you sure you want to continue(Y|N):Y

    Updating firmware on drive /dev/sdc (Serial No. XXXXXXXXXXXX)
    ..................
    Device Name : /dev/sdc
    Firmware Update on /dev/sdc Succeded!
    CMD_STATUS : Success
    STATUS_CODE : 0

    Copyright (C) 2019 Micron Technology, Inc.

    Značky: #Linux, #debian, #buster, #ssd, #linux

    • Sy chevron_right

      История и тенденции Zabbix в TokuDB

      pubsub.slavino.sk / sysadmblog · Sunday, 16 August, 2020 - 08:00 edit · 6 minutes

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

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

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

    В случае с MySQL первым делом нужно убедиться, что база данных не находится в одном файле и, при необходимости, разнести таблицы по разным файлам: сделать полную резервную копию, удалить базы данных, включить innodb_file_per_table=YES, перезапустить MySQL, восстановить базы данных из резервных копий.

    Другой важный шаг: нужно убедиться, что основной буфер СУБД, размер которого настраивается через innodb_buffer_pool_size, имеет максимально доступный объём. Чем больше объём этого буфера, тем больше «горячих», часто требуемых данных, может в нём уместиться. Идеально, если вся СУБД умещается в оперативной памяти целиком. На практике, однако, это редко достижимо, т.к. таблицы истории и тенденций в базе данных Zabbix могут достигать сотен гигабайт. В любом случае, если есть возможность, лучше увеличить объём оперативной памяти на сервере с СУБД.

    Также стоит обратить внимание на размеры журналов innodb_log_file_size: Zabbix пишет много данных и размер этих файлов должен соответствовать объёму данных, которые записываются системой в секунду (лимит для этой опции - 2 гигабайта). Оборотной стороной больших журналов является более длительный запуск сервера MySQL.

    Когда выполнены предыдущие рекомендации - на контроле есть только самое необходимое, данные снимаются с разумными интервалами времени, произведена оптимизация настроек - следующим этапом обычно идёт отключение HouseKeeper'а и секционирование таблиц истории и тенденций. Понять, о том что настало время отключать HouseKeeper, можно обратившись ко внутреннему мониторингу Zabbix. Если на графиках процесс HouseKeeper почти постоянно используется на 100%, а увеличение настроек HouseKeepingFrequency и HouseKeeperDelete не приводят к желаемому эффекту, значит пора. Zabbix не имеет официальной поддержки секционирования таблиц, однако можно найти готовые инструкции для его настройки.

    Ранее я использовал для разбивки таблиц на секции вот эту статью на wiki-странице Zabbix: Docs/howto/mysql partitioning , однако впоследствии стал пользоваться вот этой статьёй: Docs/howto/mysql partition . У второй статьи есть два преимущества:
    1. при её использовании в базе данных Zabbix не нужно создавать дополнительную нестандартную таблицу manage_partitions,
    2. при её использовании имеется возможность делить таблицы не только на секции месячного или суточного размера, но и на секции произвольного размера, в том числе более мелкого.
    Наконец, в интернете можно встретить советы по смене движка таблиц истории и тенденций с родного для MySQL движка InnoDB на движок TokuDB с технологией «фрактальных индексов». Также вместе с этим движком рекомендуют использовать «кластерные индексы», когда индексы хранятся вместе с данными, и сжатие данных в таблицах.

    Изначально TokuDB был ответвлением MySQL, в котором фирма Tokutek реализовала собственную технологию «фрактальных индексов». Позже исходные тексты TokuDB стали доступны под свободной лицензией и на их основе был реализован плагин, пригодный подключению как к оригинальной СУБД MySQL, так и к её ответвлениям - MariaDB и Percona.

    Включение плагина TokuDB в MariaDB

    Мне удавалось успешно настраивать TokuDB на Debian Stretch и Debian Buster. Установку и настройку MariaDB оставим за скобками нашего обсуждения. Будем считать, что система мониторинга уже развёрнута и использует MariaDB, а таблицы истории и тенденций пока что хранятся в таблицах формата InnoDB.

    Первым делом установим пакет с плагином, который добавляет в MariaDB поддержку формата хранения таблиц TokuDB:
    # apt-get install mariadb-plugin-tokudb
    Вместе с пакетом будет установлен дополнительный файл конфигурации /etc/mysql/mariadb.conf.d/tokudb.cnf, в котором указан путь к библиотеке libjemalloc. В случае с Debian Stretch это будет путь /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 В случае с Debian Buster это будет путь /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 Прежде чем продолжать, стоит удостовериться, что этот файл действительно сущетсвует в системе, т.к. при обновлении операционной системы до свежего релиза в файле конфигурации мог остаться устаревший путь. В Debian Stretch этот файл устанавливается с пакетом libjemalloc1, а в Debian Buster - пакетом libjemalloc2. Необходимо установить соответствующий пакет и исправить путь к файлу в файле конфигурации.

    Теперь нужно убедиться, что в системе отключена прозрачная поддержка огромных страниц (Transparent Hugepages). Для этого запускаем следующую команду:
    $ cat /sys/kernel/mm/transparent_hugepage/enabled
    Если команда поругалась на отсутствие файла, значит прозрачная поддержка огромных страниц уже отключена и делать больше ничего не нужно. Также ничего не нужно делать, если команда вывела следующее:
    always madvise [never]
    Если же команда вывела приведённый ниже текст, то прозрачная поддержка огромных страниц включена и её необходимо отключить:
    [always] madvise never
    Открываем файл /etc/default/grub, находим переменную GRUB_CMDLINE_LINUX и добавляем в список опций опцию transparent_hugepage=never. В результате должно получиться что-то такое:
    GRUB_CMDLINE_LINUX="ipv6.disable=1 transparent_hugepage=never"
    Теперь нужно обновить конфигурацию загрузчика следующей командой:
    # update-grub
    Осталось перезагрузить систему и убедиться в том, что прозрачная поддержка огромных страниц действительно отключилась.

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

    Создание новых таблиц истории и тенденций

    Если база данных только создана и не содержит исторических данных и данных тенденций, то можно просто удалить существующие таблицы:
    DROP TABLE history;
    DROP TABLE history_uint;
    DROP TABLE history_str;
    DROP TABLE history_log;
    DROP TABLE history_text;
    DROP TABLE trends;
    DROP TABLE trends_uint;
    Если же нужно выполнить миграцию существующей инсталляции Zabbix, тогда лучше сначала переименовать существующие таблицы истории и тенденций:
    RENAME TABLE history TO history_bak;
    RENAME TABLE history_uint TO history_uint_bak;
    RENAME TABLE history_str TO history_str_bak;
    RENAME TABLE history_log TO history_log_bak;
    RENAME TABLE history_text TO history_text_bak;
    RENAME TABLE trends TO trends_bak;
    RENAME TABLE trends_uint TO trends_uint_bak;
    Вместо прежних таблиц нужно будет создать новые пустые таблицы истории и тенденций, сначала без разбивки на секции, с помощью следующих SQL-запросов:
    CREATE TABLE `history` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `value` double(16,4) DEFAULT '0.0000' NOT NULL,
    `ns` integer DEFAULT '0' NOT NULL
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    CREATE INDEX `history_1` ON `history` (`itemid`,`clock`) CLUSTERING=yes;

    CREATE TABLE `history_uint` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `value` bigint unsigned DEFAULT '0' NOT NULL,
    `ns` integer DEFAULT '0' NOT NULL
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    CREATE INDEX `history_uint_1` ON `history_uint` (`itemid`,`clock`) CLUSTERING=yes;

    CREATE TABLE `history_str` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `value` varchar(255) DEFAULT '' NOT NULL,
    `ns` integer DEFAULT '0' NOT NULL
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    CREATE INDEX `history_str_1` ON `history_str` (`itemid`,`clock`) CLUSTERING=yes;

    CREATE TABLE `history_log` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `timestamp` integer DEFAULT '0' NOT NULL,
    `source` varchar(64) DEFAULT '' NOT NULL,
    `severity` integer DEFAULT '0' NOT NULL,
    `value` text NOT NULL,
    `logeventid` integer DEFAULT '0' NOT NULL,
    `ns` integer DEFAULT '0' NOT NULL
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    CREATE INDEX `history_log_1` ON `history_log` (`itemid`,`clock`) CLUSTERING=yes;

    CREATE TABLE `history_text` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `value` text NOT NULL,
    `ns` integer DEFAULT '0' NOT NULL
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    CREATE INDEX `history_text_1` ON `history_text` (`itemid`,`clock`) CLUSTERING=yes;

    CREATE TABLE `trends` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `num` integer DEFAULT '0' NOT NULL,
    `value_min` double(16,4) DEFAULT '0.0000' NOT NULL,
    `value_avg` double(16,4) DEFAULT '0.0000' NOT NULL,
    `value_max` double(16,4) DEFAULT '0.0000' NOT NULL,
    PRIMARY KEY (itemid,clock) CLUSTERING=yes
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;

    CREATE TABLE `trends_uint` (
    `itemid` bigint unsigned NOT NULL,
    `clock` integer DEFAULT '0' NOT NULL,
    `num` integer DEFAULT '0' NOT NULL,
    `value_min` bigint unsigned DEFAULT '0' NOT NULL,
    `value_avg` bigint unsigned DEFAULT '0' NOT NULL,
    `value_max` bigint unsigned DEFAULT '0' NOT NULL,
    PRIMARY KEY (itemid,clock) CLUSTERING=yes
    ) ENGINE=TokuDB COMPRESSION=TOKUDB_LZMA;
    Эти таблицы пока не разбиты на секции, но уже используют движок TokuDB, сжатие данных по алгоритму LZMA и используют кластерные индексы - индексы, хранящиеся вместе с индексируемыми данными.

    Разбивка таблиц на секции

    Разбивку таблиц на секции я проводил в соответствии со статьёй Docs/howto/mysql partition .

    Я подготовил скрипт, который выводит команды, необходимые для разбивки таблиц истории и тенденций на необходимые секции. Настройки начальной и конечной дат, а также размер каждой секции, задаются прямо в тексте скрипта:
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-

    from datetime import datetime, timedelta
    from pytz import timezone

    def table_partitions(table, start, stop, step):
    print 'ALTER TABLE `%s` PARTITION BY RANGE (`clock`) (' % table

    dt = start
    while dt < stop:
    name = dt.strftime('%Y%m%d%H%M')
    ts = dt.strftime('%s')
    dt += step
    print 'PARTITION p%s VALUES LESS THAN (%s) ENGINE = TokuDB,' % (name, ts)

    name = dt.strftime('%Y%m%d%H%M')
    ts = dt.strftime('%s')
    print 'PARTITION p%s VALUES LESS THAN (%s) ENGINE = TokuDB' % (name, ts)
    print ');'

    tz = timezone('UTC')
    # Для таблиц тенденций trends и trends_uint
    start = datetime(2018, 9, 10, 0, 0, 0, tzinfo=tz)
    stop = datetime(2019, 9, 22, 0, 0, 0, tzinfo=tz)
    step = timedelta(days=1)
    table_partitions('trends', start, stop, step)
    table_partitions('trends_uint', start, stop, step)

    # Для таблиц истории history и history_uint
    start = datetime(2019, 6, 10, 0, 0, 0, tzinfo=tz)
    stop = datetime(2019, 9, 22, 0, 0, 0, tzinfo=tz)
    step = timedelta(hours=6)
    table_partitions('history', start, stop, step)
    table_partitions('history_uint', start, stop, step)

    # Для таблиц истории history_str, history_text и history_log
    start = datetime(2019, 9, 3, 0, 0, 0, tzinfo=tz)
    stop = datetime(2019, 9, 22, 0, 0, 0, tzinfo=tz)
    step = timedelta(days=1)
    table_partitions('history_str', start, stop, step)
    table_partitions('history_text', start, stop, step)
    table_partitions('history_log', start, stop, step)
    Запускаем скрипт, сохраняем выведенные им команды в файл:
    $ ./partitions.py > partitions.sql
    Затем подключаемся клиентом MySQL к базе данных zabbix:
    $ mysql -uzabbix -p zabbix
    И выполняем в нём команды из файла partitions.sql:
    MariaDB [zabbix]> SOURCE partitions.sql
    После выполнения команд таблицы будут разбиты на секции в соответствии с настройками, прописанными в скрипте partitions.py

    Перенос имеющихся данных в новые таблицы

    Можно было бы перенести данные из старых таблиц в новые простыми SQL-запросами вида INSERT INTO history_uint SELECT * FROM history_uint_bak, но такие запросы на время их работы будут полностью блокировать вставку новых данных в таблицу, поэтому надо переносить данные порциями. Я в этих целях пользуюсь командами следующего вида:
    $ mysqldump -t -uroot -p zabbix trends_uint_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    $ mysqldump -t -uroot -p zabbix trends_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    $ mysqldump -t -uroot -p zabbix history_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    $ mysqldump -t -uroot -p zabbix history_str_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    $ mysqldump -t -uroot -p zabbix history_text_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    $ mysqldump -t -uroot -p zabbix history_log_bak | grep ^INSERT | sed 's/^INSERT INTO/INSERT IGNORE/g' | mysql -uroot -p zabbix
    Это не красивое решение, но оно меня вполне устраивает, т.к. не приводит к длительной блокировке таблиц.

    После переноса данных в новые таблицы старые таблицы можно будет удалить:
    DROP TABLE history_bak;
    DROP TABLE history_uint_bak;
    DROP TABLE history_str_bak;
    DROP TABLE history_log_bak;
    DROP TABLE history_text_bak;
    DROP TABLE trends_bak;
    DROP TABLE trends_uint_bak;

    Настройки плагина TokuDB

    Просмотрев видеоролик с выступлением Владислава Лесина - одного из нынешних разработчиков TokuDB, работающего над этим плагином в компании Percona - я составил для себя список настроек плагина, на которые следует обратить внимание:

    tokudb_fanout - максимальное количество дочерних узлов

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

    tokudb_block_size - размер узла в памяти

    По умолчанию - 4 мегабайта.

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

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

    tokudb_read_block_size - размер базового узла

    По умолчанию - 64 килобайта.

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

    tokudb_row_format - алгоритм сжатия колонок

    Возможны следующие значения:
    • tokudb_default, tokudb_zlib - среднее сжатие при средней нагрузке на процессор.
    • tokudb_snappy - хорошее сжатие при низкой нагрузке на процессор.
    • tokudb_fast, tokudb_quicklz - слабое сжатие при низкой нагрузке на процессор.
    • tokudb_small, tokudb_lzma - лучшее сжатие при высокой нагрузке на процессор.
    • tokudb_uncompressed - сжатие не используется.

    tokudb_directio - использование прямого ввода-вывода

    Значение OFF позволяет использовать дисковый кэш операционной системы в качестве вторичного кэша для хранения сжатых узлов. Для ограничения использования памяти процессом mysqld нужно использовать cgroups.

    В качестве пищи для размышлений можно принять во внимание настройки, использованные в тесте производительности TokuDB, описание которого доступно по ссылке LinkeBench MySQL :
    tokudb_cache_size = 8G ; default = 12G ?
    tokudb_directio = OFF
    tokudb_empty_scan = disabled ; default - rl
    tokudb_read_block_size = 16K ; default - 64K
    tokudb_commit_sync = ON
    tokudb_checkpointing_period = 900 ; default = 60
    tokudb_block_size = 4M
    tokudb_cleaner_iterations = 10000 ; default = 5
    tokudb_fanout = 128 ; default = 16
    Я ограничился указанием подходящего значения tokudb_cache_size и изменением следующих настроек:
    tokudb_directio = ON
    tokudb_row_format = tokudb_lzma
    tokudb_empty_scan = disabled

    Решение проблем

    После обновления версии MariaDB пакетами из репозитория по неизвестным причинам планировщик перестаёт выполнять задачу по обслуживанию секций таблиц: не удаляет устаревшие секции и, что гораздо хуже, не создаёт новые секции таблиц. Последнее приводит к тому, что сервер Zabbix не может вставить в таблицы новые данные. Проявляется это в том, что после полуночи в последних данных на графиках нет данных, а сервер Zabbix ругается в журнал ошибками следующего вида:
    6619:20200604:000100.756 [Z3005] query failed: [1526] Table has no partition for value 1591210860 [insert into history
    (itemid,clock,ns,value) values (3827556,1591210860,519948235,0.012016),(3827601,1591210860,574265420,0.016382),
    (3827553,1591210860,683308669,7.549000),(3827616,1591210860,684083178,7.715000),(3827591,1591210860,684848189,3.199600),
    (3827583,1591210860,685585717,0.016474),(3827504,1591210860,689418268,24.000000),(3827564,1591210860,690132132,3.209600),
    (3827610,1591210860,690862622,0.014954),(1284053,1591210860,732901317,3.000000),(1283392,1591210860,737607405,23.000000),
    (352809,1591210860,737607405,35.000000),(1309072,1591210860,738428022,11.000000),(3827571,1591210860,740171802,7.187000),
    (1308475,1591210860,740185955,3.000000),(1292277,1591210860,743020934,1.000000),(3827619,1591210860,743278260,0.014760),
    (3827573,1591210860,743976749,3.254600),(3827598,1591210860,744811430,7.577000),(1284110,1591210860,745749025,21.000000),
    (3827580,1591210860,746661186,7.580000),(1279841,1591210860,747623084,5.000000),(3827607,1591210860,748043948,7.717000),
    (1282792,1591210860,749216640,15.000000);
    ]
    Если новые секции таблиц не создаются автоматически, то первым делом вручную вызываем обслуживание таблиц, чтобы сервер Zabbix мог начать писать данные:
    CALL partition_maintenance('zabbix', 'trends', 365, 24, 2);
    CALL partition_maintenance('zabbix', 'trends_uint', 365, 24, 2);
    CALL partition_maintenance('zabbix', 'history', 90, 6, 8);
    CALL partition_maintenance('zabbix', 'history_uint', 90, 6, 8);
    CALL partition_maintenance('zabbix', 'history_str', 7, 24, 2);
    CALL partition_maintenance('zabbix', 'history_text', 7, 24, 2);
    CALL partition_maintenance('zabbix', 'history_log', 7, 24, 2);
    Далее, чтобы в дальнейшем заработала автоматика, могут помочь следующие действия.

    Сначала обновляем таблицы в базах данных до текущей версии MySQL:
    $ mysql_upgrade --force -uroot -p mysql
    $ mysql_upgrade --force -uroot -p zabbix
    Затем пересоздаём запланированное задание:
    USE `zabbix`;
    DELIMITER $$

    CREATE EVENT IF NOT EXISTS `e_part_manage`
    ON SCHEDULE EVERY 1 DAY
    STARTS '2019-04-04 04:00:00'
    ON COMPLETION PRESERVE
    ENABLE
    COMMENT 'Управление созданием и удалением секций'
    DO BEGIN
    CALL partition_maintenance('zabbix', 'trends', 365, 24, 2);
    CALL partition_maintenance('zabbix', 'trends_uint', 365, 24, 2);
    CALL partition_maintenance('zabbix', 'history', 90, 6, 8);
    CALL partition_maintenance('zabbix', 'history_uint', 90, 6, 8);
    CALL partition_maintenance('zabbix', 'history_str', 7, 24, 2);
    CALL partition_maintenance('zabbix', 'history_text', 7, 24, 2);
    CALL partition_maintenance('zabbix', 'history_log', 7, 24, 2);
    END$$

    DELIMITER ;
    И напоследок перезапускаем сервер MariaDB:
    # systemctl restart mariadb
    Какое из приведённых решений помогает на самом деле, сказать точно не могу, т.к. я пробовал использовать каждый из советов поодиночке и не установил чёткой закономерности, какой из них помогает всегда. Иногда одно действие не лечит проблему и на следующий день можно заметить, что новые секции опять не создались.

    Značky: #linux, #stretch, #buster, #mariadb, #debian, #zabbix, #Linux, #mysql, #3.4, #tokudb

    • Sy chevron_right

      Настройка сервера MySQL

      pubsub.slavino.sk / sysadmblog · Sunday, 9 August, 2020 - 08:00 edit · 1 minute

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

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

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

    expire_logs_days

    Срок хранения журнала транзакций. Если данные часто и помногу обновляются, то для экономии места стоит задать значение поменьше, например 1 день:
    expire_logs_days = 1
    Однако, если вы используете репликацию данных на другой сервер, журналы стоит хранить за такой период времени, который может понадобиться на восстановление репликации при её поломке. В противном случае придётся повторно копировать данные с ведущего сервера на ведомый.

    transaction_isolation

    Уровень изоляции транзакций. Значение REPEATABLE-READ не покажет внутри транзакции новые данные, добавленные в другой транзакции. READ-COMMITED - наоборот, позволяет читать внутри транзакции данные, изменённые в других транзакциях.

    Большинству приложений важна целостность и непротиворечивость данных, поэтому они используют базу данных как транзакционную (OLTP). В таком случае лучше использовать значение REPEATABLE-READ.

    Если же приложение использует базу данных для аналитических запросов, то лучше подойдёт значение READ-COMMITED.

    Бывают и приложения со смешанной логикой. Например, Zabbix хранит в базе данных как собственную конфигурацию, что больше соответствует OLTP, так и исторические данные со значениями определённых показателей в конкретные моменты времени, что больше соответствует OLAP. Но, т.к. нужно обеспечить непротиворечивость данных конфигурации, то запросы к таблицам истории тоже придётся выполнять на уровне изоляции транзакций REPEATABLE-READ.
    transaction_isolation = REPEATABLE-READ
    Для уверенности стоит поискать настройки, рекомендуемые разработчиками приложения. Если информации найти не удалось, более безопасным выбором будет REPEATABLE-READ.

    innodb_file_per_table


    Настройка, предписывающая хранить каждую таблицу базы данных в отдельном файле. Перед её выставлением необходимо сделать резервную копию всех баз данных. Чтобы настройка вступила в силу, нужно:
    1. остановить MySQL,
    2. удалить файлы ibdata1, ib_logfile0 и ib_logfile1,
    3. запустить MySQL снова,
    4. восстановить базы данных из резервных копий.
    При восстановлении данных MySQL поместит каждую таблицу в отдельный файл.

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

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

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

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

    innodb_file_per_table = 1

    table_cache

    Количество одновременно открытых файлов таблиц. Позволяет уменьшить количество открытий-закрытий файлов. Стоит оценить количество файлов в каталоге, где хранятся файлы с данными MySQL и выставить значение равного порядка.
    table_cache = 512
    Стоит учитывать, что операционная система ограничивает количество одновременно открытых одним пользователем файлов и значение, указанное в опции, не должно быть больше разрешённого операционной системой лимита.

    event_scheduler

    Настройка, включающая встроенный в сервер MySQL планировщик задач. Позволяет по расписанию запускать запросы или хранимые процедуры:
    event_scheduler = 1

    max_connections

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

    В случае веб-приложений нет особого смысла выставлять эту настройку намного больше количества процессов сервера приложения. Если в php-fpm или uwsgi для работы приложения выделено 16 процессов, то как правило каждый процесс будет устанавливать не более одного подключения к базе данных.
    max_connections = 140

    query_cache_size

    Кэш результатов прошлых запросов. Если содержимое таблиц, фигурирующих в запросе, не менялось с момента кэширования результата предыдущего такого же запроса, то этот кэш позволит серверу сразу выдать клиенту результат запроса из кэша:
    query_cache_size = 64M
    Если содержимое таблиц постоянно меняется, а вероятность повторного выполнения запроса низка, то отключение этого кэша никак не скажется на производительности СУБД, но позволит сэкономить немного оперативной памяти. Для отключения кэша запросов можно указать такие опции:
    query_cache_type = 0
    query_cache_size = 0

    general_log_file

    Общий журнал. Содержит, например, сведения о запусках и остановках сервера.
    general_log_file = /var/log/mysql/mysql.log

    log_error

    Журнал ошибок:
    log_error = /var/log/mysql/mysql.err

    log_warnings

    Не выводить предупреждающие сообщения в журнале ошибок:
    log_warnings = 0

    character-set-server и collation-server

    Настройка кодировки сервера по умолчанию и настроек сортировки и сравнения символов:
    character-set-server = utf8
    collation-server = utf8_general_ci

    join_buffer_size

    Буфер, используемый для соединения таблиц друг с другом. При недостаточном объёме буфера соединение будет осуществляться с использованием диска:
    join_buffer_size = 16M

    innodb_buffer_pool_size и innodb_buffer_pool_instances

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

    Если под MySQL выделен отдельный сервер, можно рассчитать размер этого буфера исходя из общего размера доступной на сервере памяти и объёма буферов под обработку запросов от каждого из максимально возможного количества клиентов (max_connections):
    innodb_buffer_pool_size = 512M
    В интернете можно встретить рекомендации делить буферные пулы размерами больше гигабайта на несколько экземпляров, чтобы на каждый из экземпляров приходилось, например, по одному гигабайту:
    innodb_buffer_pool_size = 10G
    innodb_buffer_pool_instances = 10

    innodb_flush_method

    Метод записи данных в файловую систему. Часто встречается рекомендация не использовать дисковый кэш операционной системы, т.к. у сервера MySQL есть собственные буферы, а двойная буферизация замедляет работу и повышает вероятность повреждения данных:
    innodb_flush_method = O_DIRECT

    innodb_log_file_size, innodb_log_buffer_size и innodb_flush_log_at_trx_commit

    Настройки журналов транзакций. Если в журнал данные пишутся помногу и часто, имеет смысл увеличить как размер самого журнала, чтобы серверу реже приходилось создавать новые файлы и переоткрывать их, так и увеличить размер буфера записи, чтобы снизить частоту блокирования сервера в ожидании записи в журнал транзакций:
    innodb_log_file_size = 256M
    innodb_log_buffer_size = 8M
    Таких файлов у MySQL два. Рекомендуется, чтобы размер каждого из них составлял 1/4 от размера innodb_buffer_pool_size. Однако размер файла журнала должен быть меньше 2 гигабайт - это внутреннее ограничение MySQL.

    У журнала транзакций имеется настройка, аналогичная настройке буферного пула innodb_flush_method:
    innodb_flush_log_at_trx_commit = 2
    Возможны следующие значения:
    • 1 - каждая транзакция после фиксации записывается на диск (наибольшая надёжность),
    • 2 - транзакция после фиксации записывается в кэш операционной системы (компромисс между надёжностью и производительностью),
    • 0 - нет требования специально сохранять данные транзакции после её фиксации, данные сохраняются по мере заполнения буфера транзакций (наибольшая производительность, но высокий риск потери данных).

    Временные файлы

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

    Создаём точку монтирования, например /mysql-tmp:
    # cd /
    # mkdir mysql-tmp
    Добавляем в файл /etc/fstab строчку для монитрования раздела размером, например, 512 мегабайт:
    tmpfs /mysql-tmp tmpfs relatime,nodev,nosuid,noexec,uid=mysql,gid=mysql,mode=0760,size=512M 0 0
    Смонтируем временный раздел:
    # mount /mysql-tmp
    Теперь нужно указать в файле конфигурации сервера MySQL внутри секции server соответствующую опцию:
    tmpdir = /mysql-tmp
    И перезапустить MySQL:
    # systemctl restart mysql
    Стоит учитывать, что если места на этом разделе окажется недостаточно, запрос не выполнится и MySQL сообщит об ошибке выполнения запроса.

    Značky: #linux, #mysql, #debian, #Linux

    • Sy chevron_right

      Правка service-файла snmptrapd

      noreply@blogger.com (morbo) · pubsub.slavino.sk / sysadmblog · Sunday, 2 August, 2020 - 08:00 edit · 1 minute

    После обновления на одном из серверов Debian Wheezy до Debian Stretch перестала работать обработка трапов демоном snmptrapd. Как выяснилось, проблема была в том, что snmptrapd был запущен не с теми опциями, которые были указаны в файле с его настройками. В файле /etc/default/snmptrapd была указана переменная с опциями:
    TRAPDOPTS='-Lf /dev/null -n -t -Oqnet'
    Реально же демон snmptrapd запускался с опциями -Lsd -f

    Из-за этого в скрипт обработки трапов OID'ы попадали в символьном виде:
    SNMPv2-SMI::enterprises.1332.3.1.1.4.5.0
    А скрипт был расчитан на обработку OID'ов в числовом виде:
    .1.3.6.1.4.1.1332.3.1.1.4.5.0
    После обновления операционной системы на сервере с Debian Wheezy до Debian Stretch, в нём поменялась система инициализации с System V Init на Systemd.

    В комплекте с Systemd поставляется такой service-файл /lib/systemd/system/snmptrapd.service для запуска snmptrapd:
    [Unit]
    Description=Simple Network Management Protocol (SNMP) Trap Daemon.
    After=network.target
    ConditionPathExists=/etc/snmp/snmptrapd.conf

    [Service]
    Environment="MIBSDIR=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp"
    Type=simple
    ExecStart=/usr/sbin/snmptrapd -Lsd -f
    ExecReload=/bin/kill -HUP $MAINPID

    [Install]
    WantedBy=multi-user.target
    Как видно, опции, с которыми должен запускаться snmptrapd, в нём прошиты жёстко, а не берутся из файла /etc/default/snmptrapd.

    Создал вместо этого стандартного service-файла свой собственный файл /etc/systemd/system/snmptrapd.service со следующим содержимым:
    [Unit]
    Description=Simple Network Management Protocol (SNMP) Trap Daemon.
    After=network.target
    ConditionPathExists=/etc/snmp/snmptrapd.conf

    [Service]
    Environment="MIBSDIR=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp"
    EnvironmentFile=/etc/default/snmptrapd
    Type=simple
    ExecStart=/usr/sbin/snmptrapd $TRAPDOPTS -f
    ExecReload=/bin/kill -HUP $MAINPID

    [Install]
    WantedBy=multi-user.target
    Чтобы о новом service-файле узнал systemd, нужно выполнить следующую команду:
    # systemctl daemon-reload
    А чтобы демон snmptrapd запустился с новыми опциями, нужно его перезапустить:
    # systemctl restart snmptrapd
    Теперь опции для snmptrapd стали браться из файла /etc/default/snmptrapd, как и было до этого.

    Značky: #debian, #linux, #snmp, #stretch, #systemd, #Linux