Многие из вас уже слышали о нашем проекте Tarantool. Это СУБД, или, попросту говоря, база данных с сервером приложений внутри. Tarantool — проект с открытым исходным кодом, и с ним может работать кто угодно. Развивается этот проект уже больше восьми лет. В Mail.Ru Group Tarantool активно используется более чем в половине продуктов: в Почте, Облаке, Моём Мире, Агенте и др. Все сделанные нами доработки этой БД мы коммитим обратно на GitHub, и сообществу доступна та же самая версия БД, что и нам. Сейчас у нас есть клиентские библиотеки почти ко всем языкам, мы сильно прибавили в этом направлении за последний год. Часть из них написана сообществом, часть — нами. Если появляется какая-то более эффективная библиотека, то мы просто делаем её официальной. Мы стараемся, чтобы всё было прямо из коробки — и БД, и библиотеки.
Одна из главных особенностей Tarantool заключается в объединении свойств БД и кэша. БД — это нечто надёжное, с транзакциями, серверным языком запросов. А кэш быстрый. И оба этих мира органично сливаются воедино в Tarantool. Эта БД предназначена для использования в высоконагруженных проектах и для работы с горячими данными.
Сравнение с классическими решениями
Если вы работаете с «традиционными» БД, например MySQL или Oracle, то наверняка сталкивались с тем, что вашей системе не хватает свойств кэша: большого быстродействия, маленького Latency и многого другого. В традиционных БД всего этого нет. У кэшей тоже есть свои недостатки, в том числе отсутствие транзакций. Даже если вы используете кэш + БД, например MySQL в связке с Memcached или PostgreSQL в связке с Redis, то это всё равно приводит к компромиссам: у вас частично теряются свойства БД, к примеру отсутствуют транзакции, хранимки, вторичные индексы. Также утрачиваются какие-то свойства кэша, например большая пропускная способность на запись. При этом появляются новые проблемы, самые серьёзные из которых — несогласованность данных и холодный старт.
Но если этот компромисс вас не устраивает и вам нужны все преимущества кэша и БД, то обратите внимание на Tarantool. Он лишён всех перечисленных недостатков. Tarantool устроен очень просто. Грубо говоря, он хранит на диске два файла: снапшот данных на какой-то момент времени и лог всех транзакций начиная с этого момента времени. Мы проводили тестирование на скорость холодного старта. Чтение файлов в память с магнитного диска происходит со скоростью 100 Мб/с. То есть, например, база данных в 100 Гб считается за 1000 с — примерно 15 мин.
Для сравнения, когда мы игрались с MySQL и PostgreSQL, там всё было гораздо хуже. Они хранят данные на диске. Там нет такой проблемы, что база не отвечает, пока всё не загрузит в память. Но кэш у них прогревается гораздо медленнее (1–2 Мб/с), и поэтому нужно прибегать к разным трюкам, наподобие предварительного прогрева индекса. Те, кто админит MySQL, это прекрасно знают. Tarantool же просто встаёт и работает. Время холодного старта — минимально возможное.
Недостатки
Тем не менее нас не всё удовлетворяет в этой БД. Первое, над чем мы работаем, — это дисковое хранилище. Tarantool изначально создавался как In-Memory БД. Благодаря своей скорости и низкой потребности в серверах, по стоимости владения он всё равно лучше, чем традиционные дисковые БД. Но поскольку Tarantool — это In-Memory БД, то возникает вопрос: что делать с холодными данными? С горячими данными он работает эффективно, но всё лежит в памяти, в том числе и холодные данные. Поэтому мы разрабатываем дисковое хранилище. Кстати, у нас в продакшене все Tarantool’ы работают на самых дешевых SATA-дисках. SSD можно поставить только для быстрого старта, но при наличии реплик это неактуально.
Пока что мы ничего не делаем с холодными данными. Их балласт с лихвой окупается быстротой работы и безумно малым количеством серверов. Например, профили пользователей обрабатываются всего восемью Tarantool’ами, а в MySQL это была бы ферма из тысячи серверов. Но если бы мы лучше работали с вытеснением холодных данных, то Tarantool’ов могло бы быть не восемь, а четыре.
Также мы разрабатываем автоматические кластерные решения. У нас сейчас их несколько, но они не универсальные. А мы хотим сделать одно правильное универсальное, чтобы можно было поставить Tarantool на десять серверов, а внутри всё шардилось, решардилось, реплицировалось, и чтобы голова не болела.
Кроме того, мы делаем поддержку разных систем, например SQL. Опять же, она пока в нестабильном состоянии, но мы возлагаем большие надежды. Поддержка SQL нужна в основном для того, чтобы можно было легко мигрировать. В той же Почте Mail.Ru есть под сотню MySQL-серверов, чью нагрузку можно перенести на пару Tarantool’ов. Но поскольку нет поддержки SQL, то нужно переписывать тонну кода. Так что проще один раз сделать поддержку.
У нас используется свой собственный аллокатор, типа Slab-аллокатора, позволяющий минимизировать влияние фрагментации памяти. Но он всё ещё неидеален, мы постоянно работаем над его улучшением.
Как подсчитать объём памяти для Tarantool’а
У Tarantool’а очень хороший Memory Footprint, а это означает маленький overhead на хранение данных. Размер данных на диске (или в памяти) лишь немногим больше размера чистых данных. Если вам нужно хранить 1 млрд строк, в каждой из которых десять полей, размер поля — четыре байта, то это будет 4 х 10 х 1 млрд плюс 1–10% оверхеда на управляющие структуры.
Наши юзкейсы
В Mail.Ru Group Tarantool используется для решения самых разных задач — суммарно наберётся несколько сотен инсталляций этой БД, из них три самые высоконагруженные: система аутентификации, система push-уведомлений и система показа рекламы. Расскажу подробнее про каждую из них.
Система аутентификации
Система аутентификации по логину и паролю
Система аутентификации по сессии/токену
Наверное, такая система есть у каждого сайта и мобильного приложения. Речь идёт о проверке логина-пароля или сессии. Это центральная система, весь наш портал использует её для аутентификации пользователей. У этой системы есть очень интересные требования, которые даже могут показаться несовместимыми:
- Востребованность. Каждая страничка, каждый Ajax-запрос, каждый вызов мобильного API обращается к этой системе, чтобы аутентифицироваться.
- Низкое время отклика. Пользователи не любят ждать, они хотят быстро получать всю информацию. То есть каждый вызов должен быстро обрабатываться.
- Высокая доступность. Система аутентификации не должна быть причиной ошибки 500. Если она не может обслужить запрос, то пользователь не обслуживается вообще, ведь дальше не идёт весь поток исполнения серверного запроса.
- Постоянные обращения к хранилищу. Каждый хит системы авторизации — это проверка сессии или логина-пароля, т. е. некий Select в базе, а иногда даже Update. Ещё есть системы anti-bruteforce и anti-fraud — нужно проверять на каждый хит, с хорошими ли намерениями обращается пользователь. Каждый хит системы авторизации может что-то обновлять, например последнее время сессии. Если это авторизация по логину и паролю, то нужно создать сессию, а значит, сделать Insert в базу. При anti-bruteforce-проверке нужно записать месторасположение пользователя (IP-адрес или что-то ещё). То есть процессов чтения и записи немало. Систему авторизации постоянно пытаются взломать, что создаёт дополнительную нагрузку, ведь она каждый раз обращается к БД, чтобы потом отказать злоумышленнику в авторизации.
- Большой объём данных. В этой системе должна быть информация обо всех пользователях.
- Данные должны быстро экспайриться. По сути, это тоже апдейты. Например, должны экспайриться сессии пользователя.
- Персистентность. Всё должно быть сохранено на диске, каждое изменение. Cессии пользователей нельзя хранить в Memcached, потому что вы их потеряете при падении сервера, и пользователям придётся заново вводить логин и пароль. А они не любят этого делать.
Некоторые из этих требований удовлетворяются, только если вы используете кэш. Например, высокая нагрузка, экспирации и прочие вещи, которые характерны для кэша. Другие требования удовлетворяются, только если вы используете базу данных. Поэтому система должна быть основана и на кэше, и на БД, объединённых в одно решение. Она должна быть надёжной и долговечной, как грузовик, но при этом быстрой, как спортивная машина.
Сейчас нагрузка по проверке логинов-паролей на нашу систему аутентификации составляет примерно 50 тыс. запросов в секунду. Кажется, что не так много, но по каждому запросу нужно сделать массу работы, в том числе проверить anti-bruteforce, выполнить много транзакций в БД и т. д. Tarantool со всем этим успешно справляется.
Зато количество аутентификаций по сессии достигает 1 млн в секунду. Это то, что приходит со всего портала. Эту нагрузку держат всего 12 серверов: четыре с сессиями и восемь с профилями пользователей. При этом они загружены всего на 15–20%, т. е. запас прочности очень велик. Просто мы любим обычно перезакладываться.
Система push-уведомлений
Сейчас всё больше и больше пользователей переходят в мобильный сегмент. Они в основном используют там приложения, а не обычный мобильный веб. И в приложениях есть такая штука, как push-уведомления. Когда на стороне сервера происходит какое-то событие и нужно уведомить об этом мобильное устройство, то как обычно это устроено? Самому мобильному приложению нет нужды держать соединение с сервером, это происходит на уровне операционной системы, которая соединяется с соответствующим веб-гейтом и периодически проверяет наличие push-уведомлений. То есть серверный код ходит в специальный API от iOS и Android, которые уже сами связываются с операционными системами на мобильных устройствах.
Чтобы соединиться с этими API и отправить данные, требуется как-то идентифицировать пользователя, поэтому пересылается токен. Токен надо где-то хранить. Более того, на одного пользователя нужно несколько токенов, потому что у него может быть несколько устройств. И пересылать токен нужно на каждое событие на сервере, о котором вы хотите уведомить пользователя. А таких событий много. Чем чаще вы уведомляете пользователя, тем чаще он пользуется вашим приложением. Поэтому для системы push-уведомлений нужна быстрая и надёжная БД.
Мы воспользовались Tarantool’ом просто потому, что у нас огромное число запросов и транзакций, для отправки push’а нужно сделать множество проверок. Причём сделать быстро. Мы не можем тормозить в этом месте, ведь это Server Side, от работы которого зависит много процессов, потребляющих много памяти.
Как вы думаете, хорошо ли, если Server Side напрямую соединяется с Android или iOS? Это плохо по нескольким причинам. Во-первых, с точки зрения архитектуры — потому что вы теряете универсальность. Ведь может появиться Windows Mobile или ещё кто-нибудь, вырастет сложность разработки, потребуется доработать кучу систем. Во-вторых, у вас возникает дополнительная точка отказа, и всё взаимодействие значительно усложняется. И в-третьих, эти мобильные API могут тормозить или упасть. Они не гарантируют быстрый ответ, могут отвечать несколько секунд. Поэтому нужна какая-то прослойка, очередь, куда помещаются все изменения, а оттуда они улетают на Apple и Google, в их API. Терять эти уведомления мы не можем. Так что очередь должна всё хранить на диске, но при этом быть очень быстрой. Tarantool полностью удовлетворяет этим критериям. Наша система выдерживает достаточно большую нагрузку — 200 тыс. запросов в секунду, и запись, и чтение. Каждое обращение в очередь — это запись, транзакция, которая реплицируется на несколько реплик. Тем не менее всё работает очень быстро.
Система показа рекламы
У нас большой портал, и мы показываем пользователю рекламу почти на каждой странице. Управляет этим процессом система показа рекламы, которая называется Target. Одна из основных проблем рекламной системы — она должна работать супербыстро и держать супербольшую нагрузку. Даже больше, чем система аутентификации. Потому что сессии — это обращение к БД, может быть несколько обращений на каждый вызов.
Реклама показывается не только на наших страницах, но и на страницах партнёров, и это тоже очень большая нагрузка. Допустим, на странице десяток рекламных блоков. Для каждого из них нужно сходить в источники данных с информацией о профиле пользователя, агрегировать результат, определить, какую именно рекламу показать, отобразить её. И всё это сделать быстро (норматив сейчас — 50 мс), потому что пользователи не любят ждать. К тому же реклама не несёт никакой функциональности для пользователя, и она точно не может служить оправданием медленной работы сервисов.
Наша система показа рекламы — один из самых больших и высоконагруженных кластеров Tarantool в мире: суммарно каждую секунду осуществляется 3 млн операций и около 1 млн транзакций (апдейтов).
В заключение
Tarantool рождён для высокой нагрузки. Если же нагрузка у вас невысока, то он обеспечит хорошее время ответа — одна миллисекунда или меньше. Традиционные БД даже на маленькой нагрузке не умеют выдавать ответ с такой скоростью. А часто нужно сделать несколько обращений, все эти миллисекунды складываются, и получается достаточно печально. Tarantool обеспечит вам высокий RPS, низкое Latency, высокий Uptime, поможет выжать все соки из железа, какие только можно, и при этом у вас будет БД с транзакциями, репликациями и серверными процедурами.
Автор: Mail.Ru Group