Администрируя высоконагруженный проект, то и дело натыкаюсь на проблему повторного запуска cron задач в то время как предыдущая задача еще не отработала.
Таким образом получается, что одни и те же cron скрипты выполняют одни и те же задачи одновременно, удваивая тем самым нагрузку. При этом они начинают выполняться медленнее, и возможна лавинообразная ситуация, когда к этим двум добавится еще и третья такая же задача. Потом четвертая, а потом все упадет вообще.
Как с этим бороться?
Вариант 1. Сложный.
Использовать в скрипте, который запускается по cron, проверку pid:
Проверяем наличие pid файла с идентификатором процесса
Проверяем, есть ли такой pid в памяти командой «ps -p PID»
Если pid запущен, прерываем работу
Иначе, пишем в pid файл свой pid и продолжаем
Однако это требует модификации скрипта.
Вариант 2. Простой.
Есть замечательная утилитка в Linux, называется . В качестве параметра, утилита принимает имя файла лока и команду для исполнения. flock ставит эксклюзивный лок на указанный файл и, при успехе, запускает указанную команду. Функционал flock не ограничивается только этой возможностью – на эту тему можно покурить соответствующий man.
Итак, у нас есть cron задача:
* * * * * user /usr/bin/php /some/heavy/script.php
С помощью небольшой модификации этой строки мы сможем предотвратить повторный запуск задачи во время выполнения предыдущей задачи:
Попытаюсь в этой статье рассказать об особенностях применения хранилища InnoDB в высоконагруженных проектах, а так же дать поверхностное сравнение MyISAM и InnoDB. Безусловно, MySQL не ограничивается только этими двумя типами хранилища данных, однако они являются подавляющими в своей распространенности использования.
Несмотря на то, что много в InnoDB для меня очевидно, все еще остаются некоторые темные пятна и если меня где то поправят, буду только благодарен.
Почему народ выбирает InnoDB? InnoDB обладает преимуществами перед MyISAM.
Транзакционная модель. Это конечно преимущество не столько для администратора, сколько для программиста. Программист может объединить операции с базой в транзакцию, с кучей вытекающих из этого профита. Это основная причина по которой архитекторы выбирают InnoDB.
Блокировка на уровне строки. В отличии от MyISAM, где идет блокировка на уровне таблицы, в InnoDB блокировка осуществляется на уровне строки. Проблема конкурентных блокировок стоит не так остро как в MyISAM, однако все таки присутствует. Но об этом ниже.
Защита от сбоев. InnoDB более устойчивая к сбоям, если сказать точнее, InnoDB намного лучше восстанавливается после сбоев и практически не теряет данные. Для восстановления же MyISAM таблиц зачастую требуется потушить MySQL сервер и вручную восстанавливать таблицы утилитой myisamchk. Результатом работы myisamchk зачастую может оказаться частичная или полная потеря данных в таблице. InnoDB восстанавливается автоматически.
Качественная работа с IO. InnoDB имеет свой собственный Buffer Pool в памяти, где держит таблицы. Для InnoDB можно отключить системную буферизацию IO при работе с таблицами InnoDB. Таким образом, можно сказать что в InnoDB нет двойной буферизации (как в MyISAM), следовательно, оперативная память разумно расходуется.
MyISAM конечно же тоже обладает преимуществами, в основном это простота и скорость. На небольших объемах данных и большом количестве операций чтения лучше хранилища не найти, если конечно вам не нужны транзакции. Но сейчас не об этом. На этой ноте про MyISAM больше ни слова.
InnoDB не готова корректно работать из коробки на высоких нагрузках. Надо хорошо понимать о происходящих в недрах InnoDB процессах дабы правильно настроить этот тип хранилища.
Ниже описаны ключевые моменты конфигурации, существенно влияющие на производительность.
innodb_file_per_table
По умолчанию, InnoDB использует общее хранилище для всех таблиц и индексов. Данная опция позволяет содавать на каждую таблицу свой .ibd файл. Наиболее частая причина применения этой опции – раскидать отдельные таблицы по отдельным физическим устройствам.
Так же бывают определенные таблицы, в которые очень часто пишутся и удаляются данные. Это серъезно фрагментирует общее хранилище таблиц и от этого может пострадать производительность других таблиц. В этом случае имеет смысл разбивать общее хранилище на отдельные куски для каждой таблицы.
Если у вас таблицы уже созданы в общем хранилище и вы перезагружаете сервер MySQL с этой опцией, старые таблицы останутся в общем хранилище, а новые будут создаваться в отдельных хранилищах. Таким образом, чтобы поместить старые таблицы в раздельные файлы, нужно их пересоздать или переименовать.
Использование выделенных блочных устройств под хранилище
Киллер-фича InnoDB. Вы можете использовать целые партиции или физические устройства вместо файлов общего хранилища InnoDB. Это сразу убирает всякую системную буферизацию ввода-вывода и всякий оверхед файловой системы. В этом случае InnoDB пишет данные прямо на устройство. Конечно же, это создает ряд ньюансов в процедуре резервного копирования.
Для того чтобы использовать эту возможность, пропишите в конфигурации
и перезапустить сервер. Иначе при следующем перезапуске, если InnoDB встретит «newraw», партиция будет заново отформатирована!
Так же надо иметь в виду, что пользователь, под которым запускается MySQL должен иметь права на запись в обозначенные партиции.
При использовании данной возможности, очевидно лучше для InnoDB выделять логические тома LVM. Это существенно упрощает бекап () и восстановление.
innodb_buffer_pool_size
Размер памяти, выделяемый под кеш данных и индексов. Строго говоря, чем больше таблиц сидит в этой памяти, тем лучше. Если есть возможность, размер этого буфера должен быть чуть больше общего размера innodb таблиц. Однако он не должен быть больше 80% объема ОЗУ.
innodb_log_file_size
Размер файла лога транзакций. Чем больше размер, тем реже InnoDB будет сбрасывать страницы Buffer Pool на диск, и тем больше требуется времени на восстановление после аварии. Размер варьируется от нескольких мегабайт до размера innodb_buffer_pool_size, но не более 4Gb суммарно во всех лог-файлах.
innodb_log_buffer_size
Размер буфера памяти для записи лога транзакций. Размер варьируется в пределах единиц-десятков мегабайт. Большой размер буфера позволяет запускать объемные транзакции без сброса лога на диск, что позволяет уменьшить IO при объемных транзакциях.
innodb_flush_log_at_trx_commit
Принимает одно из трех значений: 0, 1, 2. При значении 1, лог скидывается на диск при каждом коммите транзакции и буфер записи так же скидывается на диск. При 0 эта операция производится не при каждой транзакции а 1 раз в секунду. При значении 2, лог скидывается на диск при каждом коммите, но сброс буферов не производится.
Если вы ищете производительность в ущерб надежности – ставьте 0. Если наоборот – ставьте 1.
innodb_thread_concurrency
Количество рабочих тредов InnoDB. Начать надо с количества ядер CPU*2 + количество физических блочных устройств. Мне всегда этой формулы хватало. Официальная документация рекомендует поиграть с этим значением.
innodb_flush_method
Установка характера работы с файловой системой. Данная переменная не имеет эффекта при использовании выделенных блочных устройств под хранилище. Представляет из себя комбинацию значений O_DSYNC,O_DIRECT,fdatasync. Если вы используете большой размер innodb_buffer_pool_size, имеет смысл дать InnoDB доступ к файлам, минуя системные буфера с помощью опции O_DIRECT.
В официальном руководстве сказано, что при использовании определенных Storage Area Network, O_DIRECT может дать серъезный пенальти производительности.
Для OS GNU/Linux читайте про опции O_DSYNC (O_SYNC) и O_DIRECT на . FreeBSD очевидно имеет много сходств с GNU/Linux в этом вопросе.
Эта опция не может быть никак пропущена, если у вас серьезная нагрузка на конкурентную запись. Очень сложно это объяснить, да и не понимаю я этого до самой глубины, но если вкратце…
Если вам нужна полноценная изоляция транцакций, то эта опция не для вас. Тогда придется пренебрегать производительностью в пользу целостности транзакций.
Например, если вы используете чтение по диапазону (SELECT a FROM b WHERE c>100) внутри тразакции, то с включенной опцией innodb_locks_unsafe_for_binlog, следующий такой же запрос вернет тот же результат, даже если между ними кто то что то в эту таблицу пытался писать.
При выключенной (по умолчанию) опции innodb_locks_unsafe_for_binlog, во второй раз указанный запрос может вернуть отличный от первого раза результат в одной транзакции, поскольку пытающимся писать в эту таблицу процессам не было выставлено препятствий.
То есть, эта опция во включенном состоянии снимает туеву хучу локов при конкурентной записи-чтении в таблицы. Цена вопроса – не обеспечивается консистентный снапшот данных на время всей транзакции. Как то так в общем.
В моем случае, прирост производительности при включении этой опции был колоссальный. Однако это имеет смысл на реально массивных смешанных записях-удалениях-чтениях.
Ах да. И для репликации соответственно это не канает.
innodb_lock_wait_timeout
Довольно странная настройка, но она имеет место и является частой причиной потери данных. Когда тред ожидает снятия блокировки строки для модификации записей, он ожидает вплоть до указанного в этой опции количества секунд. По умолчанию это 50 секунд. Если за 50 секунд блокировка не была снята, транзакция отваливается с ошибкой
Если у вас нагруженный модификациями сервер, вы наверняка упретесь в это время ожидания и транзакции с изменениями данных будут завершаться с указанной ошибкой. В этом случае стоит подумать о включении опции innodb_locks_unsafe_for_binlog.
Программистов нужно предупреждать (если они не в курсе), что если они словили ошибку 1205 от InnoDB, то надо повторить или отложить транзакцию! Поскольку эта ошибка де-факто не может быть воспроизведена в тестовых условиях, очень часто программисты не в курсе и бывают весьма удивлены, наблюдая пробелы в потоках данных.
25 и 26 октября в Москве пройдет крупнейшая профессиональная техническая конференция Рунета — конференция разработчиков высоконагруженных систем . Мероприятие проходит уже четвертый год, собирая более 700 участников. В этом году основная направленность конференции — оригинальные исследования, новые архитектуры, новые концепкции и подходы в построении крупных Интернет-проектов.
HighLoad++ — знаковое событие по обмену опытом — мы ожидаем Stoyan Stefanov (Yahoo), Eugene Chigirinskiy (Microsoft), Patrice Pelland (Microsoft), James Golick, Robert Johnson (Facebook), Joe Damato, Петр Зайцев (Percona), Simon Riggs (PostgreSQL) и Bruce Momjian (PostgreSQL).
Joe Damato, “хакер”, специализирующийся на низком уровне, известный специалист в мире Ruby прочитает доклад “Настройка и инструментарий для Linux / Performance tweaks and tools for Linux”. Доклад разделен на две части. В первой части Джо рассмотрит особенности различных настроек ядра Linux (и стандартные драйвера). Разговор пойдет о некоторых малоизвестных настройках ядра, подстройка которых поможет наиболее эффективно использовать аппаратные средства железа.
Во второй части доклада разговор пойдет о полезных инструментах для изучения и диагностики ошибок в процессах. Автор пробежится по различным инструментам для Linux (strace, ltrace, oprofile, gdb, и другие) и разберет, как их можно использовать, чтобы получить представление о том, на что тратятся ресурсы и время обработки запросов.
Другой отличный доклад — про архитектуру крупнейшего интернет-сайта в мире — Facebook.com от Robert Johnson, руководитель отдела разработки в Facebook, где он разрабатывает технологии по экономически эфективному инфраструктуры и для миллионов пользователей Facebook.
Роберт расскажет о технологии, необходимой для запуска сайта таких масштабов (100 млрд. просмотров в день, 50 млрд. хранящихся фотографий), включая конкретные технологии созданные компанией Фейсбук, некоторые принципы, применяемые в работе с масштабированием, и уроки, полученные во время этих разработок. Также Роберт расскажет о наших новейших разработках в области — пропуска социального контекста из сети через платформу Facebook.
Организаторы собрали в эти два дня крупнейшую встречу разработчиков баз данных — мы узнаем о новшествах в PostgreSQL и MySQL от тех, кто разрабатывал эти новшества: Саймон Ригс, Брюс Момжан, Петр Зайцев, разработчики Сфинкса, Константин Осипов и другие.
Целый блок докладов о Ruby и Python
Frontik. Сервер сборщик на python / Сергей Никулин (HeadHunter);
Оптимизация одного из топовых приложений для социальной сети ВКонтакте: 1000 запросов в секунду на Rails / Максим Лапшин;
Приемы разработки высоконагруженных приложений на Twisted / Андрей Смирнов;
Отчет за год по DDOS (атаки на ДНС, “не жадные” ботнеты, атаки на индекс Yandex (черный seo), высокоскоростные атаки, позиция государства и МВД на эту тему) / Александр Лямин;
Пара круглых столов
Квадратный стол про использование many-core CPU с участием Google, Intel, Yandex и Badoo / (Google, Яндекс, Mail.ru, Intel);
Круглый стол с представителями ВКонтакте;
Все доклады конференции построены как профессиональные — даже если докладчик рассказывает о своей услуге, он рассказывает о том, как она устроена, а не рекламирует ее. Например — “Как мы строим CDN в России”. Классификация CDN по спобу расположения серверов: расстановка серверов по сетям интернет-провайдеров или подключение к провайдерам в точках обмена трафиком. Классификация CDN по способу распределения нагрузки: DNS, HTTP Redirect. Классификация CDN по способу нахождения кратчайшего пути до пользователя.
И многое, многое другое — более 60 докладов из которых , в который входят технические директора и ведущие специалисты крупнейших компаний Рунета (Яндекс, Mail.ru, Рамблер, Badoo и другие), выберет самые лучшие.
Подробности Вы можете найти на сайте конференции .
Имеем: высоконагруженый MySQL сервер с таблицами объёмом более 20 Гб.
Требуется: ежедневное резервное копирование на удавленный хост с шифрованием данных
Условия: процедура бекапа не должна ни коим образом сказаться на производительности MySQL во время проведения оной.
Итак, mysqldump отпадает автоматически, ибо локи таблиц там испортят нам весь аптайм. Выбор пал на технологию LVM снэпшотов, доступную в любом линуксе, утилитку шифрования gpg, а так же IO scheduler CFQ.
Итак, подготовка.
1. Подготовка LVM.
Нам нужна LVM группа с необходимым свободным местом для:
Баз MySQL
LVM снэпшота
Т.е. объема свободного пространства в группе LVM должно быть под базы + где-то 10-20% (в зависимости от тяжести IO записи работы с базами).
Создаем LVM Physical Volume на девайсе /dev/sda2 (у меня /dev/sda это RAID5 из 6 SAS дисков, sda2 можете заменить на свой девайс):
pvcreate /dev/sda2
Создаем Volume Group с именем vg0 на /dev/sda2:
vgcreate vg0 /dev/sda2
Теперь надо создать в группе vg0 логический том (Logical Volume) под партицию MySQL таблиц с именем mysql. У меня эта партиция занимает 500 Гб. При этом важно оставить в группе vg0 10-20% свободного места, не занятого логическими томами, дабы было возможно делать снэпшоты.
lvcreate -L 500G -n mysql vg0
Теперь наш девайс будет виден в:
/dev/mapper/vg0-mysql
/dev/vg0/mysql (symlink)
2. Подготовка ФС
Это, думаю, умеют делать все. Но на всякий напишу.
Дальше любимым путем переносим на этот раздел (/mysql/myisam) свои базы.
3. Подготовка MySQL
Надо пропатчить RC-скрипт MySQL для выделения высокого приоритета IO, дабы наша мышца не сдулась в ходе интенсивного бекапа.
Так же следует заметить, что я использую IO scheduler CFQ. Если у вас не CFQ, то можно забыть про приоритеты IO. Узнать/Выставить IO scheduler на девайсе можно в файле:
/sys/block/sda/queue/scheduler
(sda заменить на ваш девайс)
Смысл патча в том, чтобы после старта MySQL отдавать ему высокий приоритет IO в CFQ. Патч на CentOS 5 RC скрипт /etc/init.d/mysqld выглядит так. Думаю, народ разберется.
4. Подготовка авторизации
Я буду делать бекап через кучу пайпов. Причин две:
Так проще
tar накидывается на дисковое IO с меньшим энтузиазмом когда пишет в пайп | gpg | ssh, чем когда пишет на диск.
Конечно, это увеличивает продолжительность бекапа. Но и уменьшает вероятность затыка MySQL на время бекапа.
А именно на 30G – это размер LVM снапшота. Нам он нужен на время бекапа, и размер снапшота должен превышать тот максимальный объем данных, которые MySQL сможет записать за это время на диск. Ну и конечно, в группе LVM vg0 должно быть именно столько или больше свободного места. 30G в общем за глаза.
А это именно тот скрипт, который будет запускаться из крона.
Он запускает backup.php для снятия снапшота, монтирует снапшот в указанную директорию, тарит раздел с таблицами, кидает это все в пайп к gpg для шифрования по алгоритму AES256 с симметричным ключом и кидает дальше в пайп ssh, который уже на удаленной стороне складывает с помощью dd все это хозяйство в файл бекапа с временной меткой. Фух.
Далее он размонтирует снапшот и удаляет его.
Если кто успел заметить, используется утилита gpg для шифрования симметричным ключом, который расположен в файле $keyfile. Данный файл должен содержать около 20 случайных ASCII символов одной строкой. Стоит заметить что нужно создать этот файл раз и навсегда и сохранить где то у себя его копию, поскольку расшифровать бекап можно будет только с его помощью. А сделать это можно будет сделать командой:
gpgpath – путь к gpg, с завершающим слешем vgname – имя группы LVM, содержащей том с таблицами MySQL lvname – имя тома создаваемого снапшота partitionlvname – имя тома с таблицами MySQL в группе $vgname mntpoint – директория для монтирования снапшота remotehost – юзер и хост для удаленного бекапа (см. пункт 4) f — имя файла, в который на удаленной стороне будет складываться шифрованный бекап
Собственно, все. Удачного дебага всего этого хаоса что выше ))
Для логирования медленных запросов Apache очень удобно использовать модуль mod_log_slow, домашняя страница которого находится по адресу http://code.google.com/p/modlogslow/