Tuesday, September 14, 2010

MySQL в tmpfs

Хотелось бы поделиться опытом по использованию MySQL с хранением данных в памяти а не на диске. Это позволило нам сократить load average сервера, который из-за операций с диском стал сильно расти.



В одном проекте мы используем MySQL с движком MyISAM под Debian Lenny. Общие данные загружаются в оперативку демона на С++, а пользовательские данные один раз загружаются при логине и переодически сохраняются во время работы пользователя. Также сохраняются при логауте (либо по таймауту). Ввиду описаной схемы select-ов намного меньше, чем update-ов (select: 24%, delete: 4%, update: 61%, insert: 11%).

В принципе данная проблема - не админская, а вызвана не совсем удачным выбором инструмента. Скорее всего, нам бы подошел InnoDB, который использует row-level locking (блокировка по записям), а не table-level locking (блокировка всей таблицы при записи) как у MyISAM. Хотя объем данных записываемых на диск это врядли сократило бы. С другой стороны, нам SQL особо не нужен и мы склоняемся к портированию проекта на NoSQL (к некоторым из представителей мы давно приглядываемся (Сassandra), а некоторые (tokyo tyrant, Berkeley DB) мы активно используем для логирования пользовательских действий). Но выделить время на перевод хранилища данных на другой движок/базу не было, по этому решили использовать админ. ресурс.

С ростом количества пользователей и введением нового контента мы столкнулись с проблемой роста load average на сервере базы данных (2-3 la на 8-ми ядерном сервере наблюдалось всего при 400 запросах в секунду). При чем память была недогружена, как и процессор. Проблема была в большом большим объемом записи данных на диск (увеличение iowait). В некоторые моменты система начинала заикаться и некоторые примитивные запросы занимали 2 секунды, а то и больше. В нормальном режиме такие запросы выполняются за милисекунды.

Мы немного соптимизировали конфиги MySQL (используя как автоматические скрипты типа mysqltuner, так и ручную настройку), но это дало лишь небольшое снижение нагрузки (процентов на 10-15). По большей части параметры, отвечающие за кеширование данных, нам не подходят, так как у нас основная нагрузка - обновление данных, а не чтение. База находится на SAS диске, но скорости все равно не хватает. Бинарные логи находятся на другом диске (используются для бекапа базы со слейва).

Ускорить работу дисковой системы купив полноценный RAID нам не подходит из-за его большой цены. Но сам сервер почти простаивает, если не учитывать диски. Возможности сжатия данных в памяти до записи на диск в MyISAM нет, но и переходить на другой движек нету пока возможности (Falcon это должен был уметь, но его забросил Oracle после покупки MySQL)

База у нас занимает около 2-2.5 Gb (в tar.gz 700mb) и мы уже давно пробовали использовать MySQL в tmpfs (методом основаном на mylvmbackup), что позволяло не нагружать диск и упростить создание бекапа. К счастью мы недавно провели очистку базы, путем добавления крона, который удаляет старых пользователей, которые почти не пользовались проектом и ни разу не заплатили. Кроме этого мы очистили старые данные, которые собирали для статистики и поставили им срок жизни порядка двух месяцев.

В качестве быстрого решения даной проблемы возникла идея перевести главную базу на tmpfs. Что у нас получилось:

И так мы имели 3 сервера:
1. сервер А (боевая база куда стучатся демоны (у нас на нем 8Г оперативки ))
2. сервер Б (любой сервер на той же площадке со свободной оперативной (у нас 8Г из них 5Г свободно))
3. сервер В (на другой площадке заточен под бекапы всех проектов с максимум оперативки (у нас 16Г))

И так на Сервере А поднимаем tmpfs для файлов базы
mount -t tmpfs -o size=5G tmpfs /var/lib/mysql (с запасом в 2 раза больше чем весит база)
Так же не забываем в конфигах базы написать чтоб бин логи писались на оддельный свободный диск (мастер без них не работает), а под нагрузкой база может писать в эти логи до 1М в сек. Мы храним эти файлы не более 7 дней (более и не надо т.к. для востановления базы если что есть слайвы)

Соответсвено стартуем базу как мастер. Сервер под самими жескими нагрузками не выходит из 1ЛА и по памяти не более 6Г. Средняя скорость выполнения запроса вызросла в десятки раз, если раньше было 0,1-0,3 сек то стало 0.1-3 мсек
Далее на сервере Б так же поднимаем первый слейв тоже в tmpfs тут не стоит забывать о настройках relay-log т.к. если в слайве будет ошибка, а мастер будет доступен в эти логи он будет писать запросы которые были на мастере.. В итоге это может измерятся десятками гигобайт за ночь, прежде чем вы почините слайв, у нас это около 8-10 гигабайт в час. Бекапим эту базу снапшотами ночью 1-2 раза в день когда нагрузка на демоны минимальна. Такой слейв жрет максимум 0.2-0.3 ЛА и чуть более того что весит база.

Также на сервере В у нас подняты сразу несколько слайвов на tmpfs под наши проекты, споконо живут вместе особо не нагружая сервер при этом бекапятся снапшотом раз в 10 минут (если это время разложить то снапшот делается около 3 сек (базы вес которой 2,5 гига) ну и зжатие в архив около 6-7 минут) и да же при этом на сервере ЛА не привышает 2, даже когда бекапы пересикаются по времени. Судя по всему кол-во бекап слейвов на одном сервере определяется размером баз и кол-вом оперативки. Бекапы храним по 10 минут - последние 24 часа, каждые 6 часов - храним 30 дней, каждые 30 дней - вечно.

Далее если вдруг падает слайв Б или В поднять его с любым из бекапов с другово слайва не трогая мастер без проблем ели даже оба падают поднять не трогая мастер 10 минут - скорость переписывания бекапов.
Если падает мастер то есть на это два слейва с отстованием максимум 1-2 апдейта от мастера (не разу ни видели чтоб Slave Delay(отстование от мастера) превышал 0 сек) , при этом срочное решение проблемы это втечении 5 минут из слейва Б сделать мастер .. и перестроить демоны, при тестах они спокойно живут на одном сервере и не мешая друг другу.

В итоге чтоб одновремено упали 3 машины на 2 разных площадках это очень мало вероятно, поднять базу при любом подении сервера или площадки займет не более 10 минут.

Обязательно настраиваем оповещалки (munin, nagios, zabix - кому что больше по душе) на 2 площадках с измерением отстования слайва, можно по смс или по мылу, у нас нагиос следит за этим и при этом мунин его страхует и при этом рисует графики по которым все очень наглядно виодно что и как и кого.

Load average на серверах снижается осень сильно, теперь основную нагрузку берет на себя процессор и память, а не диск. Вот графики которые мы сняли при ещё одного переводе сервера сегодня:






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

В общем единственная потенциальная проблема — это рост базы. Но сейчас память в серваках достаточно дешевая и увеличить её не составит проблем (на части машин у нас 16Gb, на части 8Gb, но, насколько мне известно, можно поставить в потолке 128Gb). В любом случае кластеризацию базы никто не отменял и мы сможем разпределить базу на несколько серверов с схожей конфигурацией.

InnoDB - http://dev.mysql.com/doc/refman/5.1/en/innodb.html
MyISAM - http://dev.mysql.com/doc/refman/5.1/en/myisam-storage-engine.html
Сassandra - http://cassandra.apache.org/
tokyo tyrant - http://fallabs.com/tokyotyrant/
Berkeley DB - http://www.oracle.com/technetwork/database/berkeleydb/overview/index-085366.html
mysqltuner - http://mysqltuner.com/mysqltuner.pl
Falcon - http://en.wikipedia.org/wiki/Falcon_(storage_engine)
tmpfs - http://en.wikipedia.org/wiki/Tmpfs
mylvmbackup - http://www.lenzg.net/mylvmbackup/

2 comments:

  1. MyISAM иногда начинает тупить если у него большие таблцы с частыми UPDATE или DELETE. Поэтому нужно регулярно делать ANALYZE TABLE/OPTIMIZE TABLE. Я однажды это прямо в работающую программу вставил, потому что при 10 Gb таблицах он начинал тупить уже через день-два активной работы.

    ReplyDelete
  2. ...более того, я изменения в таблицы не писал прямо сразу туда, а записывал в отдельные таблицы рядом: одна с апдейтами, другая с инсертами (делитов не было), а потом заливал изменения в главную таблицу, после чего делал ANALYZE TABLE/OPTIMIZE TABLE ;)

    Вообще говоря, странно это что при трехгиговой базе у вас что-то тормозило. Вы пробовали тюнить my.cnf?

    ReplyDelete