Оптимизация LAMP-приложения на примере OpenX: разгоняемся до 1000 запросов в секунду

Содержание

Слайд 2

Кто я?

alexander@chistyakov@dataart.comalexander@chistyakov@dataart.com, alexclear@gmail.com
http://alexclear.livejournal.com
Работаю разработчиком ПО с 1998 года
В настоящее время – разработка

Кто я? alexander@chistyakov@dataart.comalexander@chistyakov@dataart.com, alexclear@gmail.com http://alexclear.livejournal.com Работаю разработчиком ПО с 1998 года В
высоконагруженных веб-проектов, консультации по вопросам связанным с высокими нагрузками

Слайд 3

Почему я?

Нагрузка 500-5000 пользователей в день есть у всех
Нагрузка 100500 запросов в

Почему я? Нагрузка 500-5000 пользователей в день есть у всех Нагрузка 100500
секунду – мало у кого есть, но все читают о ней доклады
Нагрузка 500-1000 запросов в секунду – должна быть интересна слушателям, но неинтересна докладчикам, «гонка за мегагерцы»
Переход от 1rps к 1000rps порождает ряд однотипных классов проблем

Слайд 4

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

OpenX – существующее open source веб- приложение для показа рекламы
Linux, Apache,

Постановка задачи OpenX – существующее open source веб- приложение для показа рекламы
MySQL, PHP
Необходимо выдержать заданные параметры производительности при заданном количестве объектов предметной области

Слайд 5

Предметная область

OpenX: баннеры, кампании, зоны, пользователи
Баннеры – собственно, баннеры
Пользователи – управляют баннерами
Кампании

Предметная область OpenX: баннеры, кампании, зоны, пользователи Баннеры – собственно, баннеры Пользователи
– содержат баннеры, имеют приоритеты
Зоны – группируют баннеры и кампании для расчета весов

Слайд 6

Начало

Одна виртуальная машина в локальной сети
1000 баннеров, 1 зона, 1 кампания
~ 5

Начало Одна виртуальная машина в локальной сети 1000 баннеров, 1 зона, 1
запросов в секунду

Слайд 7

Требования

Заказчик – большая компания, требования расплывчаты
200000 баннеров, 400-700 запросов в секунду

Требования Заказчик – большая компания, требования расплывчаты 200000 баннеров, 400-700 запросов в секунду

Слайд 8

Особенности OpenX

Расчет весов баннеров непосредственно в PHP коде при каждом показе
Продукт уже

Особенности OpenX Расчет весов баннеров непосредственно в PHP коде при каждом показе
оптимизирован, есть рекомендации по настройке под высокую нагрузку
Рекомендации относятся к масштабированию DB уровня
DB уровень не участвует в расчете весов!

Слайд 9

Расчет весов

Несколько циклов в PHP-коде
200000 баннеров – 200000 повторений в циклах
Внутренние объекты

Расчет весов Несколько циклов в PHP-коде 200000 баннеров – 200000 повторений в
PHP кэшируются в подключаемый кэш (memcached)
Максимальный размер объекта для memcached – 1Мб
200000 баннеров – объекты размером несколько мегабайт

Слайд 10

Оптимизация

Декомпозиция объектов до уровня отдельных полей, вынос полей в memcached
Веса рассчитываются один

Оптимизация Декомпозиция объектов до уровня отдельных полей, вынос полей в memcached Веса
раз в 10 минут и кэшируются в DB
Алгоритм сведения любого распределения к нормальному – веса объектов на отрезке [0,1], выбор случайного числа -> удобно построить индекс и сделать SQL-запрос

Слайд 11

Первые проблемы

Много запросов к memcached, он почему-то не работает – переход к

Первые проблемы Много запросов к memcached, он почему-то не работает – переход
хранению данных в APC
Доллго рассчитываются значения весов – необходимо версионирование
Несколько узлов, но APC локален – у каждого узла свой кэш объектов, взаимных блокировок нет

Слайд 12

Тестирование: средства

Siege, JMeter
JMeter: создание разветвеленных сценариев, GUI
Siege: URL не меняется, командная строка
Siege:

Тестирование: средства Siege, JMeter JMeter: создание разветвеленных сценариев, GUI Siege: URL не
до 700 rps на одной машине (Core i7)
JMeter: до 240 rps на Core i7

Слайд 13

Тестирование: результаты

От трех до семи нод, одна DB
Проблемы: ноды перетирают данные в

Тестирование: результаты От трех до семи нод, одна DB Проблемы: ноды перетирают
базе (нет синхронизации) – сделали синхронизацию через memcached
Проблемы: APC через некоторое время перестает работать – стандартный glibc аллокатор сильно фрагментирует память (вспомните браузер FF 2.0)

Слайд 14

Решение проблем

Назад к memcached (slab allocator)
php-memcached работает, php-memcache - нет
Нет под Debian

Решение проблем Назад к memcached (slab allocator) php-memcached работает, php-memcache - нет
Lenny, пришлось сдлать бэкпорт пакета из Sid
Общий кэш, синхронизация через memcached на одной ноде
Один экземпляр memcached на всех

Слайд 15

Новые вводные данные

Заказчик – большая компания, нас тоже много
Требования конкретизируются прямо на

Новые вводные данные Заказчик – большая компания, нас тоже много Требования конкретизируются
ходу
Зон может быть до 100
Limitations – работают при каждом запросе, кэширование всего ряда весов на 10 минут дает ошибочные результаты, так как limitations тоже кэшируются при этом

Слайд 16

Новые проблемы

Если веса нельзя кэшировать, нужно их пересчитывать
Данные кэшируются для зоны, 100

Новые проблемы Если веса нельзя кэшировать, нужно их пересчитывать Данные кэшируются для
зон – 100 независимых пересчетов каждые 10 минут
200000 баннеров – 2000 баннеров в зоне – по 2000 повторений в циклах в коде PHP при каждом запросе (limitations!)
100 зон – 100 наборов таблиц в базе
Что делать?

Слайд 17

Варианты решения

Поменять алгоритм выбора – варианты?
Non-uniform distribution -> uniform distribution – только

Варианты решения Поменять алгоритм выбора – варианты? Non-uniform distribution -> uniform distribution
через отрезок, при этом 100 пересчетов
Хотим один пересчет
Вариант – наименьшее общее кратное весов, один отрезок с весами, выраженными через НОК
200000 баннеров - ~200000 записей в базе
Не выражать через uniform distribution, использовать веса по-другому

Слайд 18

Компромисс

Баннеров в зоне не более 200
Зон по-прежнему может быть 100
Всего три типа

Компромисс Баннеров в зоне не более 200 Зон по-прежнему может быть 100
limitations
200 повторений в циклах PHP – приемлемо
Оставляем алгоритм расчета через uniform distribution

Слайд 19

Изменения в коде

Объекты баннеров до применения limitations хранятся в DB
Limitations транслируются из

Изменения в коде Объекты баннеров до применения limitations хранятся в DB Limitations
срокового представления в реляционное – три связи в структуре кэш-таблиц в DB
Применение limitations к баннерам это просто SQL-запрос

Слайд 20

Пара слов о хостинге

Первый этап – Amazon EC2
Миграция на Rackspace Cloud
Проблемы: средняя

Пара слов о хостинге Первый этап – Amazon EC2 Миграция на Rackspace
нода облачного хостинга недостаточно производительна, а большая – недостаточно велика
Недостаточно производительности для создания тестовой нагрузки, недостаточно IOPS для эффективной работы DB

Слайд 21

Тестирование: средства

Siege не подходит: 100 зон, около 50 параметров для каждого из

Тестирование: средства Siege не подходит: 100 зон, около 50 параметров для каждого
лимитов – нужно менять URL
JMeter: 240 rps на Core i7, в облаке – меньше
Tsung

Слайд 22

Tsung

Tsung: написан на Erlang – распределенность на уровне VM языка
Создавался с учетом

Tsung Tsung: написан на Erlang – распределенность на уровне VM языка Создавался
многонодовых конфигураций
Может генерировать необходимую нам нагрузку
Строит отчеты в виде веб-страниц с графиками

Слайд 23

Архитектура

Представлена
на картинке
Картинку
перерисовывали 7 раз

Архитектура Представлена на картинке Картинку перерисовывали 7 раз

Слайд 24

Распределение нагрузки

nginx, HAProxy
nginx – HTTP/1.0, генерирует кучу соединений, нет встроенного мониторинга состояния
HAProxy

Распределение нагрузки nginx, HAProxy nginx – HTTP/1.0, генерирует кучу соединений, нет встроенного
– HTTP/1.1, мониторинг состояния на web-странице, предназначен именно для балансировки, можно задавать политику балансировки

Слайд 25

Тестирование: проблемы 1

8 web-nod, одна DB, 100 rps
Одна нода memcached не выдерживает

Тестирование: проблемы 1 8 web-nod, одна DB, 100 rps Одна нода memcached
поток запросов
Укрупнение объектов для кэширования в memcached
Распределенный memcached – на уровне библиотеки
Экземпляр memcached на каждой ноде

Слайд 26

Тестирование: проблемы 2

12 web-nod, одна DB, ~250 rps
Большая нагрузка на web-ноды
Из 4-х

Тестирование: проблемы 2 12 web-nod, одна DB, ~250 rps Большая нагрузка на
циклов расчета весов после применения лимитов к множеству баннеров в зоне 2 цикла можно кэшировать
В коде осталось 2 цикла из 4-х

Слайд 27

Тестирование: проблемы 3

Включили maintenance скрипт в cron – перестала справляться DB
Суть проблемы:

Тестирование: проблемы 3 Включили maintenance скрипт в cron – перестала справляться DB
раз в час таблица с raw logs очищается maintenance скриптом – блокировка таблиц на время удаления
Очевидные решения: InnoDB вместо MyISAM, разбиение операции удаления на несколько мелких запросов – не помогают

Слайд 28

Декомпозиция DB, тюнинг выделенной части

Выделение raw logs в отдельную базу на отдельном

Декомпозиция DB, тюнинг выделенной части Выделение raw logs в отдельную базу на
узле
Попытка поменять тип хранилища – MEMORY вместо InnoDB, ничего не дает, блокировки только хуже
Мониторинг, тюнинг MySQL – добавление памяти под InnoDB buffer pool, log buffer

Слайд 29

Варианты решения

MariaDB vs Percona Server – разницы в производительности нет
MySQL vs PostgreSQL
NoSQL

Варианты решения MariaDB vs Percona Server – разницы в производительности нет MySQL
vs MySQL
memcached – нет поддержки списков, Redis – есть поддержка списков, то, что нужно
Проблема: нужно переписывать код
Решение: никуда не мигрировать

Слайд 30

Мониторинг

Zabbix, Cacti
Cacti: mysql-cacti-templates от коллег из Percona
Zabbix: сильно нагружает сервер, data backend

Мониторинг Zabbix, Cacti Cacti: mysql-cacti-templates от коллег из Percona Zabbix: сильно нагружает
не в RRD, а в RDBMS, неоптимальные запросы (и неоптимизируемые)
Zabbix: выше частота опроса, легче смотреть моментальные состояния

Слайд 31

Тюнинг FS

По умолчанию ext3 с data=ordered
Перемонтировали с data=writeback, iowait вместо ~10% стал

Тюнинг FS По умолчанию ext3 с data=ordered Перемонтировали с data=writeback, iowait вместо
~1.5%
Перемонтировали FS на всех DB нодах с data=writeback

Слайд 32

Тестирование: проблемы 4

Теперь не справляются кэш-таблицы
На MySQL скачки I/O
Большое количество uncheckpointed bytes

Тестирование: проблемы 4 Теперь не справляются кэш-таблицы На MySQL скачки I/O Большое
в мониторинге
Решение: вынести кэш-таблицы в отдельную DB
Решение: поменять тип хранилища на MEMORY
TRUNCATE TABLE работает очень быстро

Слайд 33

Тестирование: проблемы 5

12 web-нод, ~300 rps, три ноды DB
Проблема: скачки I/O на

Тестирование: проблемы 5 12 web-нод, ~300 rps, три ноды DB Проблема: скачки
cache DB
Проблема: тест в Tsung бежит 6 часов, после чего падает
Мониторинг: корреляция падений Tsung и скачков I/O на DB

Слайд 34

Шардинг

Мысли о шардинге были с самого начала, но по какому параметру разделять

Шардинг Мысли о шардинге были с самого начала, но по какому параметру
по шардам? И какие данные?
После декомпозиции на три базы ответ стал очевиден: нужно шардить по номеру зоны данные, хранящиеся в кэш-таблицах
Безграничные возможности для шардинга
Проблема: не все зоны получают одинаковую нагрузку

Слайд 35

Тестирование

12 web-нод, 300 rps, три ноды cache DB, одна нода raw logs

Тестирование 12 web-нод, 300 rps, три ноды cache DB, одна нода raw
DB и одна maintenance DB – тест бежит 42 часа, потом падает
~650 rps – тест бежит 6-7 часов
Мониторинг: нет корреляции падений Tsung и событий в системе
Вывод: проблемы Tsung

Слайд 36

Предел

~700 rps – начинаются ошибки на балансере
Мониторинг: нет корреляции с событиями в

Предел ~700 rps – начинаются ошибки на балансере Мониторинг: нет корреляции с
системе
Что падает - непонятно
Но задание уже выполнено – заказчик счастлив при 300 rps и пике в 600 rps в течение нескольких часов

Слайд 37

Отказоустойчивость

SPOF – распределенные узлы memcached
При падении одного узла таймаут на обращении к

Отказоустойчивость SPOF – распределенные узлы memcached При падении одного узла таймаут на
нему – все ложится
Варианты решения: репликация memcached, проксирование memcached
SPOF: узлы DB

Слайд 38

Отказоустойчивость: Moxi

Проксирование запросов к memcached – Moxi
Составная часть проекта Membase
Работает на 127.0.0.1:11211
Знает

Отказоустойчивость: Moxi Проксирование запросов к memcached – Moxi Составная часть проекта Membase
топологию узлов memcached, скрывает ее от пользователя
Может мгновенно исключать упваший узел
Не может перенаправлять запросы к другим узлам в standalone конфигурации

Слайд 39

Отказоустойчивость: Membase

Работает на порту memcached по его протоколу
Два режима работы: с persistence

Отказоустойчивость: Membase Работает на порту memcached по его протоколу Два режима работы:
и как кэш
Web-интерфейс (не конфигурируется через текстовые файлы)
При падении узла запросы автоматически перенаправляются на другие узлы
Данные, бывшие на узле, теряются – приложение должно инициировать пересчет

Слайд 40

Отказоустойчивость: MySQL

Master-slave репликация – не средство обеспечения автоматической отказоустойчивости
Master-master репликация – менее

Отказоустойчивость: MySQL Master-slave репликация – не средство обеспечения автоматической отказоустойчивости Master-master репликация
распространена, делается большим напряжением ума
SLA 99.95% - достаточно, чтобы время восстановления базы после сбоя было постоянным (InnoDB, обойдемся без репликации)
DRBD + Heartbeat + Xen

Слайд 41

Развертывание

Chef, Puppet
Оба написаны на Ruby
Про Puppet есть книга, про Chef нет
Chef более

Развертывание Chef, Puppet Оба написаны на Ruby Про Puppet есть книга, про
ориентирован на развертывание Ruby-проектов
Puppet: вся конфигурация на сервереЮ, клиент получает инструкции и разворачивает ноду
Написаны Puppet-скрипты

Слайд 42

Команда

Участвовало от 5 до 8 человек
Разработка, интеграция, тестирование, документирование, координация
Производительностью занимались выделенные

Команда Участвовало от 5 до 8 человек Разработка, интеграция, тестирование, документирование, координация
разработчики
Начало внедрения через полгода после старта проекта

Слайд 43

Что дальше?

Security assesment
Deployment
Релиз
Задача: распределить ввод-вывод по нескольким нодам параллельно
Задача: обсчитывать большие объемы

Что дальше? Security assesment Deployment Релиз Задача: распределить ввод-вывод по нескольким нодам
для получения аналитических отчетов
Hadoop, MapReduce jobs вместо SQL

Слайд 44

Выводы

Времени всегда очень мало, вариантов может быть очень много
Система не должна быть

Выводы Времени всегда очень мало, вариантов может быть очень много Система не
черным ящиком
Не верьте в магию
Прежде, чем оптимизировать, нужно измерить
Знание высокоуровневых принципов оптимизации не спасает от огромного количества рутины – лучше иметь ответы на вопросы заранее

Слайд 45

Вопросы?


Вопросы?
Имя файла: Оптимизация-LAMP-приложения-на-примере-OpenX:-разгоняемся-до-1000-запросов-в-секунду.pptx
Количество просмотров: 184
Количество скачиваний: 0