• 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

      Правка 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

    • Ha chevron_right

      Quand Debian me gonfle : Stretch et OpenVPN

      raspbeguy · pubsub.gugod.fr / hashtagueule · Saturday, 1 July, 2017 - 22:00 · 5 minutes

    Comme vous le savez sûrement, la nouvelle version stable de Debian, nom de code Stretch, est sortie. Je vous conseille à tous de faire la mise à jour les yeux fermés, ça va bien se passer, aucun accrochage à déplorer, un simple apt dist-upgrade et c'est une affaire qui roule. ... Nan j'déconne. Enfi...

    Comme vous le savez sûrement, la nouvelle version stable de Debian, nom de code Stretch, est sortie. Je vous conseille à tous de faire la mise à jour les yeux fermés, ça va bien se passer, aucun accrochage à déplorer, un simple apt dist-upgrade et c'est une affaire qui roule.

    ...

    Nan j'déconne.

    Enfin je vous conseille quand même de faire la mise à jour bien entendu, pour des raisons évidentes de sécurité, prévoyez de le faire au moins à long terme. Parce que bon, la oldstable est toujours supportée à travers des mises à jour de sécurité, mais après y a plus rien, et votre serveur est livré à lui même et aux attaquants qui sauront profiter de failles non corrigées.

    Ce que je veux dire, c'est qu'en mettant à jour votre distribution, attendez-vous à des trucs qui vont péter sévère. Faites-ça quand vous n'avez rien d'autre à faire et quand un minimum de choses vitales sont attendues de votre serveur par vos utilisateurs. Va y avoir du vilain.

    Et hop c'est cassé

    Donc oui j'aime Debian, mais Debian me gonfle parfois. Notamment ce comportement très fâcheux que je viens de découvrir aujourd'hui même concernant OpenVPN.

    OpenVPN, j'en ai déjà parlé et je ne m'étendrai pas plus là dessus, est un outil permettant de construire des réseaux virtuels privés (VPN), utiles pour abstraire des réseaux entre des machines géographiquement distantes et/ou pour déporter son point de sortie pour "sembler" se connecter d'ailleurs. Il y a donc une machine qui crée le VPN, dite serveur ou tête de pont, et des machines qui s'y connectent à distance, dites clients.

    J'ai donc une tête de pont que j'ai récemment mis à jour sur Stretch. Tout se passa bien entendu parfaitement en apparence, et tout le monde il était beau. Je me retrouvai avec une jolie Debian Stretch toute mignonne dont le cœur et l'âme n'aurait en aucun cas pu être mis en doute par quiconque. Sauf que sous ses jupons, elle avait dissimulé des trucs moins fun. Et en conséquence, quelques jours après, je me rendis compte que mes clients OpenVPN ne se voyaient plus. Je ne mis pas longtemps à soupçonner la belle Stretch d'avoir des aveux à me faire.

    L'élément fautif : le service Systemd a changé bien en profondeur.  Sous Jessie, les fichiers nécessaires pour l'établissement du VPN (configurations, certificats, clefs...) se trouvaient alors modestement dans /etc/openvpn, et ne faisait pas la distinction entre configurations clients et configurations serveurs. Le service utilisé pour démarrer OpenVPN était nommé tout simplement openvpn.service, et son boulot était uniquement de lancer une instance d'OpenVPN par fichier de configuration (dont le nom se terminait par .conf) dans ce dossier. Pour lancer openvpn, il suffisait donc de la commande simple suivante :

    systemctl start openvpn

    Sous Stretch, tout a été changé. Premièrement, le service a changé de nom très salement. Par salement, je veux dire que l'ancien nom existe toujours, mais a été remplacé par un service qui ne fait absolument rien (il lance le programme /bin/true, programme dont l'utilité crève les yeux), ce qui fait que ce changement de service implique non seulement une rupture de ce service si aucune action n'est prise par la suite, mais également que c'est très difficile de s'en rendre compte, le service ancien openvpn.service étant diagnostiqué par le système comme actif et bien portant. Donc, la nouvelle forme de ce service est en fait un couple de service, openvpn-client@.service et openvpn-server@.service, le premier se chargeant de lancer OpenVPN en temps que client, et le second en temps que serveur. Mais ce n'était pas fini : les configurations VPN devaient être déplacées aux nouveaux endroits adéquats, et la ségrégation entre clients et serveurs a été instaurée : désormais, les configurations clients doivent aller dans /etc/openvpn/client et les configurations serveurs dans /etc/openvpn/server. Mais ce n'est encore pas tout : ces nouveaux services ne s'invoquent plus de la même manière. On doit maintenant spécifier le nom de la configuration dans la commande qui démarre le service. Par exemple, pour une configuration serveur qui s'appelle hashtagueule.conf (dûment placée dans /etc/openvpn/server), la commande pour démarrer le service associé est donc :

    systemctl start openvpn-server@hashtagueule

    Pour couronner le tout, un bug de configuration, oui un bug, et non une modification de comportement, s'est glissée dans le fichier de service openvpn-serveur@.service. Ce fichier comporte la ligne suivante :

    LimitNPROC=10

    Cette directive est utile pour contrôler le nombre maximum de processus exécutés par un service, pour éviter dans certain cas l'explosion du load du serveur. Sauf qu'ici, cette valeur est beaucoup trop petite. On se retrouve alors avec l'erreur suivante consignée dans les logs :

    openvpn_execve: unable to fork: Resource temporarily unavailable

    Ce qui veut dire que le système refuse la création d'un nouveau processus pour ce service. Je me résolus donc à réparer salement et de manière non safisfaisante en changeant la valeur 10 par 100 (aucune idée si c'est carrément trop), et enfin, le service a accepté de fonctionner.

    Quelle leçon tirer de cette aventure ? Premièrement, les mises à jour sont rarement simple, surtout dans le cas de Debian. Deuxièmement, même si le nouveau fonctionnement d'OpenVPN est désormais plus propre et correspond à l'usage conventionné sur les systèmes les plus récents, on peut déplorer la manière dont elle a été mise en place. Le bon usage aurait été d'instaurer une période de transition pendant laquelle les deux workflows auraient coexisté, plutôt que de casser brutalement une configuration existante et fonctionnelle. Et je ne parle même pas de la mauvaise limite du nombre de processus...

    En espérant que cette histoire aura été utile à des gens, je vous souhaite une bonne mise à jour.

    • At chevron_right

      Quand Debian me gonfle : Stretch et OpenVPN

      raspbeguy · pubsub.gugod.fr / atomtest · Saturday, 1 July, 2017 - 22:00 · 5 minutes

    Comme vous le savez sûrement, la nouvelle version stable de Debian, nom de code Stretch, est sortie. Je vous conseille à tous de faire la mise à jour les yeux fermés, ça va bien se passer, aucun accrochage à déplorer, un simple apt dist-upgrade et c'est une affaire qui roule. ... Nan j'déconne. Enfi...

    Comme vous le savez sûrement, la nouvelle version stable de Debian, nom de code Stretch, est sortie. Je vous conseille à tous de faire la mise à jour les yeux fermés, ça va bien se passer, aucun accrochage à déplorer, un simple apt dist-upgrade et c'est une affaire qui roule.

    ...

    Nan j'déconne.

    Enfin je vous conseille quand même de faire la mise à jour bien entendu, pour des raisons évidentes de sécurité, prévoyez de le faire au moins à long terme. Parce que bon, la oldstable est toujours supportée à travers des mises à jour de sécurité, mais après y a plus rien, et votre serveur est livré à lui même et aux attaquants qui sauront profiter de failles non corrigées.

    Ce que je veux dire, c'est qu'en mettant à jour votre distribution, attendez-vous à des trucs qui vont péter sévère. Faites-ça quand vous n'avez rien d'autre à faire et quand un minimum de choses vitales sont attendues de votre serveur par vos utilisateurs. Va y avoir du vilain.

    Et hop c'est cassé

    Donc oui j'aime Debian, mais Debian me gonfle parfois. Notamment ce comportement très fâcheux que je viens de découvrir aujourd'hui même concernant OpenVPN.

    OpenVPN, j'en ai déjà parlé et je ne m'étendrai pas plus là dessus, est un outil permettant de construire des réseaux virtuels privés (VPN), utiles pour abstraire des réseaux entre des machines géographiquement distantes et/ou pour déporter son point de sortie pour "sembler" se connecter d'ailleurs. Il y a donc une machine qui crée le VPN, dite serveur ou tête de pont, et des machines qui s'y connectent à distance, dites clients.

    J'ai donc une tête de pont que j'ai récemment mis à jour sur Stretch. Tout se passa bien entendu parfaitement en apparence, et tout le monde il était beau. Je me retrouvai avec une jolie Debian Stretch toute mignonne dont le cœur et l'âme n'aurait en aucun cas pu être mis en doute par quiconque. Sauf que sous ses jupons, elle avait dissimulé des trucs moins fun. Et en conséquence, quelques jours après, je me rendis compte que mes clients OpenVPN ne se voyaient plus. Je ne mis pas longtemps à soupçonner la belle Stretch d'avoir des aveux à me faire.

    L'élément fautif : le service Systemd a changé bien en profondeur.  Sous Jessie, les fichiers nécessaires pour l'établissement du VPN (configurations, certificats, clefs...) se trouvaient alors modestement dans /etc/openvpn, et ne faisait pas la distinction entre configurations clients et configurations serveurs. Le service utilisé pour démarrer OpenVPN était nommé tout simplement openvpn.service, et son boulot était uniquement de lancer une instance d'OpenVPN par fichier de configuration (dont le nom se terminait par .conf) dans ce dossier. Pour lancer openvpn, il suffisait donc de la commande simple suivante :

    systemctl start openvpn

    Sous Stretch, tout a été changé. Premièrement, le service a changé de nom très salement. Par salement, je veux dire que l'ancien nom existe toujours, mais a été remplacé par un service qui ne fait absolument rien (il lance le programme /bin/true, programme dont l'utilité crève les yeux), ce qui fait que ce changement de service implique non seulement une rupture de ce service si aucune action n'est prise par la suite, mais également que c'est très difficile de s'en rendre compte, le service ancien openvpn.service étant diagnostiqué par le système comme actif et bien portant. Donc, la nouvelle forme de ce service est en fait un couple de service, openvpn-client@.service et openvpn-server@.service, le premier se chargeant de lancer OpenVPN en temps que client, et le second en temps que serveur. Mais ce n'était pas fini : les configurations VPN devaient être déplacées aux nouveaux endroits adéquats, et la ségrégation entre clients et serveurs a été instaurée : désormais, les configurations clients doivent aller dans /etc/openvpn/client et les configurations serveurs dans /etc/openvpn/server. Mais ce n'est encore pas tout : ces nouveaux services ne s'invoquent plus de la même manière. On doit maintenant spécifier le nom de la configuration dans la commande qui démarre le service. Par exemple, pour une configuration serveur qui s'appelle hashtagueule.conf (dûment placée dans /etc/openvpn/server), la commande pour démarrer le service associé est donc :

    systemctl start openvpn-server@hashtagueule

    Pour couronner le tout, un bug de configuration, oui un bug, et non une modification de comportement, s'est glissée dans le fichier de service openvpn-serveur@.service. Ce fichier comporte la ligne suivante :

    LimitNPROC=10

    Cette directive est utile pour contrôler le nombre maximum de processus exécutés par un service, pour éviter dans certain cas l'explosion du load du serveur. Sauf qu'ici, cette valeur est beaucoup trop petite. On se retrouve alors avec l'erreur suivante consignée dans les logs :

    openvpn_execve: unable to fork: Resource temporarily unavailable

    Ce qui veut dire que le système refuse la création d'un nouveau processus pour ce service. Je me résolus donc à réparer salement et de manière non safisfaisante en changeant la valeur 10 par 100 (aucune idée si c'est carrément trop), et enfin, le service a accepté de fonctionner.

    Quelle leçon tirer de cette aventure ? Premièrement, les mises à jour sont rarement simple, surtout dans le cas de Debian. Deuxièmement, même si le nouveau fonctionnement d'OpenVPN est désormais plus propre et correspond à l'usage conventionné sur les systèmes les plus récents, on peut déplorer la manière dont elle a été mise en place. Le bon usage aurait été d'instaurer une période de transition pendant laquelle les deux workflows auraient coexisté, plutôt que de casser brutalement une configuration existante et fonctionnelle. Et je ne parle même pas de la mauvaise limite du nombre de processus...

    En espérant que cette histoire aura été utile à des gens, je vous souhaite une bonne mise à jour.