Cоциальный граф "Одноклассников" в myTarget

49
Социальный граф «Одноклассников» в myTarget Олег Царёв, ведущий разработчик myTarget

Transcript of Cоциальный граф "Одноклассников" в myTarget

Page 1: Cоциальный граф "Одноклассников" в myTarget

Социальный граф «Одноклассников» в myTarget

Олег Царёв, ведущий разработчик myTarget

Page 2: Cоциальный граф "Одноклассников" в myTarget

myTarget

•  Платформа таргетированной рекламы •  Более 70 таргетингов (пол, возраст, регион, …, установленные приложения, поисковые запросы)

•  «Одноклассники», «Вконтакте», «Мой Мир», …

•  Огромные нагрузки

Page 3: Cоциальный граф "Одноклассников" в myTarget

О чём этот доклад

Социальный граф «Одноклассников»

+ myTarget

Page 4: Cоциальный граф "Одноклассников" в myTarget

О чём этот доклад

•  Социальный граф «Одноклассников» + myTarget

•  Можно ли из этого получить деньги? •  Каким именно образом? •  Какие технические проблемы придётся решить?

Page 5: Cоциальный граф "Одноклассников" в myTarget

Пара слов о докладчике

•  Ведущий разработчик проекта •  Отвечает на вопросы «Как?», «Почему?»,

«Сколько?», «Где?» •  Оптимизирует узкие места •  Обучает коллег, руководит коллегами •  Пилил три разных СУБД (в том числе MySQL) •  Подслушивает в курилке умных людей •  Имеет вредный характер

Page 6: Cоциальный граф "Одноклассников" в myTarget

Постановка задачи

"У нас есть задача использовать социальный граф пользователя в рекламе. Первая модельная задача, которую мы хотим решить - показывать пользователю, кто из его друзей играет в какую-то игру (например, в ту, в которую зашел сейчас пользователь или которую мы рекламируем). Мы хотим иметь возможность получить эту информацию очень быстро, т.к. хотим получить ее прямо во время выполнения запроса, не подготавливая при этом обширно данные. Исходно у нас есть набор пользователей, для каждого пользователя известен список его друзей и игр, в которые он играет."

Page 7: Cоциальный граф "Одноклассников" в myTarget

Результат

Page 8: Cоциальный граф "Одноклассников" в myTarget

Результат

Page 9: Cоциальный граф "Одноклассников" в myTarget

Результат

Page 10: Cоциальный граф "Одноклассников" в myTarget

Это очень простая задача

#!/usr/bin/env python friends = {1: [2,3], 2: [1], … } games = {1: [game1], 2: [game2], …} wp = defaultdict(defaultdict([])) ok_id = 1 for friend_id in friends[ok_id]: for game in games[friend_id]: wp[ok_id][game].append(friend_id)

Page 11: Cоциальный граф "Одноклассников" в myTarget

Технические требования

•  Десятки* тысяч запросов в секунду •  Максимальное время ответа – единицы миллисекунд

•  Чем меньше требуется ресурсов – тем лучше

Page 12: Cоциальный граф "Одноклассников" в myTarget

Дружба: общая информация

•  Социальный граф •  Вершины: 200 миллионов пользователей •  Рёбра: 13 миллиардов связей •  Граф импортируется в виде лога обновлений •  По логу обновлений можно получить состояние графа в любой момент времени

•  Граф используется для других задач •  Размер лога за всё время: 1.2 терабайт •  Ежедневные обновления: 380 мегабайт

Page 13: Cоциальный граф "Одноклассников" в myTarget

Дружба: как устроены события

События со следующими атрибутами: •  event_id: монотонно возрастает •  event_type:

•  A – связь добавилась •  D – связь удалена

•  ok_id_1: кто дружит •  ok_id_2: с кем дружит •  timestamp: когда связь поменялась •  Есть другие атрибуты (исключил из рассмотрения)

Page 14: Cоциальный граф "Одноклассников" в myTarget

Дружба: актуальный статус связи

Как узнать: дружат два пользователя или нет? 1.  Найти все события (ok_id_1, ok_id_2) 2.  Отсортировать по timestamp 3.  Состояние связи: event_type последнего – состояние связи

•  Может поступить timestamp из прошлого (!) •  События могут дублироваться (!) •  Для обновления графа нужно хранить последнее (по timestamp) обновление и удалённые связи

Page 15: Cоциальный граф "Одноклассников" в myTarget

Дружба: различные представления графа

•  Обновляемое представление: •  живые связи: 360 гигабайт •  удалённые связи: 173 гигабайта •  всего: 533 гигабайта

•  Необновляемое представление: •  Список рёбер: 200 гигабайт •  Списки смежных вершин: 90 гигабайт

Page 16: Cоциальный граф "Одноклассников" в myTarget

Игры: общая информация

•  Исходные данные – лог посещения страниц с игрой пользователями:

(ok_id, game, timestamp) •  Лог за два месяца: 1.5 терабайта •  Если агрегировать: 20 гигабайт

Page 17: Cоциальный граф "Одноклассников" в myTarget

Ключевые вопросы

•  Как хранить граф? •  Как обновлять граф? •  Как хранить игры пользователей? •  Как обновлять игры пользователей? •  Как выбирать игры друзей? •  Как уложиться в таймауты? •  Как выдержать необходимую нагрузку?

Page 18: Cоциальный граф "Одноклассников" в myTarget

Ключевые вопросы

•  Группа вопросов №1 •  Как хранить граф? •  Как обновлять граф? •  Как хранить игры пользователей? •  Как обновлять игры пользователей?

•  Группа вопросов №2 •  Как выбирать игры друзей? •  Как уложиться в таймауты? •  Как выдержать необходимую нагрузку?

Page 19: Cоциальный граф "Одноклассников" в myTarget

Ключевые вопросы

•  Хранение (вычисления) •  Как хранить граф? •  Как обновлять граф? •  Как хранить игры пользователей? •  Как обновлять игры пользователей?

•  Доставка •  Как выбирать игры друзей? •  Как уложиться в таймауты? •  Как выдержать необходимую нагрузку?

Page 20: Cоциальный граф "Одноклассников" в myTarget

Возможные решения

•  Графовые базы данных •  Реляционные СУБД

•  MySQL: join + group by •  PostgreSQL: CTE / WITH … RECURSIVE BY

•  NoSQL: Tarantool •  Собственное решение •  HDFS / Hadoop

Page 21: Cоциальный граф "Одноклассников" в myTarget

Графовые базы данных

•  http://www.highload.ru/2014/abstracts/1611.html •  Чудовищно медленный импорт данных •  Поиск соседей вершины – больше секунды. •  Ни у кого в команде нет опыта эксплуатации и использования.

•  Непрогнозируемый результат и время разработки.

•  Условно годится (?) для хранение •  Не годится для доставка

Page 22: Cоциальный граф "Одноклассников" в myTarget

Реляционные СУБД: PostgreSQL

•  http://www.slideshare.net/quipo/rdbms-in-the-social-networks-age

•  Шикарно! Хочу попробовать. •  Нет опыта эксплуатации PostgreSQL L •  Не рискнул ввязываться. •  Расчёт - всего один запрос. •  Идеально для хранение (вычисления) •  Едва ли подойдет для доставка •  Нужно тестировать

Page 23: Cоциальный граф "Одноклассников" в myTarget

Реляционные СУБД: MySQL (хранение)

•  Если коротко: даже не пытайтесь •  >500 миллионов ключей: падение скорости записи примерно в 20-25 раз

•  За две недели так и не смогли выгрузить •  200 миллионов ключей, 65 партиций... •  Больше 20 партиций => дохнет •  Для хранение не годится вообще L

Page 24: Cоциальный граф "Одноклассников" в myTarget

Реляционные СУБД: MySQL (доставка)

MySQL и HandlerSocket на 1/128 части графа •  Все данные в памяти •  6 CPU (+6 HT) – 100% использование •  MySQL 30 krps •  HandlerSocket 120krps •  MySQL: 99/95/90 frac: 100/41/19 мc •  HandlerSocket: 99/95/90 frac: 100/41/19 мc •  Каши не сваришь L •  Для доставка не годится

Page 25: Cоциальный граф "Одноклассников" в myTarget

Собственное решение

•  Начинающие программисты любят долго писать Очень Универсальные Решения, которые используются ровно в одном проекте ровно до тех пор, пока программист не уволится из проекта (а потом Очень Универсальное Решение с облегчением выпилят).

•  У меня профдеформация: писал OLAP, OLTP и NoSQL СУБД.

•  И оценил срок разработки прототипа в 4 человеко-месяца минимум.

Page 26: Cоциальный граф "Одноклассников" в myTarget

HDFS & Hadoop

•  Широко используется в myTarget •  Группа Data Mining делает умопомрачительные штуки

•  http://www.highload.ru/2014/abstracts/1596.html •  Все данные уже там •  Прямой расчёт данных – почти сутки L •  Я смог это обойти (но про это позже) •  Идеально для хранения (вычисления) •  Не годится вообще для доставка

Page 27: Cоциальный граф "Одноклассников" в myTarget

Tarantool

•  Широко используется в myTarget •  Persistent, In Memory, Low Latency •  http://tarantool.org/ •  Бенчмарк: 1 ядро, 100% загрузка •  120 krps •  99/95/90 frac: 6/3/2 мc •  Если пошардить – ещё меньше •  Идеален для доставка •  Хранение - 533 гигабайта RAM?...

Page 28: Cоциальный граф "Одноклассников" в myTarget

Очевидное решение

•  Считаем граф на hadoop (~90 гигабайт) •  Считаем игры на hadoop (~20 гигабайта) •  Заливаем в tarantool 1.  вытаскиваем друзей пользователя:

•  ok_id è [friend_id] 2.  вытаскиваем игры друзей

•  friend_idè [game] 3.  Вытаскиваем имя и фамилию друга

•  friend_idè {first name, surname}

Page 29: Cоциальный граф "Одноклассников" в myTarget

Анализ и оценка

•  У пользователей несколько* сот друзей в среднем

•  Шаг 1: одно хождение в тарантулы •  Шаг 2: несколько* сотен запросов, одно хождение

•  Шаг 3: единицы запросов, одно хождение •  X * 10 KRPS * 100-500 друзей = в лучшем случае 1..5X миллионов RPS (!)

Page 30: Cоциальный граф "Одноклассников" в myTarget

Проблемы

•  3 хождения (3-4 мс) – слишком долго! •  Десятки* миллионов запросов – слишком много!

•  Не хватит сети •  Не хватит CPU •  Нужно искать другой путь L

Page 31: Cоциальный граф "Одноклассников" в myTarget

Менее очевидное решение

•  Считаем граф на hadoop (~90 Гб) •  Считаем игры на hadoop (~20 Гб) •  Считаем на hadoop игры друзей (~ 400 Гб) •  Заливаем в tarantool 1.  вытаскиваем игры друзей пользователя:

•  ok_id è [{game, [friend_id]}] 2.  вытаскиваем имя и фамилию друга

•  friend_id è {first name, surname}

Page 32: Cоциальный граф "Одноклассников" в myTarget

Анализ и оценка

•  Два хождения – жить можно (1-2 мс) •  400 Гб RAM – многовато L •  Сетевой траффик большой (сеть лагала) •  Но уже работало почти как хотелось •  Почему бы не усечь данные?

Page 33: Cоциальный граф "Одноклассников" в myTarget

Усечение данных – попытка 1

•  «Давайте игнорировать дружелюбных (>1000 друзей) пользователей»

•  Проблема: Иван Ургант дружит с >1200 пользователей

•  «Ургант играет в эту игру? Я тоже хочу» •  На самом деле Иван Ургант не играет в игры на Одноклассники (это просто контпример)

•  И всё равно ничего не усекается L

Page 34: Cоциальный граф "Одноклассников" в myTarget

Усечение данных – попытка 2

•  «Давайте хранить лишь для активных пользователей»

•  Пока проверял – нашёл баг у ОК и два у нас •  Недельная аудитория – десятки* миллионов пользователей

•  Их друзья – почти все пользователи «Одноклассников» è нужно обрабатывать полный граф

•  Так тоже не получится L

Page 35: Cоциальный граф "Одноклассников" в myTarget

Усечение данных – попытка 3

•  «Давайте хранить информацию для рекламируемых игр»

•  Всё равно если нет рекламы è нет показов è не нужна информация

•  Количество игр уменьшилось почти в 20 раз •  И ещё один небольшой трюк, про него позже •  Итоговые данные занимают 70 гигабайт •  … •  Un tequila, por favor!

Page 36: Cоциальный граф "Одноклассников" в myTarget

Выводы

•  Хороший фильтр данных экономит немало ресурсов

•  Искать ответ нужно не в программировании, а в предметной области

•  Данный фильтр уменьшил объём данных J •  Ясно как представлять данные для доставка •  Осталось разобраться с вычислениями

Page 37: Cоциальный граф "Одноклассников" в myTarget

Вычисления: эксперименты

•  Полный граф считался почти 20 часов •  После кучи оптимизаций – в районе 12 часов •  Игры сначала 8 часов, потом 1 час •  Игры друзей – почти 16 часов •  Hadoop постоянно умирал •  Вокруг моего стола висело облако мата и проклятий

•  Решение нашлось, но не сразу •  Решение: инкрементальные вычисления

Page 38: Cоциальный граф "Одноклассников" в myTarget

Концепция поколений

•  Как рассчитывать инкрементально граф? •  Давайте каждый цикл расчёта маркировать

«поколением» •  Считаем лишь новые данные •  Результаты – новое поколение •  Разница между поколениями 1..X и X+1 – дельта

•  По дельте обновляем tarantool •  Sounds like a plan!

Page 39: Cоциальный граф "Одноклассников" в myTarget

Данные в tarantool

message WhoPlay.Game { // название игры

optional string game = 1; // число играющих друзей

optional uint32 friends_count = 2;

// ok_id некоторых играющих друзей repeated uint64 friend_id_list = 3;

} message WhoPlay.Data {

// информация по играм repeated Game games = 1;

}

Page 40: Cоциальный граф "Одноклассников" в myTarget

Обновление данных в tarantool

message WhoPlay.Update { // ok_id пользователя

optional uint64 user_id = 1; // список игр, для которых больше нет who play

repeated string deleted = 2; // обновления / добавление информации по играм

repeated Game games = 3; }

Page 41: Cоциальный граф "Одноклассников" в myTarget

Друзья

Расчёт: ok_id => { GENERATION: X, FRIENDS: [friend_id]}

Дельта: ok_id => { ADDED: [friend_id], DELETED: [friend_id],

KEEP: [friend_id]}

Page 42: Cоциальный граф "Одноклассников" в myTarget

Игры

Расчёт: ok_id => { GENERATION: X, GAMES: [game]}

Дельта: ok_id => { ADDED: [game], DELETED: [game],

KEEP: [game]}

Page 43: Cоциальный граф "Одноклассников" в myTarget

Соединение

ok_id => { ADDED: {[friend_id], [game]} DELETED: {[friend_id], [game]}

KEEP: {[friend_id], [game]}}

Page 44: Cоциальный граф "Одноклассников" в myTarget

Инверсия связей

friend_id => { game: {ADDED: [ok_id],

DELETED: [ok_id], KEEP: [ok_id]}

}

•  Последний штрих: из списка играющих в игру друзей случайным образом выбираем пять, остальные выкидываем (для большинства пользователей не выкидывает ничего, но вот отдельных странных порезало основательно)

Page 45: Cоциальный граф "Одноклассников" в myTarget

Результаты: хранение (вычисление)

•  Порядка 600 гигабайт HDFS •  Порядка 8 часов цикл расчёта •  Порядка 2 часов заливка в tarantool •  Пересчитываем раз в сутки •  Высокая волатильность данных: 20% •  Работает стабильно •  4.5 KLOC python

Page 46: Cоциальный граф "Одноклассников" в myTarget

Результаты: доставка

•  <80 GB RAM •  <1 ms response time •  десятки тысяч запросов в секунду

Page 47: Cоциальный граф "Одноклассников" в myTarget

Результаты: бизнес

•  Живёт на двух серверах •  Повышает CTR •  В confluence осталось куча документов от research

•  Получен бесценный опыт •  Зарабатывает деньги •  Этот доклад

Page 48: Cоциальный граф "Одноклассников" в myTarget

Выводы

•  Начинайте с аналитики •  Делайте бенчмарки •  Сверяйтесь с техническими требованиями

•  Сверяйтесь с бизнес-требованиями •  Не пытайтесь найти серебряную пулю •  Не пытайтесь изобретать велосипед

Page 49: Cоциальный граф "Одноклассников" в myTarget

Вопросы?

Личный: [email protected] Рабочий: [email protected] Facebook: http://facebook.com/oleg.i.tsarev Проект: http://mytarget.my.com/