Мои ошибки за 2012 год
Год назад я стал счастливым обладателем VPS сервера. О своих ошибках при установке и настройке я уже писал в теме Переезд на VPS. Часть 2 – Мои ошибки.
Прошел год, а значит у меня было 365 дней, что бы накосячить.
Что нужно было сделать, но не сделано
Бэкап хранится локально
Да, я храню бэкапы на том же самом сервере. По крайней мере я так делал большую часть 2012 года. Сравнительно недавно у меня появился быстрый интернет и теперь я забираю бэкапы почти сразу. Но это не выход. Ведь сейчас есть множество готовых решений. Начиная от бесплатного DropBox и его аналогами, заканчивая серверами под бэкап (Amazon S3, бэкап-хостинги и т. д.) со стоимостью до 15-30$/год. Цены приведены, исходя из моих потребностей. А это не более 25Gb.
Необходимо настроить автоматическую выгрузку бэкапов в надежное место.
Бэкап
Каюсь, но я до сих пор не настроил автоматические бэкапы. Скрипты для резервного копирования созданы, но я их запускаю вручную. Причем делаю это примерно раз в месяц. Так делать нельзя. Нельзя. Нельзя.
Необходимо настроить ежедневный бэкап с ротацией.
Пару слов о моих бэкапах. Все БД и файлы вместе занимают 3Gb. Один бэкап архив этих данных занимает 700Mb. Кроме этого нужно место под логи и под сырые данные, на основании которых рассчитываются данные в одном из проектов. Все это вместе съедает 8 из 15Gb, отведенных на VPS. Если я настрою автоматический бэкап и не буду его забирать, то место на сервере кончится за неделю. Как видно, задача комплексная. Нужно собраться с духом и решить её.
Бэкап MySQL наживую
Во время дампа БД я не забочусь о целостности данных.
Представим ситуацию. У нас есть база данных из 500 таблиц, общий размер которых 2Gb, есть CRON скрипты и пользователи на сайте, которые заполняют эти таблицы. Дамп 2Gb – дело не быстрое. Новые данные могут прийти в тот момент, когда мы сделали дамп половины таблиц. В итоге часть новых данных будет утеряна. Допустим, что это статистика гонок. Есть таблицы Drivers и Races. Скрипт пишет информацию о каждом заезде (Races) и о каждом гонщике (Drivers). После заезда он обновляет статистику гонщика. Заезд заканчивается в момент дампа, когда сохранены таблицы с именами на A-E. То есть в дамп попадут старые таблицы A-E и новые F-Z. А это означает, что информация о заездах будет полная, а статистика гонщиков не будет содержать информацию о последнем заезде.
Есть множество способов, как снять грамотный дамп даже с высоконагруженного проекта. Но это тема для отдельной статьи.
Ротация логов
Не настроена. Вроде бы, очень просто настроить logrotate. Даже не знаю, как отмазаться :). Кстати. Во время DDoS у меня очень быстро закончилось место. Если бы была настроена ротация логов, ничего страшного не произошло бы. Да, сервер не был бы доступен ночью. Но CRON скрипты продолжали бы работать и собирать статистику.
Необходимо настроить logrotate.
Смена пароля SSH
Пароль длинный и созданный по всем правилам (цифро-буквы в разном регистре с использованием спец символов). Но и такие пароли нужно менять раз в 6-12 месяцев. Может быть, это просто моя паранойя.
Сижу под ROOT
Просто без комментариев. Знаю, что так делать нельзя. Уже удалял все файлы с сервера. Не повторяйте моих ошибок.
Обновления библиотек посреди рабочего дня
Вот захотелось мне обновить MySQL до версии 5.5 в полдень среды – я обновил. Переименовать таблицы – переименовал. Всё это сопровождалось остановкой MySQL и недоступностью сайтов.
Никогда так не делайте.
И не забывайте про поговорку: «Семь раз отмерь – один отрежь».
Обновление с MySQL 5.1 до 5.5
Поначалу все было отлично. Кроме того, что у меня в голове возникла идея обновиться посреди рабочего дня.
yum remove mysql mysql-* rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm yum --enablerepo=remi,remi-test list mysql mysql-server yum --enablerepo=remi install mysql-server service mysqld start |
Пробуем и получаем:
Fatal error: Call to undefined function mysql_connect() |
Добавляем:
yum install php-mysql |
Проверил. Сайты работают. Но заметил, что apc-кэш недоступен. Еще добавляем:
yum install php-pecl-apc |
Всё отлично.
Только через два часа я заметил большое количество ошибок в отчетах CRON скриптов.
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php/modules/apc.so' - /usr/lib/php/modules/apc.so: undefined symbol: pcre_exec in Unknown on line 0 |
Суть ошибки в том, что CRON скрипты не могут загрузить модуль apc, который им вообще не нужен.
Решение похоже на костыль, но зато простое. Нужно создать отдельный php.ini для командной строки, в котором убрать модуль apc. Так как ini файлы модулей загружаются автоматически, нам придется добавить все настройки из php.d/apc.ini в основной php.ini. В командах это выглядит так.
cp /etc/php.ini /etc/php-cli.ini cat /etc/php.d/apc.ini >> /etc/php.ini |
После чего открываем в любом редакторе apc.ini и добавляем ; в начале каждой строки.
Было:
extension = apc.so apc.enabled = 1 apc.shm_size = 128 apc.shm_segments = 1 apc.gc_ttl = 7200 apc.ttl = 0 apc.num_files_hint = 1024 apc.file_update_protection = 2 ;apc.optimization = 1 ;apc.include_once_override = 1 ;apc.stat = 0 apc.max_file_size = 5M ;apc.stat_ctime = 1 ;apc.mmap_file_mask=/tmp/apc.XXXXXX ;apc.mmap_file_mask=/dev/zero apc.filter="-/usr/share/phpMyAdmin/.*" |
Стало:
;extension = apc.so ;apc.enabled = 1 ;apc.shm_size = 128 ;apc.shm_segments = 1 ;apc.gc_ttl = 7200 ;apc.ttl = 0 ;apc.num_files_hint = 1024 ;apc.file_update_protection = 2 ;apc.optimization = 1 ;apc.include_once_override = 1 ;apc.stat = 0 ;apc.max_file_size = 5M ;apc.stat_ctime = 1 ;apc.mmap_file_mask=/tmp/apc.XXXXXX ;apc.mmap_file_mask=/dev/zero ;apc.filter="-/usr/share/phpMyAdmin/.*" |
После этого всё заработало в полном объеме.
Но реальность всегда жестока. На следующее утро я обнаружил, что один из скриптов, обрабатывающий статистику завершился с ошибкой. Причина: неверный формат запроса на создание таблицы.
CREATE TABLE IF NOT EXISTS abc_data (fields) TYPE=MyISAM; |
Начиная с MySQL 5.5, больше не поддерживается опция TYPE. Вместо неё нужно использовать опцию ENGINE.
Правильный запрос:
CREATE TABLE IF NOT EXISTS abc_data (fields) ENGINE=MyISAM; |
Планы на 2013 год
1. Настроить нормальный бэкап.
2. Отучить себя править исходники наживую.
3. Развертывать код только через GIT.
4. Сменить связку Apache + Nginx на PHP-FPM + Nginx.