Ускоряем и разгружаем веб-сервер, прозрачно кэшируя на...
DESCRIPTION
Доклад Станислава Николова на HighLoad++ 2014.TRANSCRIPT
O компании UCDN.com• UCDN.com входит в состав холдинга XBT
(Webzilla)
• 4 года успешной работы
• 12 точек присутствия в мире
• сотни Gbps трафика
• более 7 млрд хитов в день
Немного обо мне• технический директор и сооснователь компании
UCDN
• сооснователь большого видео проекта (10ки Gbps в 2007 году)
• опыт работы в хостинговых компаниях
• первый сайт за который мне заплатили сделан в 1997 году
О чем будем говорить• Кэширование - основные принципы
• Какие алгоритмы применимы для файлового кэширования
• Как работает Nginx как reverse proxy и наша модификация
• Результаты тестов и практического использования
• Возможные другие подходы решения той же задачи
• Секретные планы на развитие модуля
• Вопросы ?
Только наш опыт, он не абсолютная истина
Кэширование - что это такое“Кэш или кеш (англ. cache, от фр. cacher — «прятать»; произносится [kæʃ] — «кэш»)
— промежуточный буфер с быстрым доступом, содержащий информацию, которая может быть запрошена с наибольшей вероятностью.
Доступ к данным в кэше осуществляется быстрее, чем выборка исходных данных из более медленной памяти или удаленного источника, однако её объём существенно ограничен по сравнению с хранилищем исходных данных…”
из Википедии
Кэширование - что это такое• Просто буфер + алгоритм записи и выбрасывания из него
• Оно практически везде:
• CPU L1, L2, L3 cache
• HDD buffer
• RAID controller cache
• FS inode cache
• Virtual memory
• Разные алгоритмы и структуры для разных приложений
• Основы одни и те же и не менялись уже 50 лет
Как работают кэши• Принцип локальности
– близость по времени (temporal locality)
• как часто запрашиваются объекты
• Пример: Тумбы на индексной странице сайта запрашиваются чаще, чем картинки внутри
– близость по месту (spacial locality)
• как близко разположнены объекты
• Пример: Блоки на HDD при sequential write и низкой фрагментации
• Реально для файлов более важны
– frequency (как часто запрашиваем)
– recency (как давно был последний запрос)
Основные метрики• cache hit ratio (1 - cache miss)
– как часто удается взять что-то из кэша
• latency
– как быстро находим и начинаем отдавать что-то из кэша
• replacement/eviction strategy
– каким образом заменяем элементы в кэше
• cache write policy
– write back
– write trough
• cache volatility
– какой % кэшей меняется за единицу времени
File requests probability distribution• По-моему переводится как “Распределение вероятностей запроса
файлов”
• Почему важно ?
– надо подобрать правильную структуру данных и алгорим выбрасывания
– от этого зависит hit ratio
• Для популярных файлов обычно
– Парето (топ 20% файлов генерируют 80% хитов)
– Ziph (Ципф)
Пример реального распределения• Ziph distribution
• несколько миллионов хитов
• log координатные оси
• не очень удобно для объяснения
Ziph распределение log/linear
Ziph распределение log/linear• A - мин. размер
кэшей
• B - макс. разумный размер кэшей
• C - размер long tail
Как выглядит хорошо кэшируемый контент
• A - максимально длинное
• B - макс крутое
• C - минимальной длины
А что практически дает график ?• A = min. размер кэша
– если размер < A = volatility
• B = оптимальный размер кэша
– если размер < B немного выше volatility
– если размер > B = ниже volatility, но и hit ratio будет ниже
Цена хорошего hit ratio• Для примера берем Парето распределение
– топ 20% файлов генерируют 80% хитов
• Все файлы в сумме занимают 1000 Gb
• 80% hit ratio = top 20% файлов = 200 Gb
• 95% hit ratio = ….? файлов = ? Gb
– в принципе 1000-2000Gb (в зависимости от наклона zipf р.)
• Т.е. 15% могут увеличить в 10 раз объемы кэшей
Цена хорошего hit ratio
Source: Facebook
Ну и что же кэшируемо ?• Кэшируемо
– достаточно выраженный топ
– сумма топ файлов умещается в кэше
• Не очень кэшируемо
– большой и длинный long tail
Как понять насколько что-то кэшируемо• смотрим логи и парсим
– access логи с агрегацией по кол-ву хитов за длинный промежуток времени
– можно самому написать или попользоватся чем-то готовым
• смотрим application layer
– в зависимости от логики приложения могут быть явные топ файлы
– для веб сайтов тип трафика тоже показателен
• делаем эксперименты и смотрим как меняется hit ratio
Немного об алгоритмах кэширования• Для каждой области применения они разные
• Основные параметры
– frequency
– recency
• Для файлов самые важные алгоритмы это:
– LRU - Least recently used - best recency
– MRU - Most recently used - best frequency
– Динамически балансируемые (ARC,CAR)
• Один из самых популярных - LRU
LRU - пример работы• список с фикс. длиной
• сортированный по самым “свежим” файлам
• при запросе файла A, он перемещается в начало списка
• новый файл R выталкивает самый старый (давно никто не запрашивал) из списка
Что мы сделали• Сервер с SATA дисками и SSD диском(и)
• Веб-сервер, работающий в режиме прокси (у нас в основном такие)
• Nginx proxy cache модуль
• SSD cache модуль, который прозрачно оптимизует proxy cache
– самые популярные файлы копируются прозрачно для веб-сервера на SSD
– стандартный модуль продолжает работать в точности так же как раньше
– их рейтинг постянно вычисляется и не достаточно популярные убираются из SSD
– поддерживаются все invalidation events
– SATA диск в основном пишет и читает только при cache miss на SSD
– т.е. уменьшаем кол-во IOPSов на чтение из SATA
Как работает NGINX proxy cache• (упрощенная схема, структуры немного сложнее)
• принимаем request
• virtual host mapping
• rewrite functions & filters
• proxy cache handler
– ищем в дереве где файл
– смотрим по указателю где он в списке (LRU)
– перемещаем его в начало списка
– fopen() • hook к нашему SSD proxy module
Где файл ?
Популярен ?
LRU
Что делает SSD cache модуль• Hook в fopen() получает все контекстные переменные и filepath
• Так же он знает filepath
• Обновляет подобные структуры (тоже дерево + LRU) в котором сохраняется инфа по файлам
• Проверяет есть ли файл на SSD диске
• Есть на диске ? Меняет filepath на тот, который на SSD
• Нет на диске ? Проверяет должен ли быть ? (по ранжировке LRU + модификации)
• должен: то включает в список на копирование, отдает оригинальный filepath
• нет: собирает инфу по файлу в ранжировке (хит) , отдает оригинальный filepath
Что делает SSD cache модуль (2)• Выбрасывает ненужные файлы периодично, когда:
– заканчивается место в структурах памяти (failsafe механизм)
– популярность файла слишком низкая
• Копирует популярные файлы с SATA на SSD
• Возможен throttling копирования, чтобы не перегружать SATA
• Убирает с SSD диска все файлы, которые proxy cache убрал (cache expiration, purge)
Что мы поменяли в NginxВ файле ngx_http_file_cache.c:
• Проверяем есть ли файл на SSD диске и меняем filepath, когда необходимо:
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r)!
• Когда файл удален , мы удаляем и из SSD диска. То же самое и в случае удаления по Cache headers
void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) !
void ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf) !
static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache)!
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache)
Возможности конфигурации SSD cache модуля
• можно задавать размер LRU списков
• модуль может прозрачно кэшировать файлы не более Х Мб (полезно когда тумбы в перемешку с большими файлами)
• ограничение макс. кол-ва файлов, которые будут закешированы на SSD (полезно, когда нужно держать Х% свободными на SSD)
• минимальное кол-во хитов для попадания на SSD (min_uses)
• алгоритм ранжировки (простейший LRU, но есть еще куча других интересных, которые можно настроить под свои задачи и эффективность возрастет)
Результаты тестов• Тестовый сетап (один из множества)
– 4 Gb SSD limit
– 40 Gb library size on SATA RAID5 6 x 4500 2Тб
– 4 Mb objects
– ziph file distribution
• Методология:
– 32000 запросов
– разное concurrency запросов
– меряем req/s, mean latency, time to execute
Результаты тестов (2)Модуль Кол-во
запросовTime to execute[s]
req/s latency mean[ms]
Concurrency Speedup[%]
SSD 32000 337 94.96 10.53 64
Proxy cache 32000 451 70.95 14.09 64 33.82
SSD 32000 343 93.29 10.72 128
Proxy cache 32000 505 63.37 15.78 128 47.23
SSD 32000 339 94.40 10.59 256
Proxy cache 32000 491 65.17 15.34 256 44.83
Результаты тестов (3)
305$
104.92$
9.53$
388$
82.47$
12.13$
Time$to$execute[s]$ req/s$ latency$mean[ms]$
Concurrency)32)SSD$cache$ proxy$cache$
Результаты тестов (4)
339#
94.40#
10.59#
491#
65.17#15.34#
Time#to#execute[s]# req/s# latency#mean[ms]#
Concurrency)256)SSD#cache# proxy#cache#
Production grade test-ы• паралельно запускаем 2 сервера с/без модуля в роли reverse proxy
• трафик одинаков 50%/50%
• сервера работают 3 дня (от cold cache)
• тип сервера:
– тип 1(6 SSD + 6 SATA) и тип2(12 SATA)
– 128 Gb RAM
– 10 Gb nic
• тест более практический, т.е. “есть ли смысл ставить такое”, а не “сколько теоретически может дать”
Production grade test-ы (2)• Видим, что SSD работают с около 70% ниже load average
• Latency от 20-60% в среднем лучше у SSD прокси
• Отдают от 60 до 200% больше трафика в пики (когда не пошейпены)
• Т.к. мы не контролируем тип распределения, то и результаты не поддаются легкому объяснению (как в случае с синтетикой)
• “Так SSD всегда будут быстрее работать, зачем мудрили ?” (вопрос знакомого, когда показали ему)
• Так как на SSD все не залезет и надо только популярное автоматом, не меняя application layer.
Конечно, это не решает все проблемы• Если контент не кешируемый, то модуль не поможет
• Если топ файлы в разы больше SSD
• Если файлы размером в 4 Тб каждый, то promotion и demotion будут очень медленными
Возможные другие подходы• Ставим на 1 сервер веб-сервер + прокси + прокси
– первое кеширует на SATA
– второе прокси кеширует на SSD
• Block level OS cache (dm device)
Возможные пути развития• Лучше алгоритм выбрасывания
• Plug-in архитектура для cache policy
• Работа только как прокси модуль в самом веб-сервере, без uplink логики
• Native purge
• Open source ?
Спасибо! Вопросы [email protected]