Каждый день на badoo.com пользователи просматривают порядка 100 миллионов профилей других юзеров. Мы храним счетчики и полную историю посещений за последние 90 дней, с некоторой агрегацией - это около 5 миллиардов ивентов. Система обрабатывающая этот поток данных создана давно и пережила несколько инкарнаций, становясь все ближе к базе данных.
В какой-то момент мы решили перестать изобретать велосипед, отказались от демонов на C+sqlite, не стали делать на mysql-ях, редисах и мемкешах, а взяли и запилили на Tarantool.
Рассказываем почему Tarantool, как шардим, реплицируем (все просто) и как плавно это дело внедрили на живой системе без downtime.
2. ~60k php req/sec + 200k media req/sec
Badoo
215M пользователей в 200 странах
переводы на ~50 языков
~500k req/sec к внутренним сервисам
~3000 серверов
2.5 датацентра
6. Как устроен хит
to from
timestamp
is_visible
source
is_new
поиск, чатик, encounters, письмо, etc. (bitmask)
юзер спрятал хит из списка?
юзер уже видел этот хит?
Задача
8. Начало - 2003
> придумали и сделали основные фичи
> храним историю за 30 дней
одна площадка
“патчик” в мемкеш, пишет текстовые снапшоты
!
История
9. hitd - 2008
> появилась еще одна площадка
> нужно экспортировать данные в базу
! медленно загружаемся из текстового снапшота
пишем логи - для репликации и экспорта
сделали снапшоты бинарными
История
10. hitd - 2009
> количество пользователей выросло в 7 раз
> хотим историю за 90 дней вместо 30
расшардили, сделали по три машины на площадку
! кончилась память
История
11. hitd - 2010
> нужно добавить поля в структуру хита
хотим простую эволюцию схемы данных!
решили попробовать sqlite
История
12. hitd - 2010+
С ростом базы - sqlite перестает справляться
hitd
апдейты
aggregator
основная база
replace/insert/update
syncer на другую площадку
История
13. hitd - 2013
держим апдейты и базу на разных дисках
! рестарт требует “прогрева базы”
cat /path/to/db > /dev/null
! не успеваем доклеивать апдейты в базу
растет WAL, рекорд - 27gb
копируем базу на ramdisk и делаем repair :(
История
14. Что хотим (2014)
История
> решить проблемы с нехваткой iops
> упростить сетап и обслуживание
> простоту программирования
> возможность влезть и “пропатчить” если нужно
“достаточно” performance (latency ~1ms / 10k rps)!
16. MySQL
Инструменты
+ переносим логику в php, данные - в mysql
+ данные пользователей уже расшардены
выжмем достаточно скорости
+ готовые админские инструменты
~ нужны транзакции, никакого handlersocket
- непредсказуемое время ответа–
?
17. Redis
Инструменты
+ быстро, ибо in memory
+ можно сделать lua api ( слегка неудобно)
~ неудобно делать удаление старых данных
~ сохранение на диск можно сделать лучше
+ хорошая документация и community
18. Tarantool
Инструменты
+ быстро, ибо in memory
+ lua - только на сервере, обновление кода на лету
+ есть документация и дружественные девелоперы
+ отличная сохранялка на диск
~ напряженка с php коннектором
здесь должна
быть
фотка
Кости Осипова
19. Мега фичи
Инструменты
обновление lua кода без рестарта
фоновые “процессы” - удаляем старые данные
произвольное количество полей в tuple
не только key-value, индексы по нескольким полям
20. Данные и запросы
uid_to uid_from timestamp sourceis_visible is_new
Реализация
add - добавить или обновить в радиусе 30 мин
× del - удалить по uid_to или uid_from
+
… list - постраничный список хитов с фильтрацией
✂ cleanup - зачистить хиты старше 90 дней
∑ counters - сколько новых хитов? за последний час?
21. Попытка #1
uid_to uid_from timestamp sourceis_visible is_new
unique
index index
Реализация
index
+50% служебные данные для каждого tuple
+200% копии данных в индексах + служебные данные
- нужно 300 гигов памяти… опять:(
120gb исходные данные
22. Попытка #2
uid_to 0 1 42 3 ∞
uid_from timestamp sourceis_visible is_new
Реализация
X записей -> одна, со списком из X элементов
всего один индекс, из одного поля
~ нужно бегать по списку для поиска нужных хитов
~ поддерживаем уникальность ручками
23. Нюансы
uid_to 0 1 42 3 ∞
uid_from timestamp sourceis_visible is_new
Реализация
tuple[n] - честно бежит по списку, т.е. O(n)
нужно кешировать результаты запроса count
~ если хитов очень много - разбиваем список на части
24. Репликация
Реализация
> нужна полная копия данных на каждой площадке
> нужен умный merge хитов на приеме
делаем свою на php + lua stored procedures
! встроенная репликация не подходит
(кроссплощадка)
25. tnt
Прага
tnt
Майами
x3 x4
php Берем по-многу за раз
Заливаем по одной
~8500км
~140ms latency
Реализация
lua процедуры repl_load, repl_list, repl_count
php карта + транспорт
! экономим latency, скачивая пачками
на практике latency ~1500ms
при ~1000 записей/сек
27. Dark launch
импортируем часть данных в tarantool
включаем постепенно для части пользователей
пользователи ничего не заметят, а мы потестируем
Выкладка
измеряем, оптимизируем - повторяем