КТО ЗДЕСЬ
• Зовут Андрей, резидент HL ;)
• Делал вебню, игры, поиск
• Знаю много страшных слов
• Сегодня про “скорость” в целом
• Завтра про “поиск” в целом
• Ничего нового, все украдено, explicit lyrics
Про скорость
• Как бенчмаркать
– Как планировать эксперименты
• Как профайлить
• Как планировать емкость
• Везде подразумевается прилагательное
“ПРАВИЛЬНО”
Цели uber alles
• Сравнение двух “систем”
– HW, SW, версии, конфигурации
• Нагрузочное тестирование
• Планирование емкости
• Проверка железа
• Ликвидация ВНЕЗАПНЫХ проблем
• Проверка регрессий, воспроизведение
проблем, и т.д.
Цели => метрики
• Только rps == только bandwidth
– Например, диск под нагрузкой
– Например, кассы в супермаркете
• Только latency == только best-case wait time
– Например, 1 поток, когда надо 16 потоков
• Только loadavg == только queue length
– Например, опять касса в супермаркете
Цели => агрегатные функции
• Только среднее == это вообще о ком??
– avg ( 1 ms x 999 + 10000 ms x 1) = 11 ms
– avg ( 1 ms x 500 + 1000 ms x 500) = 501 ms
– Средняя температура по больнице
• Иногда впрочем годятся min, max
– Планирование емкости
– Планирование катастроф!!!
– NB: только при соблюдении ограничений
Шок! Ежа не сменить на ужа!
• Разные метрики НЕ СВЯЗАНЫ
• Померили rps, например
• 4 ядра, 100 rps == bandwidth
• Интуитивно, 10 ms / req == latency, так?
• Интуитивно, на 8 ядрах 200 rps, так?
Шок! Ежа не сменить на ужа!
• #АВОТХРЕН
• 100 rps => avg ( latency ) = 10 ms, ок
– Увы, среднее не значит ничего
– Min, max, median ( latency ) – какие угодно
• Cores x 2 => rps x ?
– Масштабируемость нелинейна
– Может и навредить! (RAM, disk trashing…)
Цели => план борьбы
• “У нас тормозит запрос, давай его
оптимизить”
• Насколько станет быстрее?
– Даже по малозначащему среднему?
• А ХРЕН ЕГО ЗНАЕТ
– 1 ms x 999 + 10000 ms x 1 => ???
– Вариант, avg ( 2 ms x 999 + 3000 ms x 1 ) = 5 ms
– Вариант, avg ( 0.1 ms x 999 + 10000 ms ) = 10 ms
Цели uber alles
• Представьте себя вебсайтом, например
• Нужно много, bandwidth
• Нужно быстро, latency
• Нужно одновременно, конфликт!
• Цель?
– Типично max { bandwidth | latency<=L }
– Бывает min { latency | bandwidth<=B }
Мерь распределения!
• Вот, например, латентность
• Не особо годится avg ( latency )
• Уже лучше
– Percentile_50 ( latency ) = median
– Percentile_80, _95, _99 ( latency )
– Percentile_100 ( latency ) = max, worst case
– 95%, насколько это плохо?
• Совсем хорошо, график latency / bw( X )
Видь края!
• Помним про ограничения
– Типично max { bandwidth | latency<=L }
– Бывает min { latency | bandwidth<=B }
• global_max ( bw ), но зато latency 30 сек
– Добро пожаловать на шоссе Энтузиастов!!!
• global_min ( latency ), но только при 5 rps
– “Да я в 5 утра за 15 минут в Выхино домчал…”
Помни цель!
• Например, выбрать между системой A, B
– В широком смысле!
• Выбрать софт
– XyzDB или WtfSQL?
• Выбрать железо
– Xeon или Opteron?
• Выбрать настройки
– Конкретные buffer_pool_size, число тредов, итп
Мерь нужное!
• 10000 CREATE TABLE медленнее
=> innodb отстой!
• Avg ( ReportLatency ) улучшилось в 3 раза
=> хорошее изменение!
• 1000 x INSERT стал в 2 раза быстрее
=> новый CPU рулит!
Но есть нюанс…
• 10000 CREATE TABLE медленнее
=> а все остальное?
• Avg ( ReportLatency ) улучшилось в 3 раза
=> жалко, все остальное ухудшилось в 2
• 1000 x INSERT стал в 2 раза быстрее
=> вот только ядер в 4 раза меньше
Сравнивай сравнимое!
• Читаем внимательно
• Sphinx, померили… full scan
• Mamba, померили… “index” lookup
• “Я мастерски соптимизировал запрос с 30
до 20 сек, ну а потом построил индекс”
Сравнивай сравнимое!
• Еще интересные варианты
– Guilty as charged…
• Давайте померим отладочный билд!
• Давайте оставим дефолтные настройки!
• Давайте жахнем один запрос 1000 раз!
• Клади линейку с правильного края!!!
• Исключение, маркетинг!!!
Типичная ситуация раз
• Штатный режим
• В ходе разработки, плановые тесты
• Бывает редко ;)
• Методика – понятная
– Сделали эксперимент (репрезентативный)
– Собрали все подряд счетчики
– Посмотрели, отыскали диод, повторили
Типичная ситуация два
• ААА ВСЕ ПРОПАЛО
• Давление снаружи и изнутри черепа
• Методика – такая же
– Физику не обманешь
– Правда, эксперимент уже в быстром полете
• Offtopic (?), “как обычно” – быстрее
– А вот психику обманешь!
Стандартные тулзы
• Когда в разработке
– обычно – gprof (C/C++), xdebug (php) итп
– хардкор – нанобенчмарки, vtune!!!
• Когда режем по живому
– ps, top, vmstat, iostat, mpstat, netstat, strace, op
rofile…
• Когда идем по приборам
– sar, munin, cacti, …
Нестандартные тулзы
• В приложении
– Встроенные счетчики
– Крайне желательно, последовательные
• Снаружи
– kill –SEGV + gdb!
• В голове
– Знание “мировых констант”
– Арифметика и нюх!!!
Кейс #1, тормоза… без нагрузки
• Sphinx, trunk, очередной апдейт
• Под нагрузкой – все примерно ок
• Без нагрузки – адская загрузка CPU
• В общем – чуть (?) хуже
• strace, gdb
=> pthread_mutex_timedlock + ошибочка!!!
Кейс #2, невидимый диод
• MySQL, prod
• Внезапно, чудовищные тормоза
– всех запросов
– Были миллисекунды, стали минуты (!)
• Ничего не поменялось!
– На работе никого, суббота
Кейс #2, исключаем глупое
• Живое железо (виртуализации нет)
• Внешний SAN
• Проверяем, что все запросы тормозят
– SHOW PROCESSLIST, все так
• Проверяем, что SAN чувствует себя ок
– Клиент проверил, SAN о сбоях не говорит
Кейс #2, смотрим всякое
• SHOW PROCESSLIST, vmstat, iostat
– Запросы висят в commit
– 100% утилизация IO, iowait, но все медленно
– Видимо, CPU профайлить бесполезно
• stacktrace, strace, oprofile
– Ничего подозрительного, см. бесполезно
• sar
– В момент сбоя упали rtps, wtps, вырос iowait
Кейс #2, практически нашли!
• Выяснили, это IO подсистема!
• Непростая, SAN по FC, много POF
– DB сервер
– Сам SAN
– Соединение по FC
– Диск на SAN
• Бенчмарк с другого сервера, все тоже плохо
• И внезапно…
Кейс #2, совсем нашли
• Браузер закешировал статус!!!
• На самом деле, там таки издох диск ;)
• Мораль – никому не верить ;)
– Особенно людям
– Даже своим глазам
Самое интересное – совсем мало ;)
• Как предсказывать масштабируемость
– Предсказываю, наверняка не уложусь по
времени!!!
• Зачем? Планирование емкости, в тч. в полете
• Ключевые слова
– Little’s law
– Amdahl’s law
– Universal Scalability law
– Линейная регрессия, очистка данных
Закон Литтла
• Concurrency = Throughput * Response
• Клиенты = Прибытие * Обработка
• Все это средние за длинный период
• 10 ядер, 0.5 сек с ядра = 5 клиентов
• В среднем!
• Придет больше – будут стоять “клиенты”
• Придет меньше – будут стоять “работники”
Закон Амдала
• 95% работы параллелится, но =>
• 5% работы не параллелится (a = 0.05) =>
• 20 раз максимум, причем недостижимый
– 24 x CPU = 11.1 x
– 48 x CPU = 14.3 x
– 64 x CPU = 15.2 x
• C(N) = N / ( 1 + a*(N-1) )
– C == Capacity
Universal Scalability Law
• ASL (Gene Amdahl 1967)
– C(N) = N / ( 1 + a*(N-1) )
– a = степень contention (непараллелящееся)
• USL (Neil Gunther 1993)
– C(N) = N / ( 1 + a*(N-1) + b*N*(N-1) )
– b = степень coherency (consistency delay)
– Общие данные надо синхронизировать :(
Практические выводы?
• Душить contention, улучшать параллелизм
• Душить coherency, улучшать параллелизм
– App mutex, DB lock, любой другой ресурс
• USL как бы говорит, есть sweet spot
– Максимальная Capacity ( NumThreads / Boxes )
– Значит, его можно измерить
– Значит, его можно смоделировать!
Сводка про бенчмарки
• Помни о целях!
• Не путай числа! rps != bandwidth)
• Мерь нужное! 99% latency != avg rps
• Не мерь среднее!
• Мерь распределения!
• Видь края-ограничения!
• Сравнивай сравнимое!
Сводка про профайлинг
• Пользуй стандартные тулзы
– vmstat, iostat, oprofile, ряд других
– Обмеряем все типичные диоды
– Проблема будет найдена
• Люби арифметику (ну хоть наблюдения)
• Ничего не боимся – см. психология
• Никому не верим – см. практика!!!
Сводка про предсказания
• Линейной масштабируемости – нет
• Сублинейной масштабируемости – нет
• С ростом – может случиться хуже
• Можно померить – а можно предсказать!
• Модель нетяжелая – регрессии рулят