Производительность веб-приложений инструменты и алгоритмы Сербул Александр руководитель направления контроля качества интеграции и внедрений 1С-Битрикс AlexSerbul О чем будем говорить 1) 2) 3) 4) Поймем предметную область Что нас вынуждает беспокоиться? Что такое «быстро» и когда «тормозит» Как выжить и не проиграть конкурентам С чего все началось 1) Тим Бернерс-Ли, CERN* 2) С 1989 года – WWW/HTTP/HTML 3) Первый веб-сервер, первое фото в сети *ЦЕРН (CERN) — Европейская организация по ядерным исследованиям, крупнейшая в мире лаборатория физики высоких энергий. Законодатели современной моды 1) 2) 3) 4) Соцсети Видео хостинги Новостные сайты Корпоративные ресурсы, порталы Гонка против законов физики 1) 2) 3) 4) Гиганты … Часто в «облаках» … Теорема CAP и NoSQL CDN Гиганты - изнутри Архитектура Битрикс24 Static CDN js, css Elastic Load Balancing Web 1 Web 2 local cache local cache mysqld mysqld CloudWatch + AutoScaling … images (clients) Static images (clients) Dynamic Dynamic CDN js, css Elastic Load Balancing Web N Web 1 Web 2 local cache local cache local cache mysqld mysqld mysqld control cache: memcached mysqld mysqld mysqld control cache: memcached mysqld control cache: memcached S3 CloudWatch + AutoScaling … Web N local cache master-master replication mysqld mysqld master-master replication mysqld mysqld mysqld master-master replication control cache: memcached mysqld mysqld mysqld control cache: memcached mysqld management, monitoring, backup control cache: memcached Как выжить, как победить? Рва Как победить (или хотя бы выжить)? 1) Понимать, что нужно Клиенту, «вжиться в него» 2) Понять принципы создания высоконагруженных, масштабируемых приложений 3) Научиться логировать метрики 4) Научиться анализировать их (самое сложное) 5) Запустить процесс с обратной связью 6) Свести анализ к маленькому набору индикаторов к ОДНОЙ ЗЕЛЕНОЙ ЛАМПОЧКЕ Что видит Клиент Начнем с «конца». Веб-сервер, кластер, NoSQL, кэши 1) 2) 3) 4) 5) 6) 7) 8) Смотрим на систему глазами Клиента Что такое – «тормозит»?? Производительность JS Раздача статики с разных доменов, точек CDN Latency, TCP/IP SSL SPDY? Так бывает часто в client-side Список известных «безобразий» client-side Много людей… делают сайт А следит… один. Иногда это Клиент А сроки спускают сверху иногда… Неоптимальные ресурсы: картинки, стили Куча файлов Google PageSpeed Не профилируют Профилируют, но т.к. тестов нет – ломают быстро 9) Алгоритмы – данных стало больше и … все легло (нанимайте опытных бойцов) 1) 2) 3) 4) 5) 6) 7) 8) Как мерить client-side производительность Локальное тестирование – далеко не все. Клиенты – далеко. 1) 2) 3) 4) Cобираем js-meтрики Отправляем на сервер в Pinba Storage Пишем тесты nagios Рисуем в munin pinba_timer_add( array( 'jstimer'=>'responseEnd-responseStart', 'jshost'=>$jshost, 'jsip'=>$_SERVER["REMOTE_ADDR"], 'jsua'=>$_SERVER["HTTP_USER_AGENT"], ), (intval($_REQUEST["responseEnd"]) - intval($_REQUEST["responseStart"]))/1000 ); pinba_hostname_set( strval(substr($_REQUEST["host"],0,128)) ); pinba_script_name_set( strval(substr($script,0,128)) ); pinba_request_time_set($timef); Как мерить client-side производительность Сбор client-side метрик pinba_timer_add( array( 'jstimer'=>'responseEnd-responseStart', 'jshost'=>$jshost, 'jsip'=>$_SERVER["REMOTE_ADDR"], 'jsua'=>$_SERVER["HTTP_USER_AGENT"], ), (intval($_REQUEST["responseEnd"]) intval($_REQUEST["responseStart"]))/1000 ); pinba_hostname_set( strval(substr($_REQUEST["host"],0,128)) ); pinba_script_name_set( strval(substr($script,0,128)) ); pinba_request_time_set($timef); Как мерить client-side производительность Анализ client-side метрик Рендер у Клиентов: select avg(round(timer_value/req_count,3)) from bx24_cps_js_performance_host where tag2_value='domContentLoadedEventStartresponseStart'; Рендер в браузерах: select substring(tag2_value,1,100) as ua, avg(round(timer_value/req_count,3)) as avg_time,count(*) from bx24_cps_js_performance_jstimer_ua where tag1_value='domContentLoadedEventStart-responseStart' group by ua order by count(*) desc limit 10; DNS-скорость: select tag2_value, avg(round(timer_value/req_count,3)) as avg_ip_time, count(*) from bx24_cps_js_performance_jstimer_ip where tag1_value='domainLookupEnd-domainLookupStart' group by tag2_value order by count(*) desc limit 20; Топ коннектов: mysql> select tag2_value, avg(round(timer_value/req_count,3)) as avg_ip_time from bx24_cps_js_performance_jstimer_ip where tag1_value='connectEnd-connectStart' group by tag2_value order by avg_ip_time desc limit 20; +-----------------+-----------+ | 176.60.226.9 | 7.6150000 | | 119.32.156.237 | 3.9420000 | | 79.133.133.97 | 3.2835000 | | 78.138.133.2 | 2.4352500 | | 195.38.55.178 | 1.9980000 | Как мерить client-side производительность 1) 2) 3) 4) 5) Аналогично можно мерить отдачу из CDN глазами Клиента «Распределенное» тестирование – очень полезно Можно фиксировать каждый N хит Ставьте тесты на пороги и рисуйте графики Клиент ждал больше секунды по причине тормозов веб-проекта – плохо, заметно! Как мерить client-side производительность Научитесь БЫСТРО локализовывать источник ВНЕШНИХ проблем 1) 2) 3) 4) Проблемы провайдера Временные «тормоза» (congestion) сети Тормозит браузер клиента (играет в WOT в соседнем окне) Тормозит ТОЧНО не ваш веб-проект Скорость локализации – минуты. Автотесты – nagios/zabbix. Все пока понятно? Идем дальше. «Тормоза» на server-side ТОЧНО ясно, что замедление – на server-side 1) Медленная отдача статики 2) Медленная генерация дин. контента Разбираемся со статикой – обычно это проще: - сервер не «висел»? (логи) - бэкап никто не запускал? - канал не забили? (логи, графики) - память/диски – объем и нагрузка (iostat) - на storage нет еще 50 проектов? - может убрать в CDN? «Тормоза» на server-side - статика Классика: - вынести статику на отдельный домен (|| в браузере) - на отдельный сервер(ы) (быстрее отдача) - в CDN Сервер статики Rev. proxy server (Nginx) Стат. файлы Сервер приложений Сервер баз данных Appl. server (PHP-FPM) RDBMS(MySQL) «Тормоза» на server-side - статика Подводные камни… 1) Статика «проникает» на apache/php-fpm 2) Забиваются тяжелые воркеры 3) Все висит Пишем тест, локализуем: apache /server-status, apachetop Со статикой - разобрались 1) 2) 3) 4) 5) Статика отдается максимально быстро Подкрутили буферы nginx Поставили быстрые диски Убрали все в CDN Создали тесты – покраснеют если «статика» сломается Осталось самое сложное и интересное. «Тормоза» на server-side - Приложение 1) Балансировщики: DNS HAProxy AWS ELB Nginx… 200 ОК 500 Internal Server Error 502 Bad Gateway 503 Service Unavailable 504 Gateway Timeout «Тормоза» на server-side - Приложение Разберитесь в ошибках от upstream! 1) Ошибки приложения – лог 2) Очередь забилась и чем: nginx – apache/php-fpm 3) Служебная страничка – не шокируйте клиентов «Тормоза» на server-side - Приложение Типовая структура веб-приложения: 1) 2) 3) 4) 5) Авторизовать клиента Отдать страницу(ы) из кэша или … Сделать выборку из БД Обработать данные Сформировать верстку и отдать клиенту Еще есть: XSLT, nginx SSI, js/ajax «фигачит» в БД напрямую… Страницы быстрые – главная, детальная Страницы «медленные» – выборки с фильтрами, поиск по параметрам Алгоритмы и V-данных: постраничка, шардинг. «Тормоза» на server-side – Кэш 1) Кэш – это «наркотик» 2) Главное – вовремя соскочить Кэш: - Файлы - БД - Memcached (кластер) Гранулированность, граф зависимостей MySQL query cache – «to be or not to be»? ;-) Выход «есть» – денормализация, NoSQL, async-очереди, «удобные» сценарии, шардинг «Тормоза» на server-side – БД 1) ACID – ближе к ЛСД 2) Что у вас за приложение? CAP «скушает»? MySQL Replication (+semisync) MySQL – «master-master» A/P Galera/Percona XtraDB Cluster/MariaDB Galera Cluster «Тормоза» на server-side – PHP На примере PHP 1) 2) 3) 4) pinba таймеры php-fpm slow log gdb, strace Анализ логов приложения, распределения «Тормоза» на server-side – PHP gdb –p 123456 (gdb) source /src/php-5.3.19/.gdbinit (gdb) dump_bt executor_globals.current_execute_data [0x0252d628] stemming() /var/www/html/bitrix/modules/search/tools/stemming.php:231 [0x0252bc78] stemming() /var/www/html/bitrix/modules/search/classes/mysql/search.php:1090 [0x02525ec8] StemIndex() /var/www/html/bitrix/modules/search/classes/general/search.php:1332 [0x025223f8] Index() /var/www/html/bitrix/modules/iblock/classes/general/iblockelement.php:4857 [0x0251b670] UpdateSearch() /var/www/html/bitrix/modules/iblock/classes/general/iblockelement.php:3295 [0x02519c40] Add() /var/www/html/bitrix/modules/crm/classes/general/crm_webdav_helper.php:486 [0x02514010] SaveEmailAttachment() /var/www/html/bitrix/modules/crm/classes/general/crm_email.php:867 [0x065c2030] EmailMessageAdd() [0x0250fcc8] call_user_func_array() /var/www/html/bitrix/modules/mail/classes/general/mail.php:2477 … «Тормоза» на server-side – PHP XHProf (github.com/facebook/xhprof) Почти не создает нагрузку на бою Можно быстро найти корень проблемы Полезно автоматически сохранять трейсы долгих страниц … и анализировать их с разработчиками Итоги 1) Алгоритмически страницы НЕ ДОЛЖНЫ тормозить 2) Сброс кэша не должен приводить к коллапсу – денормализация 3) Исследуйте «крайние» случаи 4) А также, мониторьте среднегодовую температуру (+7) 5) Все автоматизируйте и быстро, БЫСТРО, тестами определяйте текущее состояние веб-системы 6) Принцип ОДНОЙ зеленой лампочки! 7) Только системный подход, обратная связь Всем удачи! Производительность – это просто! Спасибо за внимание! Вопросы? Александр Сербул [email protected] AlexSerbul