Дмитрий Дегтярев, "Хабикаса"
DESCRIPTION
HighLoad++ 2013TRANSCRIPT
Опыт переезда соцсети с Livestreet (PHP/MySQL) на
NodeJS/Redis/LUA
Дмитрий Дегтярев
Чего в докладе нет
Highload
Silver bullet
Авторитет Гуру
План доклада
• Что лечим: Область применения, постановка задачи.
• Тестируем лекарство: Синтетические бенчмарки.
• Механика применения: Советы по использованию.
• Обмен опытом, обсуждение
Область применения: онлайн каталоги
• Интернет-магазины, блоги, аукционы, сайты объявлений, знакомств, соц. сети…
• Основные запросы: чтение списка «товаров» с фасетным поиском, страница «товара»
• Информация часто меняется – счетчики лайков, цены, наличие, дата последнего комментария
• Множество блоков «смотрите также», «аксессуары», «еще на эту тему», «сейчас обсуждают» и т.д.
7dach
Что имеем сейчас: время отдачи страниц
0
1000
2000
3000
4000
5000
6000
Livestreet Livestreet nocache
Magento Magento nocache
Custom PHP
Custom PHP
nocache
SQL запросов
msec
Постановка задачи
• Сокращение времени генерации страницы
• Избавление от кэшей и необходимости их валидации
• Применение удобных для разработки языков
• Упрощение архитектуры, сокращение кол-ва элементов
Предпосылки к изменению: RAM
Источник: http://www.jcmit.com/mem2013.htm
Предпосылки: Junk-информация
Junk информация:
• Посты, лайки, комменты, описания товаров, рекомендации товаров, статистика кликов, чат-сообщения, счетчики нового
• Не требует 100% целостности
Транзакционная информация:
• Цены, платежи, заказы
Медиа информация:
• Картинки, видео, аудио
Предпосылки: умные и быстрые клиенты • Развитие стандартов HTML5, JavaScript: ECMA-262, edition 5
• Развитие клиентских библиотек: AngularJS, EmberJS, … много
• Развитие клиентского железа: память, процессоры
• Развитие поисковиков: Google _escaped_fragment_
Типичный представитель логики в веб-сервере: PHP+MySQL+MemCached
• постоянный маршаллинг данных PHP - MySQL - Memcached
• процессы инициализации фреймворка при каждом вызове
• кэши и механизмы их инвалидации
• нормализованная структура данных и множество операций JOIN таблиц
• обращения к ФС, в том числе со стороны БД
• часто борьба с транзакциями там, где они не нужны
“Обычная” архитектура
СУБД
Кэш
Доступ к данным
Логика Шаблонизатор Браузер
Результаты запросов, объекты
Фрагменты HTML
HTML
Разносим логику
Варианты реализации:
• Redis + LUA
• Postgres + PL/SQL (умеет делать JSON)
• …другие варианты
Кэш Доступ к данным
Логика Шаблонизатор Браузер JSON JSON
Логика Прокси
HandleBars Ember Ember-data NodeJS LUA Redis
Тестируем на данных блога • Топик - id, название, дата, анонс, картинка, пара счетчиков, author_id
• Автор - id, имя, аватар
• 3000 топиков, 1200 авторов
• Получаем JSON со списком всех топиков и списком уникальных авторов
• Embedding = SQL JOIN, дублирование данных
• Sideloading = сокращение объема данных, передача только уникальных объектов
Результаты тестирования
0,00
5,00
10,00
15,00
20,00
25,00
30,00
35,00
PHP MySQL PHP MySQL MemCached
Postgres Redis Lua
Один поток
8 потоков
Postgres: работа с JSON
Redis+ LUA
Выводы
• MySQL + Memcached это очень быстро для простых запросов
• JSON функции в Postgres медленные
• Redis не хватает многопоточной версии
Исходные коды тестов:
https://github.com/Mitek99/dblogic-benchmark
Тестируем выборки с суммированием
0
5
10
15
20
25
PHP + MySQL Redis + Lua
1 поток
8 потоков
* ZUNIONSTORE + Sorted Set = очень медленно
MySQL
Redis + LUA: как устроено
topic1_tags topic2_tags topic3_tags topic4_tags topic5_tags
ZUNIONSTORE sum_tags 5 topic1_tags topics2_tags topic3_tags topic5_tags AGGREGATE SUM
5 3 3 3 2 1 1
sum_tags
ZRANGE sum_tags 0 -1
Выводы
• MySQL и Postgres сами по себе очень быстрые
• Медленными оказываются «движки» с плагинами
• Логику на Redis+Lua писать можно и даже приятно
• Сразу проектировать Master-Master репликацию уровня приложения
• Redis можно и нужно оптимизировать
Хранение, индексы, сортировки и выборки • WHERE FIELD=VALUE
• ORDER BY … LIMIT N
• GROUP BY
Создаем тэг “FIELD=VALUE” и ключ типа SET со множеством ID записей имеющих этот тэг. Используем SINTERSTORE или SUNIONSTORE
Создаем SORTED SET и используем ZINTERSTORE для выборки отсортированных элементов, потом ZRANGE для выбора N первых элементов
Создаем SORTED SET и используем ZINTERSTORE для выборки отсортированных элементов
Возможности библиотеки RNode
• Создание и обновление индексов
• Выборки с ограничениями по тэгам
• Суммирование по тэгам для построения фильтров
• Sideloading связанных объектов
• …Постоянно развивается
• Доступно на GitHub: https://github.com/Mitek99/rnode