Архитектура Ленты на Одноклассниках
Upcoming SlideShare
Loading in...5
×
 

Архитектура Ленты на Одноклассниках

on

  • 4,623 views

 

Statistics

Views

Total Views
4,623
Views on SlideShare
2,892
Embed Views
1,731

Actions

Likes
1
Downloads
9
Comments
0

8 Embeds 1,731

http://jug.lv 1719
https://twitter.com 3
http://assets.txmblr.com 3
https://www.google.com 2
http://summary 1
http://cloud.feedly.com 1
http://translate.googleusercontent.com 1
https://www.google.lv 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Архитектура Ленты на Одноклассниках Архитектура Ленты на Одноклассниках Presentation Transcript

  • Архитектура Ленты на Одноклассниках Алина Васильева разработчик сервиса Лента Одноклассники alina.vasiljeva@odnoklassniki.ru
  • Одноклассники • Социальный портал • Граф друзей • Аудитория: – 250 млн аккаунтов – 6 млн пользователей онлайн – более 40 млн посетителей в день 1 в среднем 90 друзей 12 групп
  • Лента 2
  • Лента • Один из ключевых сервисов портала • Цели – показ пользователю действий и событий друзей и групп – распространение контента по порталу – стимулирование пользователей создавать контент • Задачи – показ интереснейшего контента максимально большому количеству пользователей – агрегация – группировка – сортировка – выживание в условиях высокой нагрузки 3
  • События • В ленту попадают события более чем 100 разных типов – Фото – Статусы – Дружбы – Классы – Подарки – Игры – Группы – Музыка – Видео – и многое другое... 4 Больше всего добавляется классов к фото По показам лидируют темы из групп
  • Запись и хранение событий • Для достижения цели необходимо записывать и хранить события каждого пользователя • Главная сущность: Feed • Для каждого пользователя нужно хранить List<Feed> 5 class Feed { long createDate; short feedTypeId; Long referenceId; ... }
  • Запись и хранение событий • SQL ? 6 • SELECT, JOIN, COUNT...
  • Нагрузка • В час пик пользователи генерируют 1 миллион событий в 5 минут (>3000 операций записи в секунду) 7 • Запросы ленты конкретного пользователя: >4000 в сек • Запросы общей ленты на главной: >9000 в сек
  • История развития хранилища фидов • SQL решение не рассматривалось изначально – высокая нагрузка – необходима высокая доступность – характер данных, запросов и нагрузки 8
  • История развития хранилища фидов • Oracle Berkeley DB – Key / Value хранилище CP-типа – Key: long feedOwnerId – Value: List<Feed>  byte[] – Хранятся последние N записей (500) 9 • Через ~2 года добавили Voldemort + Tarantool – Key / Value хранилище AP-типа – Хранение данных в памяти – Более высокая производительность – Более высокая доступность – Хранятся последние 30 записей – Использовался одновременно с Berkeley
  • Переход на Cassandra • Причины – Нестабильность Berkeley – Ограничение на объѐм хранимых данных – Упирались в трафик • необходимо пересылать по сети все данные • Преимущества – Высокая доступность, распределѐнность – Масштабирование, восстановление на ходу – Высокая скорость записи – Скорость чтения не зависит от объема – Возможность реализации бизнес-логики 10
  • Cassandra • Хранение данных в Column Family – Row Key – Column Key + Column Value + Timestamp 11
  • Хранение фидов в Cassandra 12
  • Общая картина Feed Proxy - координирующее Java-приложение 13
  • Инфраструктура ленты 14 • Сервера распределены по трѐм дата-центрам Feed Proxy кластер: 21 000 запросов/сек Feed Storage кластер: 120 000 запросов/сек
  • Инфраструктура ленты 15 • Выдерживаем потѐрю целого дата-центра Приложения обновляются путѐм отключения серверов в одном ДЦ Обновление кластера Proxy: 5 минут Обновление кластера Storage: 30 минут
  • Общая лента • Задача – показ ленты событий от всех друзей 16 распространение информации получение информации
  • Общая лента 17
  • Список подписок • При дружбе пользователи добавляются друг к другу в список подписок (ObservedList) • Формируется список друзей, за событиями которых пользователь следит и которые попадают к нему в ленту • Храним список подписок для каждого пользователя 18 class ObservedList { List<ObservedItem> items; ... } class ObservedItem { long feedOwnerId; long lastUserAccessTime; long lastFeedOccurrenceTime; ... }
  • Хранение списка подписок • SQL снова не подходит – 350 добавлений в секунду (18 млн за сутки) – 9000 чтений в секунду – характер данных и запросов • Хранили в Berkeley DB, перешли на Cassandra 19
  • 1. Получаем список подписок из ObservedList 2. По каждой подписке получаем список фидов из Storage 3. Объединяем, сортируем Алгоритм сборки общей ленты [simplified] List<Feed> feeds = new ArrayList<Feed>(); ObservedList observedList = getObservedList(feedFollowerId); for (ObservedItem item: observedList.getItems()){ List<Feed> userFeeds = getFeeds(observedItem.getFeedOwnerId()); feeds.addAll(userFeeds); } Collections.sort(feeds, FEEDS_COMPARATOR); 20 Выполняется на Feed Proxy
  • И опять нагрузка • 9000 запросов получения общей ленты в секунду – даже с учѐтом кэширования на вебе – помним про 90 друзей и 12 групп у пользователей! – 9000 * 102 = 918 000 походов в базу в секунду • Базы данных не в состоянии эффективно обработать такое количество запросов 21 Нужен кеш событий общих лент пользователей
  • Feed Cache • Java-приложение, цель которого получение, хранение и отдача общих лент 22
  • Масштабы Feed Cache • Самое мощное приложение инфраструктуры ленты • 64 сервера, распределѐнные по трѐм дата-центрам • Кол-во запросов: 100 тысяч в секунду (~1500 на сервер) • В кэши входит 100 млн событий в 5 минут • Трафик: 1 Гб/сек – 10 Мб/сек входящего на 1 сервер – 6 Мб/сек исходящего на 1 сервер • Объем хранимых данных: 6 ТБ (в RAM) – ~100 ГБ на 1 сервере – в среднем 100 KБ на пользователя 23
  • Хранение данных в Feed Cache • По ключу идентификатора пользователя хранится список фидов • Длина списка ограничена – 1000 записей, но, бывает, уменьшаем (при повышенной нагрузке) – специальный алгоритм по вытестению данных из кэша – планируем переход на Cassandra 24
  • Хранение данных в Feed Cache • Помимо списка фидов хранятся также дополнительные данные – время последнего логина – время последнего открытия ленты – время последнего обновления данных с Feed Proxy – значение последнего выбранного фильтра • Данные сериализуются и хранятся в Off-Heap памяти • Раз в 12 часов сервер записывает данные на диск (снепшот) • При рестарте приложение стартует со снепшота ~8 минут • При старте без снепшота есть механизмы обеспечивающие плавную загрузку данных 25
  • Кластер Feed Cache 26 • Шардинг – каждый сервер обслуживает 1/64 часть пользователей – партиционирование по id пользователя • У каждого сервера есть «заместитель», на который перенаправляются запросы в случае недоступности • Обновление приложений всего кластера занимает ~1 час (обновление по ¼ серверов)
  • Feed Cache - Отдача данных • Feed Cache запрашивает новые события с Feed Proxy по истечению временного периода (15 минут) – инфраструктура уже выдерживает обновления раз в 1 минуту 27
  • Время последнего события • И всѐ же нагрузка на хранилище фидов получается черезмерно большая • При каждом обновлении на Feed Proxy обходить базы всех друзей неоправданно дорого • ведь новые события могли появиться всего у пары из них, а то вообще ни у кого • Решение - отдельно хранить дату добавления последнего события в ленту пользователя • Отдельная база: Voldemort + Tarantool (key / value) – long feed_owner_id  long last_create_date 28
  • База UpdateInfo • При добавлении нового события обновляется timestamp в базе UpdateInfo • Далее это значение проверяется при сборке событий для общей ленты 29
  • • Перед запросом в базу Feeds проверяется значение UpdateInfo - появились ли новые события Алгоритм сборки общей ленты [improved] 30 public List<Feed> collectRecentFeeds( long feedFollowerId, long lastUpdated){ 1. ПОЛУЧАЕМ СПИСОК ПОДПИСОК (OBSERVED LIST) 2. ДЛЯ КАЖДОЙ ПОДПИСКИ 3. ПРОВЕРЯЕМ UpdateInfo if (hasNewFeeds(item.getId(), lastUpdated)){ 4. ПОЛУЧАЕМ ФИДЫ 5. ДОБАВЛЯЕМ ФИДЫ В ОБЩИЙ СПИСОК } } ... } Хотя в UpdateInfo тоже ходим не каждый раз. Значения кэшируются в ObservedList.
  • Группировка событий • Проблема – повторяющиеся бесполезные события 31
  • Группировка событий • Решение – группировка событий 32 • Исключение событий
  • Группировка событий • Решение – инфраструктура мержеров событий 33 List<Feed> feeds = getFeeds(); for (Merger merger: mergers){ merger.mergeFeeds(feeds); } Длина списка уменьшается на ~25%
  • Приоритеты событий • Проблема – событий много, нужно показать пользователю самое интересное • Решение – подсчѐт весов событий и пересортировка на их основании • Вес подсчитывается при входе события в Feed Cache • Также анализируется состояние кэша – подсчитывется сколько событий каких типов уже присутствует в кэше 34 множество дополнительных коэффициентов и параметров
  • Feed Stats • Отдельное Java-приложение с хранением данных в Cassandra • Сбор статистики о предпочтениях пользователей • Записывает действия, которые пользователь совершает по отношению к своим друзьям – 53 000 записей в секунду • На основании собранной статистики подсчитывает веса друзей • Далее этот вес используется лентой при подсчѐте веса события 35
  • Полная картина 36
  • Real-time доставка событий • Проблема: чтобы увидеть новые события пользователю необходимо обновить страницу • С учѐтом многоуровнего кэширования и ограничений новое событие может прийти в ленту с задержкой • Задача: доставлять события в ленты пользователей моментально и автоматически 37
  • Real-time доставка событий После добавления нового события Feed Storage нотифицирует Feed Cache друзей в онлайне, отсылая им фид, который далее переправляется прямо на Web 38
  • Спасибо! Алина Васильева разработчик сервиса Лента Одноклассники alina.vasiljeva@odnoklassniki.ru odnoklassniki.ru/alina v.ok.ru job@odnoklassniki.ru