OTRS: копирование тикитов на архивный сервер
Приходит время когда даже мощный и оптимизированный сервер mysql не справляется с нагрузкой. Чтобы вернуть былую скорость необходимо время от времени проводить очистку базы данных OTRS. Под очисткой я имею ввиду удаление успешно закрытых и объединенных тикитов. Чтобы иметь возможность в дальнейшем просмотреть эти тикиты необходимо перед очисткой произвести перенос тикитов и их вложений на архивный сервер OTRS.
Данная операция имеет смысл лишь на высоконагруженном экземпляре OTRS. Высоконагруженный — это какой? В одной из копий которую я администрировал речь шла о 60 тыс. тикитов в месяц. Объем БД раздувался до 5 Гб (после очистки 3 Гб). При этом файлы вложений в файловой системе занимали несколько десятков гигабайт.
В нашем распоряжении:
OTRS 2.4.7 Продакшен сервер ( БД OTRS MyISAM 4 ГБ ) Архивный сервер ( БД OTRS MyISAM 25 Гб ) На обоих серверах в качестве ОС был RHEL |
Бекап БД архивного сервера
Делаем бекап архивной базы. После заливки дампа с промышленного сервера OTRS и тестирования работоспособности OTRS архивный дамп который мы сделаем можно будет удалить. В случае же возникновения каких-либо проблем всегда можно будет восстановить БД архивного сервера OTRS из дампа.
Если места на раздере маловато то можно сразу сжимать
mysqldump --opt otrs | gzip > otrs.sql.gz |
или
mysqldump --opt otrs | bzip2 > otrs.sql.bz2 |
если нужно восстановить дамп из архива:
gunzip < otrs.sql.gz | mysql < mysql options > |
или
bunzip2 < otrs.sql.bz2 | mysql < mysql options > |
Время выполнения дампа на моем сервере всегда гораздо меньше чем сжатие архиватором самого дампа.
Поэтому если места на разделе хватает под дамп ~10 Гб (при БД в 25 Гб), то для наглядности можно вначале выполнить дамп, а потом уже начать сжимать:
file =otrs.sql && mysqldump --opt otrs > $file && cat $file | pv -s $ ( du -sb $file | awk '{print $1}' ) | gzip > otrs.sql.gz |
Отмечу, что для успешного выполнения команды выше необходим установленный пакет
Дамп на продакшене
mysqldump --quick --add-locks --lock-tables --no-create-info otrs | sed 's/INSERT/REPLACE/g' > otrs_no_create_info_replace.sql |
Тут необходимо обратить внимание на то, что в дампе мы заменяем оператор INSERT на REPLACE.
Зачем мы это делаем? Дело в том, что мы будем заливать дамп на архивный сервер на котором уже есть функционирующая БД OTRS. Благодаря оператору REPLACE записи которые находятся в БД и совпадают с таковыми в дампе будут заменены записями из дампа. Знаете способ лучше как добавить порцию данных на работающую БД пишите в комментариях.
Дамп выполняется сравнительно быстро — ~ две минуты на бд 4 Гб (Xeon(R) CPU E5530) на объеме БД ~ 4 Гб.
Копируем дамп на архивный сервер
scp otrs_no_create_info_replace.sql root @ archive_server_ip: / root / mysql_backup |
iptables
Проверяем правила iptables
iptables -vnL #В цепочке OUTPUT должно быть следующее: Chain OUTPUT ( policy ACCEPT 42445 packets, 7867K bytes ) pkts bytes target prot opt in out source destination 5 440 DROP tcp -- * * 0.0.0.0 / 0 0.0.0.0 / 0 tcp dpt: 110 72 4591 DROP tcp -- * * 0.0.0.0 / 0 0.0.0.0 / 0 tcp dpt: 25 |
Тут показано, что исходящие соединения на портах 25 и 110 заблокированны. Это делается для того,
чтобы архивный OTRS был “отрезан” от внешнего мира и не влиял на работу промышленного OTRS.
Кусок в конфиге /etc/sysconfig/iptables отвечающий за правила указанные выше
# Лочим исходящие соединения на 110 порт, чтобы ОТРС на этом сервере не забирал почту из ящика из которого выгребает продакшен. -A OUTPUT -m tcp -p tcp --dport 110 -j DROP # Лочим 25 порт на отправку, чтоб OTRS никому ничего не мог отправить -A OUTPUT -m tcp -p tcp --dport 25 -j DROP |
Заливаем дамп
Предварительно необходимо проверерить дотаточно ли места на разделе где находится файлы mysql.
df -h |
Визуальный способ заливки дампа. Показывает сколько времени осталось.
file =otrs_no_create_info_replace.sql && cat $file | pv -s $ ( du -sb $file | awk '{print $1}' ) | mysql -uotrs -p --database otrs |
Самый надежный способ заливки дампа:
mysql -uotrs -p --database otrs < otrs_no_create_info_replace.sql |
дамп в 3,69GB залился за 1:55:39 на системе IBM eServer BladeCenter HS21 (2 x Intel(R) Xeon(R) CPU 5160 @ 3.00GHz, 3290 Мб ОЗУ). Напомню, что такое продолжительное время заливки дампа из-за оператора REPLACE.
Наблюдать за запросами можно:
mytop -s1 mysqladmin proc stat |
Почта
Если мы не хотим, чтобы архивный сервер забирал почту с почтового сервера и тем самым влиял на работу продакшен сервереа, то необходимо отключить почту. То есть сделать неактивной учетку под который OTRS забирает почту на архивном сервере. Это не актуально если мы на фаерволе создали соответствующее запрещающее правило.
Проверка корректности переноса тикитов
Проверяем совпадает ли количество созданных тикитов на наших OTRS’ах.
Сколько создано тикитов в течение месяца
SELECT date_format ( create_time , '%m - %Y' ) , COUNT ( * ) FROM ticket GROUP BY date_format ( create_time , '%m %Y' ) ORDER BY date_format ( create_time , ' %Y -%m' ) ; |
Перенос вложений тикитов
Переносим вложения тикитов, находящиеся на web сервере
Архивируем
tar -cf 10 - 12 .tar . / 10 / . / 11 / . / 12 / |
Копируем
scp 10 - 12 .tar root @ archive_server_ip: / root / |
Разархивируем
tar -xf 06-09.tar -C . / 2011 / |
Очистка тикитов на продакшене
Создаем задание на ОТРС в GenericAgent
Устанавливаем время выполнения задания,
устанавливаем статус “закрытый успешно”, “закрытый неуспешно” и “удаленный”
устанавливаем время закрытия — Заявка закрита ПЕРЕД 3 месяцев
Удалить — Да
Также вычищаем тикиты полугодичной давности в состоянии merged (объединенные)
Отптимизация таблиц
После удаления большого числа записей из таблиц БД желательно проводить дефрагментицию таблиц. За это отвечает команда optimize. Ниже скрипт который сжимает лишь таблицы нуждающиеся в данной операции.
#!/usr/bin/perl use DBI ; $dbhost = 'localhost' ; $dbuser = 'otrs' ; $dbpass = 'PASSWD' ; $db = 'otrs' ; $dbl = DBI -> connect ( "DBI:mysql:$db:$dbhost" , $dbuser , $dbpass ) or die "mysql connection failed" ; $sth = $dbl -> prepare ( "select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='$db' and DATA_FREE<>0" ) ; $sth -> execute ; while ( ( $table_name ) = $sth -> fetchrow ) { # print "optimize table $table_name\n"; my $sth = $dbl -> prepare ( "optimize table $table_name" ) ; $sth -> execute ; } |