Post on 16-Jun-2015
Олег Анастасьев ведущий разработчик, команда платформы odnoklassniki.ru
Ближе к Cassandra
7 M онлайн 40M в день, 80M в месяц
!
~ 300 000 www страниц/сек, 20 ms на страницу
>280 ГБит/сек !
> 6 600 серверов в 5 ЦОД 99.9% java
Cassandra @ *Начинали в 2010
-своя версия, основана на 0.6 -целились в:
выживаемость при отказе ЦОД, масштабируемость, простота эксплуатации, адаптируемость
*Сейчас -23 разных кластера -418 всего нод -240 TB данных !
-пережили несколько отказов ЦОД
“Раз” - котенок !
самый быстрый
Класс! 103 927 Вы и 103 927
Data Range
Виджет Класс!*Он везде
-На каждой странице по несколько -В ленте активности -На сайтах в Интернетах !
*Он на всем -Картинки и альбомы -Видео -Посты и комментарии -Ссылки на внешние сайты
Класс! 103 927
Data Range
Виджет Класс!
Класс! 103 927
*Высоко нагруженный -1 000 000 чтений/сек, 3 000 записей/сек !
*Сложный профиль -Много чтений -Длинный хвост (40% чтений случайны) -Чувствительна к вариациям скорости -3TB данных (9TB с RF) и растет -~ 60 млрд класс!ов к ~6 млрд объектов
RefId:long RefType:byte UserId:long Created
9999999999 PICTURE(2) 11111111111 11:00
Простое решение
Вы и 4256
SQL табличка
!
для отрисовки !SELECT TOP 1 WHERE RefId,RefType,UserId=?,?,?
(98% are NONE) !
SELECT COUNT (*) WHERE RefId,RefType=?,? (80% are 0)
!SELECT TOP N * RefId,RefType=? WHERE IsFriend(?,UserId)
RefId:long RefType:byte UserId:long Created
9999999999 PICTURE(2) 11111111111 11:00
Простая проблема
= N >=1
= M>N
= N*140
Вы и 4256
SQL табличка
!
для отрисовки !SELECT TOP 1 WHERE RefId,RefType,UserId=?,?,?
(98% are NONE) !
SELECT COUNT (*) WHERE RefId,RefType=?,? (80% are 0)
!SELECT TOP N * RefId,RefType=? WHERE IsFriend(?,UserId)
Пробуем CassandraLikeByRef (
refType byte, refId bigint, userId bigint, !PRIMARY KEY ( (RefType,RefId), UserId)
LikeCount ( refType byte, refId bigint, likers counter, !PRIMARY KEY ( (RefType,RefId))
= N*20%
Вы и 4256 для отрисовки !SELECT FROM LikeCount WHERE RefId,RefType=?,?
(80% are 0) !SELECT * FROM LikeByRef WHERE RefId,RefType,UserId=?,?,?
(98% are NONE)
>11 M iops
LikeByRef ( refType byte, refId bigint, userId bigint, !PRIMARY KEY ( (RefType,RefId, UserId) )
*Пробуем решить по быстрому !
!
!!
SELECT TOP N * RefId,RefType=? WHERE IsFriend(?,UserId)
-Нужен Order Pres Partitioner (Random не масштабируется)
-Запросы по диапазону ключей (KeyRange) -Больше сетевого оверхеда -Партиций >10x, Размер данных > x2
*Что делает -Хранит пары (PartKey, ColumnKey) в SSTable
*-Filter.db !
* И это хорошо -Убрали 98 % чтений с диска -Меньше ложных попаданий
*Но все таки… -Они стали очень большими
Проблемы с GC Promotion Failures .. фиксим (CASSANDRA-2466)
Колоночный блум фильтр
Уже готово ?
- 2 похода для отрисовки (COUNT+RR) - THRIFT медленный, когда много клиентов - EXISTS() дает 200 Gbit/sec (140*8*1Mps*20%)
cassandra
00
сервер приложений > 400
1. COUNT()
2. EXISTS
Совместить!
- one-nio remoting (быстрее родного nio в java) - клиенты знают топологию кластера
odnoklassniki-like
cassandra
get() : LikeSummary
Сетевой Бизнес Intf
Кеш счетчиков
Кеш соц. графа
*Быстрый запрос TOP N друзей 1. Берем друзей из кеша соц графа 2. Проверяем по блум фильтру в памяти 3. Читаем с диска пока получим N !
*Свои кеши -Специализированные под приложение !
*Свое объединение реплик данных -… можно находить и разрешать кофликты
Вместе это хорошо
Слушаем мутации// Implement itinterface StoreApplyListener { boolean preapply(String key, ColumnFamily data); }
* Регистрируем слушателя после применения логов но до госсипа
!
*RowMutation.apply() и расширяем логику записей + На репликах, хинты, ReadRepairs
// and register with CFSstore=Table.open(..) .getColumnFamilyStore(..);store.setListener(myListener);
*Кеш счетчиков -Off heap (sun.misc.Unsafe) -Компакен (30M in 1G RAM) -Читаем только кеш локальной ноды
!
* Репликацию кеша - проблема холодного кеша реплик - делаем (NOP) записи
меньше чтений - учитывает длинный хвост
Счетчики с быстрым чтениемLikeCount (
refType byte, refId bigint, ip inet, counter int PRIMARY KEY ( (RefType,RefId),
Вариации скорости*Что делает Cassandra
1. Взять 1 ноду с данным и CL-1 - дайджест 2. Ждем данные и дайджест 3. Сравниваем и возвращаем (или RR)
*Ноды притормаживают -Изза: SEDA, ротируем commit log , внезапно
много IO, заткнулась сеть или пропала, внезапно много IO мимо кеша диска…
*И что видят клиенты ? -Пики времени обработки запросов -Можно только ждать (до таймаута)
Read Latency leveling* “Параллельная” обработка чтений
1. Запрашиваем данные со всех реплик сразу 2. Ждем сколько надо CL ответов реплик
!
*И это хорошо -Всегда минимальное время обработки -Та же нагрузка при отказе ЦОД
!
* что (не так уж) плохо -“Дополнительная” нагрузка и трафик
More tiny tricks*Для SSD io
-Deadline IO шедулер -64k -> 4k размер запроса на чтение
!
*Хинт Лог -Коммит лог для хинтов -Ждем доставки всех хинтов на старте
!
*Селективый компактор -Чаще читаем из CF - чаще компактим
“Два” - котенок !
самый пухлый
*Сообщения в чатах -Читаем свежую страницу на открытии
-длинный хвост (80%) для остальных -150 млрд, 100 TB на дисках -Чтений больше: 120k в сек; 8k записей
Сообщение это структура
-Все сообщения чата в 1 партиции -Каждое представлено блобом
для уменьшения накладных расходов !
-Стало плохо Возможны конфиликтующие изменения одного сообщения
(пользователи, антиспам, чистка,…)
Message ( chatId, msgId, !created, type,userIndex,deletedBy,... text )
MessageCF ( chatId, msgId, !data blob, !PRIMARY KEY ( chatId, msgId )
Легкое разрешение конфликтов
Messages ( chatId, msgId, version timestamp, data blob PRIMARY KEY ( chatId, msgId, version )
get
(version:ts1, data:d1)
write( ts1, data2 )
get
(version:ts1, data:d1)
write( ts1, data3 )
(ts2, data2) (ts3, data3)
delete(version:ts1) insert(version: ts3=now(), data3)
- merged on read
delete(version:ts1) insert(version: ts2=now(), data2)
Специализированный кеш*Опять. Потому что можем
-Off-heap (Unsafe) -Кеширует только свежайшие страницы -Пишет состояние в локальный (system) CF
И ключи, и значения последовательное чтение на старте
-Компрессия данных в памяти В 2 раза больше памяти бесплатно
Делим диски*4U HDDx24, до 4 TB на сервер
-Size tiered compaction = файл до 4 TB -RAID10 ? LCS ?
!
*Делим CF на 256 кусочков *Стало хорошо
-Более частые, но меньшие сбросы мемтаблиц -Столько же работы для компактора
но более мелкими наборами
-Можно распределять между дисками
Политика распределения*Из коробки
-“Берем наиболее свободный по месту диск”
*И теперь некоторые из них -слишком нагружены на ввод-вывод !
*По поколениям -На каждом диске хранится одинаковое
количество sstables одного поколения работает лучше всех для ЖД
“Три” -
Уродливый и страшный
это-ж, братцы, Франкенштейн !
*Список чатов -мало данных (230GB) -есть горячий набор, короткий хвост (5%) -список часто пересортировывается -130k чтений/сек, 21k записей/сек
Конфликтные изменения*List<ЧатOverview> в 1 блоб
.. или мы получим много могилок !
*Много конфликтов все меняют 1 колонку !
*Определен алгоритм слияния *Нужно детектирования конфликтов
Векторные часы*Voldemort
-byte[] ключ -> byte[] значение + ВЧ -Все клиенты - координаторы -Заменяемые виды хранилищ !
*Ну и заменили -На СС таблицы от CS 0.6 -Со специализированным кеш
кеши. мы знаем как.
Скорость*Кластер из 3 нод, RF = 3
-Intel Xeon CPU E5506 2.13GHz RAM: 48Gb, 1x HDD, 1x SSD
!
*8 байт ключ -> 1 KB значение !
*Дает -75 k чтений/сек и 15 k записей
Зачем нам C* ?* Готовые компоненты РБД
быстрое хранилище, gossip, надежные асинхронные сообщения, детектор сбоев, топология, последовательная обработка, ...
*Данные могут быть структутированы сложнее, чем byte[] ключ -> byte[] значение
*Выполнила наши цели *Сделано на java
СПАСИБО
one-nio ремотинг быстрее, чем java nio; с автомагической встроенной сериализацией
shared-memory-cache кеш для java вне кучи и в разделяемой памяти
Олег Анастасьев !oa@odnoklassniki.ru odnoklassniki.ru/oa @m0nstermind !
github.com/odnoklassniki