Rails do scale: Лицемер

топ 100 блогов levgem05.06.2010 Вчера Лицемер дошел до отметки в 29300 запросов в минуту при среднем времени ответа порядка 200 мс. Как и обещал, рассказываю, что делал.

Внутренняя структура не очень сложная: таблица с пользователями, таблица с настройками, таблица с комментариями. Остальное неважно. Всё вертится на рельсах и, да, это было правильное решение, потому что позволяло предельно быстро пробовать и перестраиваться.

В качестве базы данных был выбран постгрес и это тоже очень правильное решение, потому что в отличие от mysql, позволяет гораздо дешевле (читай без выделенного DBA) перестраивать новые схемы данных, менять индексы и, что самое главное, умеет правильно использовать индекс при ORDER BY, а так же невообразимо быстро делает ORDER BY random(). Это оказалось очень важно.

Для дальнейшего рассказа надо отметить ещё одну деталь: запись и чтение идут почти поровну. Люди ставят баллы друг другу как заведенные.

Вся история оптимизации лицемера сильно напоминала ремонт дамбы во время паводка. Пока дамба протекает, уровень воды маленький и напор слабый. Латаем, уровень растет, растет усилие. Тут тоже самое: пока пользователям было неудобно, их было мало. Стало удобно, их стало больше, нагрузка выросла. В процессе общения с заказчиком нагрузки более чем 3 раза превысили самые смелые ожидания.




Этап первый



Когда пациент попал в руки, в нём не оказалось ни единого индекса. Индексы добавили, время упало с 8000 мс до 900 мс, однако начала тормозить вставка. К тому времени таблица с пользователями имела уже порядочный размер, поэтому индекс стал недешевой штукой.

Из-за построения индекса резко упала скорость записи, в следствие этого пользователям стало очень неудобно комментировать, ведь следующую девчонку не покажут, пока не записался комментарий про текущую.

pgpool



Для целей надежности перед двумя постгресами стоял pgpool. Это первое что надо стереть, когда начинает расти нагрузка. Убирание pgpool дало ещё несколько дней передышки, снизив скорость записи в базу, раза в 4


Ускорение записи



Поскольку в рельсах нельзя отложить запись в базу на момент после ответа серверу, было принято решение воткнуть быструю очередь сообщений. Мой выбор был rabbitmq, потому что в отличие от ActiveMQ, он вообще не требует конфигурации, работает из коробки и достаточно стабильно. Проблемы, которые с ним возникали, все были от внешней среды (неправильные настройки ОС или заканчивающееся место на разделе).

В итоге забесплатно получился большой буфер, позволяющий прожевать всплеск активности пользователей.

Я использовал персистентные очереди, что бы не бояться падения кролика. С ними есть проблемы: после рестарта кролик очень долго, минут по 5 проверяет свои таблицы с этими очередями.

Плюс он никак не диагностирует свободное место на диске — сами следите за этим. Ещё была проблема в том, что во freebsd стояло очень маленькое ограничение на размер data size. Предположительно это приводило к его core dump. Когда я выкрутил data size в ulimit до 5 ГБ, проблема исчезла.

Шардинг



Когда лицемер попал ко мне в руки, комментарии уже были разбиты на 100 таблиц: number = recipient_id % 100.

Это очень удобно и рекомендую так поступать. Размер одной таблицы при этом снижается в 100 раз по сравнению с одной большой, соответственно радикально уменьшается время вставки в индекс и делает вообще возможным процесс переноса таблицы на другую БД.

Однако, это было 100 таблиц внутри одной БД. Повторю: так стоит делать даже внутри одной БД.

Зарегистрировав 3000-миллисекундную выборку из таблицы по первичному ключу, мы поняли что одна база уже не справляется. 3 мегабайта в секунду записи на диск — это был потолок одного сервера и решили ставить ещё один. Не знаю, насколько это хорошо или плохо, но система на такой скорости общения с диском уже плохо делала ls

Для этого разбили пользователей так же на 100 шардов (а потом и их свойства) и отправили на второй сервер половину таблиц.

Нагрузка спала, впрочем через небольшое время вернулась, потому что пришли ещё пользователи.

Шардинг и рельсы



Для работы с шардами и многими БД в рельсах сейчас полноценного плагина нет. Я воспользовался Ковыринским db_charmer, который делался прежде всего для master/slave, и на нём так и остался, однако любая работа выглядит так:


User.choose_partition(user_id)
user = User.db_for_key(user_id).find_by_user_id(user_id)
user...
user.db_for_key(user_id).save


Не очень удобно, зато предсказуемо. Плюс ActiveRecord жить не может без концепции мастер базы. В случае с 10 равноправными шардами никакой мастер базы нет.

Кроме такой формы неудобства Лёшин плагин никаких сюрпризов не приподносил, поэтому я остался на нём. data_fabric отдавал какой-то магией, которой мне в этот момент хотелось меньше всего.


Важно так же понимать, что при шардинге можно распрощаться со всякими клевыми ассоциациями, потому что прийдется учить has_many ходить к правильному партишну.

Очередь и шарды



Через некоторое время количество баз увеличилось до 8 штук и начались проблемы с очередью. Дело в том, что все комментарии сваливались в одну очередь из которой 30 воркеров вытаскивали сообщения, обрабатывали их и писали в базу.

Одна база начала сбоить (хард рассыпался что ли) и в итоге все воркеры вставали в очередь на запись в эту базу. Очередь росла, потому что другие базы стояли и всё становилось плохо.

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

Так же в отдельную очередь вынесли отсылку комментариев на вконтакт. Блокирование http запроса не должно тормозить запись в базу.

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

Инструменты



Рельсы показали себя хорошо. Излишних проблем не создавали, ActiveRecord оказался в такой необычной для него ситуации, не очень большой проблемой.

unicorn для такого сайта — это пожалуй единственно возможный механизм деплоя рельс. zero downtime deploy наше всё.

Советую загодя разобраться с chef. Без него деплоить серверы пачками становится очень дорого.

Постгрес показал себя хорошо. pgpool показал себя плохо. Хочется репликацию — берите londiste, это лучший вариант сейчас.

rabbitmq требует стабильного окружения вокруг себя. Настраивайте мунин или чего там, но за местом на диске следить надо в любом случае. И проверьте, что письма о том, что закончилось место, приходят. Поставьте к нему Alice для мониторинга очередей.


FreeBSD… Цензурных слов мало, но это была одна из самых дорогих ошибок заказчика. Сразу скажу спасибо Rails do scale: Лицемер [info]_slw, он здорово помог с её настройкой. Теперь, почему я так негативно к ней настроен.

Время развертывания свежего дебиановского сервера — минут 15-20. Ровно столько, сколько надо скопипастить apt-get install ruby, postgresql и дождаться, пока это всё распакуется. Установка фри занимает больше рабочего дня: пока порты скачаются, пока то, пока сё. В них ещё и битые пакеты и она отказывается их ставить.

Короче, если вы админ, вам она полезна, потому что без вас никуда. Если же вы заказчик, то помножьте количество серверов на 6 часов и помножьте на стоимость часа работы человека. FreeBSD — это тамагочи с которым постоянно надо возиться, причём при постоянной коммуникации админа и программистов.

Плюс надо понимать, что установка порта во фре ещё не значит, что всё запустилось. Для того же постгреса надо сделать ещё кучу действий, что бы он стал рабочим. Короче, неоправданно дорогой инструмент с очень низкой степенью автоматизации, отвлекающий вас от основного бизнеса.



Советы



Используйте вконтактовский user_id в качестве users.id. Это тот самый случай, когда можно и нужно переопределять primary key. Будет немного неудобно в рельсах, но разберитесь с этим.

Сразу думайте, как будете распиливать. Миллионы записей держать в одной таблице неправильно и не получится. Лучше в два раза увеличить объём данных, но получить возможность распилить таблицу на сотню шардов.

Используйте рельсы и ActiveRecord. Если всё пойдет хорошо, то времени на эксперименты с экзотикой типа Datamapper не будет, инструменты должны быть проверенные.

С базой данных рецепты общие: ставьте те индексы, которые нужны, убирайте которые не нужны, читайте slow query log. В мускле он плохой, потому что не показывает меньше секунды, однако надо урезать всё, что дольше 300 мс.

Используйте очереди сообщений. Надежные типа rabbitmq. Они позволят сократить время ответа засчёт отложенной записи.

Обязательно выстройте систему слежения за состоянием кластера:
1) место на всех разделах
2) живость разделов
3) длину очереди сообщений на запись

График в мунине — это фигня. Должны ходить письма. Письма о том, что «всё хорошо» ходить не должны, они раздражают. Пусть ходят письма только когда что-то плохо.

Нахрен не нужно разбивать даже и на два раздела жесткий диск. Логи в такой системе вообще не нужны, выключите их и в рельсах, и в nginx и где только можно, они только хард убивают. Всё что надо, трекает вконтакт, а вот проблемы из-за того, что кончилось место в 400-меговом разделе /var, куда кролик пытался записать очередь сообщений, просто добивают своей бессмысленностью.

Постгресовый wal отправляем на другой хард. И вообще всячески разгружаем жесткий диск, на который пишет БД.

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

Оставить комментарий

Архив записей в блогах:
Трансформация мира, это когда то, что вчера вызвало шок - сегодня становится просто жизнью. Когда все вернется на круги своя и мир станет прежним? Таким привычным и для многих удобным. Думаю, почти каждый из нас уже задавал себе этот вопрос. Мой ответ – никогда. Никогда он уже не ...
Через месяц мы будем отмечать день рождения "Чатика", сообщества, которое спонтанно родилось на одном из жж-завтраков. Вокруг завтраков всегда оно было. Дружба, встречи, партнёрство, активности. Но никогда не управлялось и не направлялось мной. И вот с прошлого октября появилось ...
Но внезапно выясняется, что встреча на фото была аж 2 мая (фото №2). 16 декабря 2022 года главком ВСУ Залужный в интервью The Economist с пафосом рассказывал, что новая религия Украины и его лично - «убивать русских». Но что-то пошло не так и сегодня единственный контрнаступ, ...
Ощущая со временем свой распад, как физического тела, я понимаю, что он осуществляется по жизненным природным законам, которые суть вечные и неизменные решения Господа. Осознавая это, я чувствую радость от исполнения божьего закона. ...
Как-то писал про популярные в Италии историко-приключенческие романы Леонардо Гори . А вот яркий пример итальянской исторической фантастики. На сегодняшний день историк Витторио Ветрано, ушедший в литературное творчество, опубликовал уже три романа ("Сокровище Экватории", "Тайна ...