Сергей Чистович "Подходы к кешированию на UGC-сервисе"
Я.Субботник в Санкт-Петербурге
О докладе:
Данные на UGC-сервисах очень быстро меняются, и у каждого пользователя они свои. Выборка этих данных – дорогостоящая операция, поскольку может определяться множеством параметров и сложными условиями. Что и как мы можем кешировать в этой непростой ситуации?
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Сергей Чистович "Подходы к кешированию на UGC-сервисе"
1. Подходы
к
кешированию
в
UGC-‐сервисе
Сергей
Чистович
Руководитель
группы
сервисов
общения
Я.Субботник,
Санкт-‐Петербург,
3
декабря
2011
года
2. Какую
проблему
решаем?
— Повышение
надёжности
и
производительности
— уменьшение
нагрузки
на
базу
данных
для
определённого
типа
сервисов
2
3. Что
за
сервис?
Социальная
сеть,
форум,
блогохостинг:
— Много
пользователей
— Много
статей
— Много
настроек
— Уведомления,
сообщения,
ограничения
доступа
и
т.д.
например,
Я.ру
3
4. В
каком
смысле
кеширование?
Кеширование
–
это
набор
средств
и
приёмов
для
повышения
надёжности
и/или
производительности
системы
за
счёт
уменьшения
потребности
в
формировании
и/или
передачи
данных.
4
5. Что
насчёт
архитектуры?
Типичный
веб-‐сервис:
— Снаружи
пользователи
— Перед
ними
веб-‐сервер
— За
ним
бэкэнд
— А
за
ним
база
данных
(MySQL,
да?)
5
6. Где
может
тормозить?
— Получить
данные
из
БД
— Сформировать
html/json/whatever
— Передать
по
сети
— Отобразить
в
браузере
6
8. Есть
проблема?
Есть
решение!
— Тормозит
форматирование?
Поставь
больше
бэкэндов!
— Работает
всегда
— Просто
в
реализации
— Тормозят
запросы?
Шардируй
базу!
— Работает
отчасти
— Требует
программирования
Будем
фокусироваться
на
проблемах
с
БД.
8
9. Коллективное
бессознательное
Рекомендации
по
кешированию
из
интернетов:
— Закешируйте
самые
популярные
блоки
— В
query
cache
БД
или
в
memcache
— Прямо
готовым
html
не
работают
(в
нашем
случае)
9
10. Кто
виноват?
— У
нас
нет
«популярных»
блоков
— У
каждого
пользователя
свой
взгляд
на
сервис
— Ограничения
доступа
— Настройки
— Уведомления
и
счётчики
— Френдлента
— Активных
данных
гораздо
больше
10
11. Что
делать?
База
не
справляется
со
сложными
запросами?
— Оптимизируй
их!
— Настрой
её!
— Прокачай
её!
— Не
помогло?
Слишком
много
данных?
— Включи
голову!
11
12. Корни
проблемы
— Данные
меняются
очень
быстро
— Кеш
инвалидируется,
не
успев
сработать
— Слишком
много
параметров
— Засорение
кеша,
низкий
hit
rate
но
мы
всё-‐таки
попробуем.
12
13. Где
можно
кешировать?
— В
приложении
— В
базе
— Во
внешнем
кеше
(и
в
чём
разница?)
13
14. Пример:
глобальные
константы
— Можно
кешировать
в
приложении
— Экономия
на
запросах
или
— Экономия
на
сложности
запросов
14
15. Пример:
счётчики
Счётчики
уведомлений,
друзей
и
т.д.
SELECT COUNT(*) FROM messages WHERE uid=12345;
При
большом
объёме
данных
начинает
тормозить.
15
16. Счётчики
–
в
кеш
— Очень
компактные
данные
— Ключ
–
только
один
uid
— Изменяются
не
очень
часто
Положим
результат
запроса
в
кеш?
работает
до
какого-‐то
предела.
16
17. Счётчики
-‐
инкрементальные
— Изменяем
значение
в
ответ
на
действия
—
триггерами/процедурами
в
БД
—
или
просто
в
коде
— Храним
в
БД
(персистентность)
— Нужно
иногда
пересчитывать
17
18. Пример:
френдлента
— Тоже
может
быть
инкрементальной
— Но
очень
много
данных
— И
очень
много
обновлений
18
19. А
если
более
мощный
ключ?
— Количество
общих
друзей
(UID1,
UID2)
— Информация
о
записи
(FEED,
ITEM,
UID)
— Блоки
в
анкете
(UID1,
CATEGORY,
UID2)
19
20. Это
ни
в
какой
кеш
не
лезет!
— Хранить
только
для
избранных
—
предсказывать
востребованность
ключа
— Уменьшать
кардинальность
ключа
20
21. Пример:
информация
о
посте
В
лоб:
return getMessage(FEED, ITEM, VIEWER)
Мощность
пространства
ключей
–
N2,
и
к
тому
же
объём
данных
большой.
Фактически
зависит
не
от
VIEWER,
а
от
relation(FEED, VIEWER).
21
22. Пример:
информация
о
посте
По
уму:
rel = relation(FEED, VIEWER);
return getMessage(FEED, ITEM, rel);
Мощность
пространства
ключей
–
N
*
C
Вдобавок
rel
можно
повторно
использовать
в
пределах
одного
вызова
или
даже
закешировать.
22
23. Пример:
блоки
в
анкете
В
лоб:
return getCategories(FEED, UID, category_list)
(нам
нужны
некоторые
блоки,
с
учётом
доступов)
Сложность:
N
*
N
*
2c
23
24. Пример:
блоки
в
анкете
По
уму:
rel = relation(FEED, VIEWER)
return [c for c in getCategories(FEED, rel)
if c.name in category_list)]
Сложность:
N,
повторно
используем
rel
из
предыдущего
примера.
24
25. СУБД
vs
кеш
СУБД
Кеш
— Не
требует
инвалидации
— Гибкая
схема
— Есть
репликация
— Гибкое
управление
ключами
— Гарантирует
наличие
данных
— Самоочищается
— Джойны
и
сложные
— Глупый
–
значит,
запросы
быстрый!
25
26. Инвалидация
кеша
— Всегда
явная,
по
событию
— Протухание
по
времени
–
только
для
очистки
кеша
— Не
замусоривать
невостребованными
ключами
26