System administration
June 2011 9

Zabbix, мониторинг портов последней мили и оптимизация работы с БД с использованием partitioning

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


В наличии был только один сервер HP с двумя процессорам и 4 ядрами на борту, памяти было 10G, Raid5 132G 15000 SAS.
Основное количество абонентских портов это порты ADSL на различных DSLAM, как большой емкости — до 576 портов на «корзину» так и малопортовых — от 16 до 64 портов, в зависимости от конфигурации.

Определим как будем мониторить и строить триггеры


Что можно получить с dslam'a? Практически все, вопрос только как это сделать. Для меня самый верный способ это опрос по snmp. Вся беда была в том что MIB файлы к большинству железок не доступны простым смертным из-за выкрутасов производителей с заключением кучи договоров и прочих непонятных мне препятствий (к чести huawei mib'ы они все же прислали без различных договоров, а вот по другому поставщику их так и не удается получить). Если ваша ситуация схожа с моей то берем в руки snmpwalk и анализируем все что выдает железка, а выдаст она очень много, мегабайты текста. Анализ полученных oid очень трудоемкий процесс. Хорошо если есть готовые шаблоны для zabbix или есть mib (тогда шаблоны из них можно сделать быстро и легко прочитав это топик «подключаем любую железку имеющую MIB» habrahabr.ru/blogs/sysadm/85156)
После того как получили шаблоны нужно определить, что же будем собирать, с какой периодичностью и сколько времени хранить. Все эти параметры в итоге задаются в рабочем шаблоне который и будем привязывать к железкам.

Мой набор вышел не сильно большим, к примеру для dslam'a большой емкости параметры собираемые с первого порта


1.01ifAtucFfrADSL 1.01ifAtucFrADSL количество ретрайнов
1.01ifAtucLossADSL количество потерь сигнала
1.01ifDownSnrADSL 1.01ifUpSnrADSL шумы
1.01ifDownSpeedADSL 1.01ifUpSpeedADSL реальная скорость на абонентской линии
и не активные, но включаемые при необходимости расширенного анализа состояния порта
1.01ifOperPhysicalStatADSL физическое состояние порта
1.01ifOperStatADSL состояние порта


И дополнительный шаблон с элементами которые можно включить.

1.01ifDownAttenuationADSL 1.01ifUpAttenuationADSL затухание в линии
1.01ifDownOutputPowerADSL 1.01ifUpOutputPowerADSL мощность сигнала
1.01ifDownSpeedMaxADSL 1.01ifUpSpeedMaxADSL максимально возможная достижимая скорость
1.01ifProfSpeedADSL профиль на порту


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

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

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

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

Данные можно представить в виде графика по времени


Так же были у меня интересные китайские коммутаторы Edge-core от коих я избавился в пользу Huawei, так с ними я делал такой шаблон, который опрашивал результаты измерения абонентских кабелей рефлектометром и анализируя полученные результаты выдавал список портов с неисправными UTP. Эти измерения можно было провести послав на железки по snmp команду либо скриптом из забикса, либо кроном. Этот шаблон я так и не доделал из-за замены всех ежей на хуявеи.

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

Приступим к настройке БД под Zabbix


На данный момент последняя стабильная ветка 1.8.5 скачать её можно с официального сайта www.zabbix.com/download.php
Инструкцию как его установить и сделать первоначальную настройку приводить не буду, так как она есть на сайте www.zabbix.com/documentation/start

У меня все стоит на Ubuntu server 10.04 64 bit. В качестве БД первоначально было Postgresql 8.4 далее 9.0 сейчас переехал на MySQL 5.5, поставленную на сервер согласно официальному руководству и небольшого допиливания напильником. Причина переезда поддержка partitioning table dev.mysql.com/doc/refman/5.5/en/partitioning.html" (ну и не смог я заставить работать постгрес так же быстро как мускул сколько не бился, похоже не умею я его готовить, ЗЫ partition table есть в постгрессе, но реализован он несколько иначе чем в мускуле).

Конфигурация MySQL не сложная и хорошо описана на форуме вот пример топика по которому я настраивал MySQL www.zabbix.com/forum/showthread.php?t=12407

Отмечу ключевую обязательную опцию
innodb_file_per_table

Движок по умолчанию надо выставить innodb, кодировку utf-8.
Если будет очень любопытно выложу конфигу.

Zabbix сохраняет в БД множество значений основные большие таблицы это hystory* и trend*
Первоначально в таблицах истории у меня было до 500 миллионов записей и весила эта таблица порядка 40 гигов с индексным файлом, что вызывало некоторые проблемы с производительностью.
Данные собранные с абонентских портов в среднем хранятся около 3 дней. Старые данные при этом удаляются housekeeper'ом оставляя после этого фрагментированые таблицы. Насколько это плохо думаю не нужно объяснять.
Что же делать в этом случае? Ответ есть — использовать partition table с разделением по времени. Для этого я воспользовался опытом из блога Бразильского товарища zabbixzone.com/zabbix/partitioning-tables
Он предлагает разделить таблицы на 2 типа: большие — с делением по дням, и не очень большие — с делением по месяцам.
Вот эти таблицы с делением по дням:
  • history
  • history_log
  • history_str
  • history_text
  • history_uint

и с делением по месяцам:
  • acknowledges
  • alerts
  • auditlog
  • events
  • service_alarms
  • trends
  • trends_unit


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

Сначала делаем дамп каждой таблицы которую собираемся менять
mysqldump --no-create-info --lock-tables zabbix history_str > 09.06.2011_history_str.sql

Очищаем выше обозначенные таблицы от данных.
Слегка меняем структуры таблиц

ALTER TABLE `acknowledges` DROP PRIMARY KEY, ADD KEY `acknowledgedid` (`acknowledgeid`);
ALTER TABLE `alerts` DROP PRIMARY KEY, ADD KEY `alertid` (`alertid`);
ALTER TABLE `auditlog` DROP PRIMARY KEY, ADD KEY `auditid` (`auditid`);
ALTER TABLE `events` DROP PRIMARY KEY, ADD KEY `eventid` (`eventid`);
ALTER TABLE `service_alarms` DROP PRIMARY KEY, ADD KEY `servicealarmid` (`servicealarmid`);
ALTER TABLE `history_log` DROP PRIMARY KEY, ADD PRIMARY KEY (`itemid`,`id`,`clock`);
ALTER TABLE `history_log` DROP KEY `history_log_2`;
ALTER TABLE `history_text` DROP PRIMARY KEY, ADD PRIMARY KEY (`itemid`,`id`,`clock`);
ALTER TABLE `history_text` DROP KEY `history_text_2`;


* This source code was highlighted with Source Code Highlighter.


Создаем partition table с делением по месяцам до 2013 года

ALTER TABLE `acknowledges` PARTITION BY RANGE( clock ) (
PARTITION p201105 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-01 00:00:00")),
PARTITION p201106 VALUES LESS THAN (UNIX_TIMESTAMP("2011-07-01 00:00:00")),
PARTITION p201107 VALUES LESS THAN (UNIX_TIMESTAMP("2011-08-01 00:00:00")),
PARTITION p201108 VALUES LESS THAN (UNIX_TIMESTAMP("2011-09-01 00:00:00")),
PARTITION p201109 VALUES LESS THAN (UNIX_TIMESTAMP("2011-10-01 00:00:00")),
PARTITION p201110 VALUES LESS THAN (UNIX_TIMESTAMP("2011-11-01 00:00:00")),
PARTITION p201111 VALUES LESS THAN (UNIX_TIMESTAMP("2011-12-01 00:00:00")),
PARTITION p201112 VALUES LESS THAN (UNIX_TIMESTAMP("2012-01-01 00:00:00")),
PARTITION p201201 VALUES LESS THAN (UNIX_TIMESTAMP("2012-02-01 00:00:00")),
PARTITION p201202 VALUES LESS THAN (UNIX_TIMESTAMP("2012-03-01 00:00:00")),
PARTITION p201203 VALUES LESS THAN (UNIX_TIMESTAMP("2012-04-01 00:00:00")),
PARTITION p201204 VALUES LESS THAN (UNIX_TIMESTAMP("2012-05-01 00:00:00")),
PARTITION p201205 VALUES LESS THAN (UNIX_TIMESTAMP("2012-06-01 00:00:00")),
PARTITION p201206 VALUES LESS THAN (UNIX_TIMESTAMP("2012-07-01 00:00:00")),
PARTITION p201207 VALUES LESS THAN (UNIX_TIMESTAMP("2012-08-01 00:00:00")),
PARTITION p201208 VALUES LESS THAN (UNIX_TIMESTAMP("2012-09-01 00:00:00")),
PARTITION p201209 VALUES LESS THAN (UNIX_TIMESTAMP("2012-10-01 00:00:00")),
PARTITION p201210 VALUES LESS THAN (UNIX_TIMESTAMP("2012-11-01 00:00:00")),
PARTITION p201211 VALUES LESS THAN (UNIX_TIMESTAMP("2012-12-01 00:00:00")),
PARTITION p201212 VALUES LESS THAN (UNIX_TIMESTAMP("2013-01-01 00:00:00"))
);

ALTER TABLE `alerts` PARTITION BY RANGE( clock ) (
PARTITION p201105 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-01 00:00:00")),
PARTITION p201106 VALUES LESS THAN (UNIX_TIMESTAMP("2011-07-01 00:00:00")),
PARTITION p201107 VALUES LESS THAN (UNIX_TIMESTAMP("2011-08-01 00:00:00")),
PARTITION p201108 VALUES LESS THAN (UNIX_TIMESTAMP("2011-09-01 00:00:00")),
PARTITION p201109 VALUES LESS THAN (UNIX_TIMESTAMP("2011-10-01 00:00:00")),
PARTITION p201110 VALUES LESS THAN (UNIX_TIMESTAMP("2011-11-01 00:00:00")),
PARTITION p201111 VALUES LESS THAN (UNIX_TIMESTAMP("2011-12-01 00:00:00")),
PARTITION p201112 VALUES LESS THAN (UNIX_TIMESTAMP("2012-01-01 00:00:00")),
PARTITION p201201 VALUES LESS THAN (UNIX_TIMESTAMP("2012-02-01 00:00:00")),
PARTITION p201202 VALUES LESS THAN (UNIX_TIMESTAMP("2012-03-01 00:00:00")),
PARTITION p201203 VALUES LESS THAN (UNIX_TIMESTAMP("2012-04-01 00:00:00")),
PARTITION p201204 VALUES LESS THAN (UNIX_TIMESTAMP("2012-05-01 00:00:00")),
PARTITION p201205 VALUES LESS THAN (UNIX_TIMESTAMP("2012-06-01 00:00:00")),
PARTITION p201206 VALUES LESS THAN (UNIX_TIMESTAMP("2012-07-01 00:00:00")),
PARTITION p201207 VALUES LESS THAN (UNIX_TIMESTAMP("2012-08-01 00:00:00")),
PARTITION p201208 VALUES LESS THAN (UNIX_TIMESTAMP("2012-09-01 00:00:00")),
PARTITION p201209 VALUES LESS THAN (UNIX_TIMESTAMP("2012-10-01 00:00:00")),
PARTITION p201210 VALUES LESS THAN (UNIX_TIMESTAMP("2012-11-01 00:00:00")),
PARTITION p201211 VALUES LESS THAN (UNIX_TIMESTAMP("2012-12-01 00:00:00")),
PARTITION p201212 VALUES LESS THAN (UNIX_TIMESTAMP("2013-01-01 00:00:00"))
);

ALTER TABLE `auditlog` PARTITION BY RANGE( clock ) (
PARTITION p201105 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-01 00:00:00")),
PARTITION p201106 VALUES LESS THAN (UNIX_TIMESTAMP("2011-07-01 00:00:00")),
PARTITION p201107 VALUES LESS THAN (UNIX_TIMESTAMP("2011-08-01 00:00:00")),
PARTITION p201108 VALUES LESS THAN (UNIX_TIMESTAMP("2011-09-01 00:00:00")),
PARTITION p201109 VALUES LESS THAN (UNIX_TIMESTAMP("2011-10-01 00:00:00")),
PARTITION p201110 VALUES LESS THAN (UNIX_TIMESTAMP("2011-11-01 00:00:00")),
PARTITION p201111 VALUES LESS THAN (UNIX_TIMESTAMP("2011-12-01 00:00:00")),
PARTITION p201112 VALUES LESS THAN (UNIX_TIMESTAMP("2012-01-01 00:00:00")),
PARTITION p201201 VALUES LESS THAN (UNIX_TIMESTAMP("2012-02-01 00:00:00")),
PARTITION p201202 VALUES LESS THAN (UNIX_TIMESTAMP("2012-03-01 00:00:00")),
PARTITION p201203 VALUES LESS THAN (UNIX_TIMESTAMP("2012-04-01 00:00:00")),
PARTITION p201204 VALUES LESS THAN (UNIX_TIMESTAMP("2012-05-01 00:00:00")),
PARTITION p201205 VALUES LESS THAN (UNIX_TIMESTAMP("2012-06-01 00:00:00")),
PARTITION p201206 VALUES LESS THAN (UNIX_TIMESTAMP("2012-07-01 00:00:00")),
PARTITION p201207 VALUES LESS THAN (UNIX_TIMESTAMP("2012-08-01 00:00:00")),
PARTITION p201208 VALUES LESS THAN (UNIX_TIMESTAMP("2012-09-01 00:00:00")),
PARTITION p201209 VALUES LESS THAN (UNIX_TIMESTAMP("2012-10-01 00:00:00")),
PARTITION p201210 VALUES LESS THAN (UNIX_TIMESTAMP("2012-11-01 00:00:00")),
PARTITION p201211 VALUES LESS THAN (UNIX_TIMESTAMP("2012-12-01 00:00:00")),
PARTITION p201212 VALUES LESS THAN (UNIX_TIMESTAMP("2013-01-01 00:00:00"))
);

ALTER TABLE `events` PARTITION BY RANGE( clock ) (
PARTITION p201105 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-01 00:00:00")),
PARTITION p201106 VALUES LESS THAN (UNIX_TIMESTAMP("2011-07-01 00:00:00")),
PARTITION p201107 VALUES LESS THAN (UNIX_TIMESTAMP("2011-08-01 00:00:00")),
PARTITION p201108 VALUES LESS THAN (UNIX_TIMESTAMP("2011-09-01 00:00:00")),
PARTITION p201109 VALUES LESS THAN (UNIX_TIMESTAMP("2011-10-01 00:00:00")),
PARTITION p201110 VALUES LESS THAN (UNIX_TIMESTAMP("2011-11-01 00:00:00")),
PARTITION p201111 VALUES LESS THAN (UNIX_TIMESTAMP("2011-12-01 00:00:00")),
PARTITION p201112 VALUES LESS THAN (UNIX_TIMESTAMP("2012-01-01 00:00:00")),
PARTITION p201201 VALUES LESS THAN (UNIX_TIMESTAMP("2012-02-01 00:00:00")),
PARTITION p201202 VALUES LESS THAN (UNIX_TIMESTAMP("2012-03-01 00:00:00")),
PARTITION p201203 VALUES LESS THAN (UNIX_TIMESTAMP("2012-04-01 00:00:00")),
PARTITION p201204 VALUES LESS THAN (UNIX_TIMESTAMP("2012-05-01 00:00:00")),
PARTITION p201205 VALUES LESS THAN (UNIX_TIMESTAMP("2012-06-01 00:00:00")),
PARTITION p201206 VALUES LESS THAN (UNIX_TIMESTAMP("2012-07-01 00:00:00")),
PARTITION p201207 VALUES LESS THAN (UNIX_TIMESTAMP("2012-08-01 00:00:00")),
PARTITION p201208 VALUES LESS THAN (UNIX_TIMESTAMP("2012-09-01 00:00:00")),
PARTITION p201209 VALUES LESS THAN (UNIX_TIMESTAMP("2012-10-01 00:00:00")),
PARTITION p201210 VALUES LESS THAN (UNIX_TIMESTAMP("2012-11-01 00:00:00")),
PARTITION p201211 VALUES LESS THAN (UNIX_TIMESTAMP("2012-12-01 00:00:00")),
PARTITION p201212 VALUES LESS THAN (UNIX_TIMESTAMP("2013-01-01 00:00:00"))
);

ALTER TABLE `service_alarms` PARTITION BY RANGE( clock ) (
PARTITION p201105 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-01 00:00:00")),
PARTITION p201106 VALUES LESS THAN (UNIX_TIMESTAMP("2011-07-01 00:00:00")),
PARTITION p201107 VALUES LESS THAN (UNIX_TIMESTAMP("2011-08-01 00:00:00")),
PARTITION p201108 VALUES LESS THAN (UNIX_TIMESTAMP("2011-09-01 00:00:00")),
PARTITION p201109 VALUES LESS THAN (UNIX_TIMESTAMP("2011-10-01 00:00:00")),
PARTITION p201110 VALUES LESS THAN (UNIX_TIMESTAMP("2011-11-01 00:00:00")),
PARTITION p201111 VALUES LESS THAN (UNIX_TIMESTAMP("2011-12-01 00:00:00")),
PARTITION p201112 VALUES LESS THAN (UNIX_TIMESTAMP("2012-01-01 00:00:00")),
PARTITION p201201 VALUES LESS THAN (UNIX_TIMESTAMP("2012-02-01 00:00:00")),
PARTITION p201202 VALUES LESS THAN (UNIX_TIMESTAMP("2012-03-01 00:00:00")),
PARTITION p201203 VALUES LESS THAN (UNIX_TIMESTAMP("2012-04-01 00:00:00")),
PARTITION p201204 VALUES LESS THAN (UNIX_TIMESTAMP("2012-05-01 00:00:00")),
PARTITION p201205 VALUES LESS THAN (UNIX_TIMESTAMP("2012-06-01 00:00:00")),
PARTITION p201206 VALUES LESS THAN (UNIX_TIMESTAMP("2012-07-01 00:00:00")),
PARTITION p201207 VALUES LESS THAN (UNIX_TIMESTAMP("2012-08-01 00:00:00")),
PARTITION p201208 VALUES LESS THAN (UNIX_TIMESTAMP("2012-09-01 00:00:00")),
PARTITION p201209 VALUES LESS THAN (UNIX_TIMESTAMP("2012-10-01 00:00:00")),
PARTITION p201210 VALUES LESS THAN (UNIX_TIMESTAMP("2012-11-01 00:00:00")),
PARTITION p201211 VALUES LESS THAN (UNIX_TIMESTAMP("2012-12-01 00:00:00")),
PARTITION p201212 VALUES LESS THAN (UNIX_TIMESTAMP("2013-01-01 00:00:00"))
);


* This source code was highlighted with Source Code Highlighter.


Создаем partition table с делением по дням

ALTER TABLE `history_uint` PARTITION BY RANGE( clock ) (
PARTITION p20110603 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-03 00:00:00")),
PARTITION p20110604 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-04 00:00:00")),
PARTITION p20110605 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-05 00:00:00")),
PARTITION p20110606 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-06 00:00:00")),
PARTITION p20110607 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-07 00:00:00")),
PARTITION p20110608 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-08 00:00:00")),
PARTITION p20110609 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-09 00:00:00")),
PARTITION p20110610 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-10 00:00:00")),
PARTITION p20110611 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-11 00:00:00"))
);

ALTER TABLE `history_log` PARTITION BY RANGE( clock ) (
PARTITION p20110603 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-03 00:00:00")),
PARTITION p20110604 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-04 00:00:00")),
PARTITION p20110605 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-05 00:00:00")),
PARTITION p20110606 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-06 00:00:00")),
PARTITION p20110607 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-07 00:00:00")),
PARTITION p20110608 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-08 00:00:00")),
PARTITION p20110609 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-09 00:00:00")),
PARTITION p20110610 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-10 00:00:00")),
PARTITION p20110611 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-11 00:00:00"))
);

ALTER TABLE `history_text` PARTITION BY RANGE( clock ) (
PARTITION p20110603 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-03 00:00:00")),
PARTITION p20110604 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-04 00:00:00")),
PARTITION p20110605 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-05 00:00:00")),
PARTITION p20110606 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-06 00:00:00")),
PARTITION p20110607 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-07 00:00:00")),
PARTITION p20110608 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-08 00:00:00")),
PARTITION p20110609 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-09 00:00:00")),
PARTITION p20110610 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-10 00:00:00")),
PARTITION p20110611 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-11 00:00:00"))
);

ALTER TABLE `history` PARTITION BY RANGE( clock ) (
PARTITION p20110603 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-03 00:00:00")),
PARTITION p20110604 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-04 00:00:00")),
PARTITION p20110605 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-05 00:00:00")),
PARTITION p20110606 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-06 00:00:00")),
PARTITION p20110607 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-07 00:00:00")),
PARTITION p20110608 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-08 00:00:00")),
PARTITION p20110609 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-09 00:00:00")),
PARTITION p20110610 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-10 00:00:00")),
PARTITION p20110611 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-11 00:00:00"))
);

ALTER TABLE `history_str` PARTITION BY RANGE( clock ) (
PARTITION p20110603 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-03 00:00:00")),
PARTITION p20110604 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-04 00:00:00")),
PARTITION p20110605 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-05 00:00:00")),
PARTITION p20110606 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-06 00:00:00")),
PARTITION p20110607 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-07 00:00:00")),
PARTITION p20110608 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-08 00:00:00")),
PARTITION p20110609 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-09 00:00:00")),
PARTITION p20110610 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-10 00:00:00")),
PARTITION p20110611 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-11 00:00:00"))
);


* This source code was highlighted with Source Code Highlighter.


Восстанавливаем данные каждой таблицы так (подставив для каждой таблицы свое имя файла дампа)
mysql zabbix < 09.06.2011_history_str.sql

В конечном результате данные будут храниться очень удобно — каждый день/месяц в отдельном файле, отдельной части таблицы

ls -l /var/lib/mysql/zabbix/ |grep history_u
-rw-rw---- 1 mysql mysql 8628 2011-06-08 14:00 history_uint.frm
-rw-rw---- 1 mysql mysql 140 2011-06-08 14:00 history_uint.par
-rw-rw---- 1 mysql mysql 457179136 2011-06-07 11:34 history_uint#P#p20110605.ibd
-rw-rw---- 1 mysql mysql 557842432 2011-06-07 11:34 history_uint#P#p20110606.ibd
-rw-rw---- 1 mysql mysql 620756992 2011-06-07 11:34 history_uint#P#p20110607.ibd
-rw-rw---- 1 mysql mysql 629145600 2011-06-08 00:03 history_uint#P#p20110608.ibd
-rw-rw---- 1 mysql mysql 666894336 2011-06-09 00:08 history_uint#P#p20110609.ibd
-rw-rw---- 1 mysql mysql 423624704 2011-06-09 14:55 history_uint#P#p20110610.ibd
-rw-rw---- 1 mysql mysql 114688 2011-06-07 11:09 history_uint#P#p20110611.ibd
-rw-rw---- 1 mysql mysql 114688 2011-06-07 11:44 history_uint#P#p20110612.ibd
-rw-rw---- 1 mysql mysql 114688 2011-06-07 11:44 history_uint#P#p20110613.ibd
-rw-rw---- 1 mysql mysql 114688 2011-06-07 11:44 history_uint#P#p20110614.ibd
-rw-rw---- 1 mysql mysql 114688 2011-06-08 14:00 history_uint#P#p20110615.ibd
-rw-rw---- 1 mysql mysql 8688 2011-05-27 21:30 history_uint_sync.frm
-rw-rw---- 1 mysql mysql 131072 2011-05-27 21:30 history_uint_sync.ibd


Очистка старых данных производится простой командой (вместо `history_uint` подставьте нужную вам таблицу)
ALTER TABLE `history_uint` DROP PARTITION p20110604;
Добавление новой части таблицы
ALTER TABLE `history_uint` ADD PARTITION (PARTITION p20110628 VALUES LESS THAN (UNIX_TIMESTAMP("2011-06-29 00:00:00")));

Руками чистить таблицы и добавлять новые как то не интересно, опять же в блоге предлагают процедуру для таблиц разбитых по дням код взят тут pastebin.com/ijyKkxLh дабы сохранить его для потомков выложу его здесь без изменений.

/**************************************************************
 MySQL Auto Partitioning Procedure for Zabbix 1.8
 zabbixzone.com/zabbix/partitioning-tables

 Author: Ricardo Santos (rsantos at gmail.com)
 Version: 20110518
**************************************************************/
DELIMITER //
DROP PROCEDURE IF EXISTS `zabbix`.`create_zabbix_partitions` //
CREATE PROCEDURE `zabbix`.`create_zabbix_partitions` ()
BEGIN
  CALL zabbix.create_next_partitions("zabbix","history");
  CALL zabbix.create_next_partitions("zabbix","history_log");
  CALL zabbix.create_next_partitions("zabbix","history_str");
  CALL zabbix.create_next_partitions("zabbix","history_text");
  CALL zabbix.create_next_partitions("zabbix","history_uint");
  CALL zabbix.drop_old_partitions("zabbix","history");
  CALL zabbix.drop_old_partitions("zabbix","history_log");
  CALL zabbix.drop_old_partitions("zabbix","history_str");
  CALL zabbix.drop_old_partitions("zabbix","history_text");
  CALL zabbix.drop_old_partitions("zabbix","history_uint");
END //
DROP PROCEDURE IF EXISTS `zabbix`.`create_next_partitions` //
CREATE PROCEDURE `zabbix`.`create_next_partitions` (SCHEMANAME varchar(64), TABLENAME varchar(64))
BEGIN
  DECLARE NEXTCLOCK timestamp;
  DECLARE PARTITIONNAME varchar(16);
  DECLARE CLOCK int;
  SET @totaldays = 7;
  SET @i = 1;
  createloop: LOOP
    SET NEXTCLOCK = DATE_ADD(NOW(),INTERVAL @i DAY);
    SET PARTITIONNAME = DATE_FORMAT( NEXTCLOCK, 'p%Y%m%d' );
    SET CLOCK = UNIX_TIMESTAMP(DATE_FORMAT(DATE_ADD( NEXTCLOCK ,INTERVAL 1 DAY),'%Y-%m-%d 00:00:00'));
    CALL zabbix.create_partition( SCHEMANAME, TABLENAME, PARTITIONNAME, CLOCK );
    SET @i=@i+1;
    IF @i > @totaldays THEN
      LEAVE createloop;
    END IF;
  END LOOP;
END //
DROP PROCEDURE IF EXISTS `zabbix`.`drop_old_partitions` //
CREATE PROCEDURE `zabbix`.`drop_old_partitions` (SCHEMANAME varchar(64), TABLENAME varchar(64))
BEGIN
  DECLARE OLDCLOCK timestamp;
  DECLARE PARTITIONNAME varchar(16);
  DECLARE CLOCK int;
  SET @mindays = 3;
  SET @maxdays = @mindays+4;
  SET @i = @maxdays;
  droploop: LOOP
    SET OLDCLOCK = DATE_SUB(NOW(),INTERVAL @i DAY);
    SET PARTITIONNAME = DATE_FORMAT( OLDCLOCK, 'p%Y%m%d' );
    CALL zabbix.drop_partition( SCHEMANAME, TABLENAME, PARTITIONNAME );
    SET @i=@i-1;
    IF @i <= @mindays THEN
      LEAVE droploop;
    END IF;
  END LOOP;
END //
DROP PROCEDURE IF EXISTS `zabbix`.`create_partition` //
CREATE PROCEDURE `zabbix`.`create_partition` (SCHEMANAME varchar(64), TABLENAME varchar(64), PARTITIONNAME varchar(64), CLOCK int)
BEGIN
  DECLARE RETROWS int;
  SELECT COUNT(1) INTO RETROWS
    FROM `information_schema`.`partitions`
    WHERE `table_schema` = SCHEMANAME AND `table_name` = TABLENAME AND `partition_name` = PARTITIONNAME;
  
  IF RETROWS = 0 THEN
    SELECT CONCAT( "create_partition(", SCHEMANAME, ",", TABLENAME, ",", PARTITIONNAME, ",", CLOCK, ")" ) AS msg;
       SET @sql = CONCAT( 'ALTER TABLE `', SCHEMANAME, '`.`', TABLENAME, '`',
        ' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', CLOCK, '));' );
    PREPARE STMT FROM @sql;
    EXECUTE STMT;
    DEALLOCATE PREPARE STMT;
  END IF;
END //
DROP PROCEDURE IF EXISTS `zabbix`.`drop_partition` //
CREATE PROCEDURE `zabbix`.`drop_partition` (SCHEMANAME varchar(64), TABLENAME varchar(64), PARTITIONNAME varchar(64))
BEGIN
  DECLARE RETROWS int;
  SELECT COUNT(1) INTO RETROWS
    FROM `information_schema`.`partitions`
    WHERE `table_schema` = SCHEMANAME AND `table_name` = TABLENAME AND `partition_name` = PARTITIONNAME;
  
  IF RETROWS = 1 THEN
    SELECT CONCAT( "drop_partition(", SCHEMANAME, ",", TABLENAME, ",", PARTITIONNAME, ")" ) AS msg;
       SET @sql = CONCAT( 'ALTER TABLE `', SCHEMANAME, '`.`', TABLENAME, '`',
        ' DROP PARTITION ', PARTITIONNAME, ';' );
    PREPARE STMT FROM @sql;
    EXECUTE STMT;
    DEALLOCATE PREPARE STMT;
  END IF;
END //
DELIMITER ;


* This source code was highlighted with Source Code Highlighter.


Теперь остается добавить выполение этого кода по крону раз в 3 дня
строчка в конфиге крона будет выглядить приблизительно так
0 6 */3 * * Логинка_от_кого_выполняем mysql -B -h localhost -u zabbix -pПАРОЛЬКА zabbix -e "CALL create_zabbix_partitions();"

С настройкой БД закончили.

Настроим автопривязку шаблонов от количества плат на оборудовании


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

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



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

Что же мы получили?


Загрузка проца и прочие разные графики ниже.
На графике размера БД можно заметить два падения, первое падение — первый запуск процедуры, второе падение через сутки — ручная проверка выполнения процедуры.



Краткие качественные характеристики


Как видно ресурсы позволяют поднять нагрузку без особого ущерба производительности. Раньше баловался и доводил количество items до 300 000 и количество получаемых значений в секунду до 200. Сейчас же все лишнее и не нужное из мониторинга убрано.

Мелкий бонус


Пример части карты сети FTTB


Контроль за линками одного корпоративного клиента


Продолжение будет если тема будет интересна ))

ЗЫ Извиняюсь за несколько сумбурное изложение материала.
UPD: Исправил часть орфографических и грамматических ошибок.
UPD2: Исправил еще много орфографических и грамматических ошибок, подправил потерявшиеся ссылки.
+26
42.6k 156
Comments 46
Top of the day