2.16

Смотреть на английском

2.16 Инженерия производительности

Обзор и мотивация

Инженерия производительности это ремесло намеренного достижения достаточной скорости кода с опорой на измерение, а не инстинкт. Эта глава работает на уровне кода и компонентов: функции, циклы, структуры данных, запросы, выделения памяти и то, как один сервис тратит своё время. Это спутник главы 3.5, рассматривающей производительность на уровне системы (горизонтальное масштабирование, балансировка нагрузки, мощности и устойчивость). Когда система медленна, глава 3.5 спрашивает, сколько машин вам нужно; эта глава спрашивает, почему одна машина вообще делает так много работы. Обычно нужны обе, а на уровне кода прячется удивительно большая доля стоимости и задержки.

Для больших команд эта дисциплина важна, потому что производительность деградирует тихо. Ни один коммит не замедляет сервис, но тысяча мелких, каждый добавляющий вызов базы данных или неограниченный цикл, замедлит. Без общего метода измерения, бюджетирования и контроля производительности вы обнаружите гниение только когда клиент пожалуется или запуск расплавится. Метод превращает производительность из героического тушения пожара в рутинное свойство, которое вы защищаете.

Для корпораций производительность это деньги: более быстрый код означает меньше машин, меньшие счета за облако и возможность выполнять соглашение об уровне обслуживания (SLA) по задержке без избыточного резервирования. Для государства производительность это доступ: страница, загружающаяся на старом телефоне по слабому мобильному соединению, это разница между гражданином, завершившим заявление на пособие, и тем, кто сдался. Государственным системам также нужны воспроизводимые свидетельства бенчмарков, потому что закупки и надзорные органы попросят вас доказать числа, а не просто утверждать.

Ключевые принципы

  • Измеряйте, прежде чем оптимизировать. Узкое место почти никогда не там, где вы думаете. Профилируйте, затем действуйте.
  • Избегайте преждевременной оптимизации. Предупреждение Дональда Кнута остаётся в силе: оптимизация кода, который не важен, стоит ясности и ничего не покупает.
  • Определяйте «достаточно быстро» как число. Бюджет производительности с целью и процентилем превращает мнение в «прошло» или «не прошло».
  • Средние лгут; процентили говорят правду. Хвост (p99) это то, что чувствуют пользователи, а не среднее.
  • Алгоритмические выигрыши побеждают микронастройку. Лучший класс сложности обгонит любое количество хитрости с константными множителями.
  • Задержка и пропускная способность разные цели. Улучшение одной может ухудшить другую; знайте, какую покупаете.
  • Делайте бенчмарки честно или не делайте вовсе. Прогрев, дисперсия и репрезентативная нагрузка отделяют реальные числа от вымысла.
  • Контролируйте производительность в CI, наблюдайте в эксплуатации. Регрессии, пойманные до слияния, дёшевы; пойманные пользователями дороги.

Рекомендации

Сначала измеряйте и профилируйте, прежде чем тронуть строку

Старейшее правило в этой области самое игнорируемое: найдите узкое место, прежде чем оптимизировать. Обратитесь к профилировщику, инструменту, выборочно или с инструментацией наблюдающему работающую программу и показывающему, где она тратит время и память. Профилируйте ЦП (какие функции сжигают циклы), память и выделения (что выделяется и как часто, поскольку «текучка» выделений вызывает паузы сборки мусора) и ввод-вывод (время ожидания диска, сети или базы данных). Огненный график (flame graph), многоярусная визуализация, где каждый прямоугольник функция, а его ширина затраченное время, делает доминирующую стоимость очевидной с первого взгляда: ищите самые широкие прямоугольники, а не самые глубокие стеки. Оптимизируйте самую большую стоимость первой, снова измеряйте и остановитесь, когда достигнете бюджета. Это связано с практиками наблюдаемости главы 9.2, потому что профиль из эксплуатации побеждает любую догадку, сделанную на ноутбуке.

Остерегайтесь и обратной ошибки. Полная фраза Кнута гласит, что преждевременная оптимизация корень многих зол, и он имел в виду малые неэффективности, соблазняющие пожертвовать читаемым кодом ради воображаемой скорости. Пишите сначала ясную версию, измеряйте и оптимизируйте только код, которого обвиняет профилировщик.

Определите, что значит «достаточно быстро», бюджетами производительности

Скорость не добродетель в абстракции; это цель, которую вы либо достигаете, либо нет. Установите бюджет производительности: конкретный предел вроде «p99 задержки оформления заказа менее 300 мс» или «эта конечная точка выделяет менее 1 МБ на запрос». Привяжите его к тому, что чувствуют пользователи или бизнес, и выражайте как процентиль, а не среднее, потому что среднее скрывает медленный хвост, где живут реальные пользователи. Если 1% запросов занимает 5 секунд, ваше среднее может выглядеть нормально, пока значимая доля клиентов страдает. Бюджеты дают команде общее неоспоримое определение готовности и черту, которую регрессия видимо пересекает.

Обращайтесь к алгоритмической эффективности раньше микрооптимизации

Самые крупные и дешёвые выигрыши приходят от алгоритмической эффективности, то есть от того, как работа растёт с ростом входных данных, описываемой нотацией O-большое (способ классифицировать скорость роста, так что сортировка O(n log n) масштабируется гораздо лучше сортировки O(n в квадрате)). Вложенный цикл, невидимый на десяти элементах, становится катастрофой на десяти тысячах. Прежде чем вручную настраивать горячую функцию, спросите, не делает ли она принципиально слишком много работы: случайный запрос N+1, линейный просмотр, который должен быть поиском по хешу, или повторяющаяся работа, которую можно запомнить. Это связано с алгоритмическими основами в главе 2.13. Никакая настройка констант не спасёт неверный класс сложности.

Различайте задержку и пропускную способность и уважайте хвост

Задержка это сколько длится одна операция; пропускная способность это сколько операций завершается за единицу времени. Это не одна цель, и оптимизация одной может навредить другой. Пакетирование улучшает пропускную способность, но добавляет задержку первому элементу пакета; добавление параллельных исполнителей поднимает пропускную способность, но может ухудшить хвостовую задержку из-за состязания. Решите, что именно нужно вашим пользователям. И всегда следите за хвостом: задержкой p95 и p99, самыми медленными 5% и 1% запросов, потому что в масштабе пользователь делает много запросов и часто попадает в хвост. Сообщайте процентили, оповещайте по ним и закладывайте под них бюджет.

Знайте пределы параллелизма

Когда вы распараллеливаете, помните закон Амдала: ускорение от добавления процессоров ограничено долей работы, которая должна выполняться последовательно. Если 10% задачи по сути последовательны, никакое число ядер не даст ускорения более чем в 10 раз. Конкурентность (структурирование работы так, чтобы задачи могли продвигаться независимо) и параллелизм (фактическое их выполнение одновременно) добавляют реальную сложность, от состояний гонки до накладных расходов координации. Измерьте последовательную долю, прежде чем предполагать, что больше потоков вас спасёт, и честно признайте, что простейшая корректная версия часто достаточно быстра.

Используйте кэширование и локальность данных и уважайте их стоимость

Кэш, быстрое хранилище недавно или дорого вычисленных результатов, самый мощный инструмент производительности, которым вы располагаете, и самый опасный. Шутка Фила Карлтона, что две трудные задачи в информатике это инвалидация кэша и именование вещей, предупреждение: устаревший кэш выдаёт неверные ответы, а логика инвалидации место, где плодятся тонкие ошибки. Кэшируйте намеренно, задавайте сроки действия и знайте свою историю корректности, прежде чем оптимизировать долю попаданий. На самом низком уровне локальность обращений, хранение используемых вместе данных близко друг к другу в памяти, использует иерархию кэшей ЦП и может ускорить код в несколько раз без алгоритмических изменений, превращая промахи кэша в попадания. Непрерывные массивы побеждают структуры с погоней за указателями по этой причине. Это пересекается с выбором раскладки данных в главе 3.4.

Делайте бенчмарки честно и не доверяйте микробенчмаркам

Бенчмарк, который лжёт, хуже его отсутствия, потому что даёт ложную уверенность. Прогревайте перед измерением, чтобы замерять установившееся поведение, а не однократный запуск и компиляцию «на лету». Запускайте много итераций и сообщайте дисперсию, а не одно счастливое число. Используйте репрезентативную нагрузку с реалистичными размерами и распределениями данных, потому что микробенчмарк на игрушечном вводе часто измеряет способность компилятора удалить ваш тест, а не реальную скорость кода. Остерегайтесь классических ловушек: значение, которое оптимизатор доказывает неиспользуемым и убирает, цикл, который среда выполнения выносит, или кэш, тёплый в бенчмарке и холодный в эксплуатации. В сомнении измеряйте весь путь, а не изолированную функцию.

Контролируйте производительность в CI и наблюдайте её в эксплуатации

Сделайте производительность свойством, которое защищает конвейер. Добавьте тесты производительности в стратегию главы 2.4 с регрессионными шлюзами, валящими сборку, когда ключевой бенчмарк или бюджет ухудшается сверх порога. Это ловит медленное ползучее ухудшение до слияния. Затем замкните петлю в эксплуатации телеметрией главы 9.2: отслеживайте реальные процентили задержки, скорость выделений и медленные запросы относительно ваших бюджетов, потому что эксплуатационный трафик находит случаи, которые ваши бенчмарки никогда не воображали.

Компромиссы: плюсы и минусы

ПодходПлюсыМинусы
Оптимизировать сейчас по интуицииОщущается продуктивно; иногда удачный выигрышОбычно настраивает не тот код; добавляет сложность без выгоды
Сначала измерить, затем оптимизироватьЦелится в реальное узкое место; опирается на свидетельстваТребует инструментов и дисциплины; медленнее начинать
КэшированиеБольшие выигрыши по задержке и пропускной способностиОшибки инвалидации; устаревшие данные; стоимость памяти
Больше параллелизмаВыше пропускная способность на параллельной работеПотолок Амдала; состязание; ошибки конкурентности
МикрооптимизацияВыжимает константные множителиМалый потолок; вредит читаемости; часто шум
Алгоритмическое улучшениеВыигрыши растут с размером вводаТребует анализа; иногда крупное переписывание
Шлюзы производительности в CIОстанавливают регрессии рано и дёшевоНестабильные бенчмарки подрывают доверие; нужна стабильная среда

Основное напряжение это усилия против отдачи, и разрешение в измерении. Работа над производительностью имеет резко убывающую отдачу: первое исправление по профилю может вдвое сократить задержку, десятое сэкономит процент, вдвое усложнив код. Вы разрешаете это, отказываясь оптимизировать без числа в руках и бюджета, который нужно достичь. Измеряйте, чтобы найти исправление, достойное внедрения, и останавливайтесь в момент, когда уложились в бюджет, а не гонитесь за скоростью ради неё самой.

Вопросы для обсуждения с командой

  1. Есть ли у вас письменный бюджет производительности для критических путей и выражен ли он процентилем? У многих команд есть смутное ощущение, что вещи должны быть «быстрыми», но нет числа, по которому кто-то мог бы провалиться, а это значит, что производительность ничья работа, пока не сломается. Бюджет вроде «p99 менее 300 мс» делает цель конкретной, даёт рецензентам, что обеспечивать, и превращает регрессию в видимое событие, а не медленное скольжение. Это важнее всего в больших командах, где задержка прокрадывается через многие руки и ни один автор не видит накопленную стоимость. Принесите текущие данные о задержке и спросите, сообщаете ли вы средние, льстящие вам, или процентили, говорящие правду. Если вы не можете сказать, что значит «достаточно быстро» в виде числа, это первое, что нужно исправить.

  2. Когда вы в последний раз что-то оптимизировали, подсказал ли вам профилировщик, где смотреть, или вы гадали? Известно, что узкое место находится не там, где ожидают опытные инженеры, а время на настройку не того кода потеряно дважды: в самой работе и в добавленной сложности. Культура, профилирующая сначала, тратит усилия там, где они окупаются, и оставляет ясный код в покое. Попросите вашу команду вспомнить три последних исправления производительности и началось ли каждое с измерения или догадки. Подумайте, можете ли вы профилировать в эксплуатации или реалистичной промежуточной среде, потому что профиль с ноутбука может сильно ввести в заблуждение. Ответ показывает, является ли ваша работа над производительностью инженерией или фольклором.

  3. Что сегодня не даёт регрессии производительности дойти до эксплуатации? В растущей команде честный ответ часто «жалоба клиента», то есть пользователи ваш регрессионный тест. Шлюз CI, валящий сборку, когда бенчмарк или бюджет ухудшается, ловит проблему, пока её дёшево исправить и автор ещё помнит изменение. Обсудите, достаточно ли стабильны ваши бенчмарки, чтобы служить шлюзом, потому что нестабильный тест производительности, кричащий «волк!», будет проигнорирован или отключён. Поговорите и о том, что вы наблюдаете в эксплуатации, поскольку некоторые регрессии проявляются только под реальным трафиком и данными. Цель сделать производительность свойством, которое система защищает автоматически, а не тем, что вы заново открываете в инциденте.

  4. Оптимизируете ли вы задержку или пропускную способность на каждом критическом пути и записал ли кто-нибудь этот выбор? Это разные цели, тянущие в противоположные стороны: пакетирование и параллельные исполнители поднимают пропускную способность, но могут добавить задержку отдельным запросам, поэтому команда, оптимизирующая по инстинкту, часто покупает не ту ось и заставляет пользователей ждать ради экономии машинного времени, которого никому не хватало. В большой команде опасность умножается, потому что одна группа настраивает общий сервис на массовую пропускную способность, пока другая зависит от него ради интерактивной задержки, и ни одна не знает цели другой. Принесите реальный шаблон использования каждого пути (интерактивный запрос против фонового пакета), текущую процентильную задержку и необходимую вам устойчивую пропускную способность, затем решите ось явно, а не позволяйте умолчанию возникнуть самому. Для корпоративной или государственной системы под SLA назовите, по какой метрике написано соглашение, потому что оптимизация неизмеряемой оси может нарушить контракт, пока ваши панели выглядят здоровыми.

  5. Откуда вы знаете, что ваши бенчмарки измеряют реальную работу, а не оптимизатор, удаляющий ваш тест? Бенчмарк, который лжёт, хуже его отсутствия, потому что даёт команде ложную уверенность, а регрессия всё равно выходит. Команды регулярно сообщают одно счастливое число с холодного прогона на игрушечном вводе, измеряющее запуск, компиляцию «на лету» и способность компилятора убрать неиспользуемый код, а не поведение, с которым реально сталкиваются пользователи. Принесите пример бенчмарка и допросите его: прогревает ли он, запускает ли много итераций, сообщает ли дисперсию, использует ли репрезентативные размеры и распределения данных и защищён ли результат от удаления мёртвого кода. Противоположное тяготение в том, что честные бенчмарки писать и запускать медленнее, чем быстрые микробенчмарки, поэтому согласуйте, где допустимы дешёвые приближения, а где вы требуете строгости. В государственной или регулируемой среде, где закупки и надзорные органы попросят воспроизвести числа, фиксируйте устройство, нагрузку и среду рядом с результатом, чтобы утверждение можно было проверить, а не просто заявить.

  6. Когда работа над производительностью конкурирует с функциями за одних и тех же инженеров, как вы решаете и у кого власть над бюджетом? Производительность имеет резко убывающую отдачу, поэтому первое исправление по профилю может вдвое сократить задержку, а десятое сэкономит процент за двойную сложность кода, и без правила побеждает самый громкий голос или ближайший срок. Противоположные соображения реальны: неисправленный долг производительности молча нарастает и дорожает для дооснащения, однако погоня за скоростью сверх бюджета обделяет дорожную карту и добавляет сложность, замедляющую будущую работу. Принесите текущее состояние бюджета по каждому критическому пути, оценку стоимости статус-кво в машинах или потерянной конверсии и предельную отдачу следующей оптимизации, чтобы размен делался на свидетельствах, а не под давлением. Для большой корпорации или государственной программы назовите, кто владеет бюджетом производительности и кто может санкционировать трату инженерного времени против него, потому что цель, которую никто не отвечает защищать, тихо размывается.

Взгляд по секторам

Стартап. Скорость поставки побеждает процесс, поэтому сопротивляйтесь переписываниям и грандиозным фреймворкам производительности. Потратьте один день с профилировщиком на пути, на который пользователи действительно жалуются, исправьте самую большую стоимость (часто запрос N+1 или случайный линейный просмотр) и добавьте один лёгкий процентильный бюджет в CI, чтобы выигрыш не мог тихо регрессировать. Берегите глубокую оптимизацию на момент, когда реальное число, а не догадка, скажет, что код слишком медленный.

Малый бизнес. Без специалиста по производительности и при ограниченном бюджете опирайтесь на инструменты, за которые уже платите: профилировщик в вашей среде выполнения, процентили задержки на панели хостинга и встроенный анализатор запросов в вашей базе данных. Установите один-два простых бюджета, привязанных к тому, что чувствуют клиенты, например время загрузки страницы или оформления заказа, и воспринимайте нарушение как сигнал купить более быстрый тариф или исправить худший запрос, а не запускать проект настройки, который вы не сможете укомплектовать.

Крупная организация. В масштабе парка производительность прямая стоимость, поэтому управляйте ею как общей дисциплиной: стандартные инструменты профилирования, процентильные бюджеты, привязанные к бизнес-метрикам, и регрессионные шлюзы CI, применяемые последовательно, чтобы ползучее замедление одной команды не раздувало весь счёт за облако. Отслеживайте задержку, выделения и пропускную способность относительно базовых значений по сервисам и храните воспроизводимые свидетельства бенчмарков, потому что сокращение ЦП на 30% в большом парке это повторяющаяся экономия, достойная проверки и защиты от штрафов по SLA.

Государственный сектор. Производительность это гарантия доступа: страница, загружающаяся на старом телефоне по слабому соединению, решает, завершит ли гражданин заявление на пособие. Устанавливайте явные бюджеты для реалистичных малопроизводительных устройств и ограниченных сетей и публикуйте воспроизводимые результаты бенчмарков, фиксирующие устройство, сеть и нагрузку, чтобы закупки и надзорные органы могли проверить числа, а не принимать их на веру. Предпочитайте прозрачное проверяемое измерение утверждениям поставщиков и требуйте от поставщиков тех же воспроизводимых свидетельств.

Примеры

Стартап. Небольшая SaaS-команда замечает, что панель кажется вялой, и испытывает соблазн переписать её на более быстром фреймворке. Вместо этого они проводят день с профилировщиком и огненным графиком, показывающим, что 70% времени запроса занимает одна конечная точка, выдающая один запрос к базе данных на каждую строку, классический шаблон N+1. Они заменяют её одним пакетным запросом, задержка падает с 1,2 секунды до 90 миллисекунд, и они добавляют бюджет p99 в 200 мс в лёгкий бенчмарк CI, чтобы исправление не могло тихо регрессировать. Без переписывания, один день, десятикратный выигрыш.

Крупная организация. Ритейл-платформа запускает тысячи экземпляров, и её счёт за облако определяется одним сервисом рекомендаций. Кампания профилирования находит сильную «текучку» выделений, вызывающую частые паузы сборки мусора, плюс кэш с плохой долей попаданий. Настройка структур данных под локальность и исправление ключей кэша сокращает ЦП на запрос на 40%, что позволяет команде обслуживать тот же трафик на 40% меньшем числе машин. Экономия окупает инженерные усилия за недели, а SLA по задержке p99, иногда нарушавшееся, теперь выполняется с запасом, избегая контрактных штрафов.

Государственный сектор. Национальное налоговое управление должно обслуживать граждан на старых устройствах и медленных сельских соединениях. Команда устанавливает явный бюджет: страница подачи декларации должна стать интерактивной менее чем за 3 секунды на малопроизводительном телефоне по ограниченному профилю 3G. Они профилируют страницу, сокращают блокирующую интерактивность работу и публикуют воспроизводимые результаты бенчмарков, фиксирующие устройство, сеть и нагрузку, чтобы надзорные органы и аудиторы доступности могли проверить утверждение, а не принимать его на веру. Производительность здесь не рычаг стоимости, а гарантия доступа, сохраняющая сервис пригодным для всех.

Бизнес-обоснование: мотивы, ROI и TCO

Отдача от инженерии производительности проявляется в трёх учётных книгах. Первая стоимость инфраструктуры: более быстрый код делает ту же работу на меньшем числе машин, и для большого парка сокращение ЦП на 30% прямая повторяющаяся экономия, затмевающая разовые инженерные усилия. Вторая выручка и удовлетворённость: задержка коррелирует с конверсией, отказом от использования и доверием пользователей, поэтому сокращение хвоста рычаг роста, а не только гигиеническая задача. Третья избегаемый риск: нарушение SLA несёт штрафы, а запуск, плавящийся под нагрузкой, несёт репутационный ущерб и стоимость тушения пожаров.

Совокупная стоимость владения скромна и сосредоточена в начале. Вы вкладываетесь в инструменты профилирования, стабильную среду для бенчмарков и шлюзы CI, а также в дисциплину писать бюджеты и читать профили. Большая скрытая стоимость в альтернативе: долг производительности молча нарастает, а дооснащение скорости в медленную систему после запуска гораздо дороже её непрерывной защиты. Обосновывайте руководству в его единицах. Переводите задержку в конверсию или долю завершивших граждан, ЦП в ежемесячные расходы на облако, а регрессионный шлюз в предотвращённые инциденты. Самый сильный аргумент: производительность дёшево защищать коммит за коммитом и разорительно восстанавливать после гниения.

Антипаттерны и ловушки

  • Оптимизация без профилирования. Настройка кода, не являющегося узким местом, пока реальная стоимость остаётся нетронутой.
  • Преждевременная оптимизация. Жертвование ясностью ради воображаемой скорости, которую профилировщик никогда бы не отметил.
  • Сообщение средних. Сокрытие болезненного хвоста за комфортным средним; пользователи чувствуют p99, а не среднее.
  • Театр микробенчмарков. Числа с игрушечной нагрузки, наполовину удалённой оптимизатором, без прогрева и сообщаемой дисперсии.
  • Кэш без истории инвалидации. Погоня за долей попаданий при выдаче устаревших или неверных данных.
  • Предположение, что больше потоков поможет. Игнорирование закона Амдала и последовательной доли с последующим утоплением в состязании.
  • Нет регрессионного шлюза. Пусть пользователи будут тестом производительности, потому что ничто в CI не охраняет бюджет.
  • Оптимизация не той оси. Покупка пропускной способности пакетированием, когда пользователям нужна низкая задержка, или наоборот.

Модель зрелости

  • Уровень 1, Начальный: Производительностью занимаются, только когда что-то ломается. Нет бюджетов, привычки профилировать, бенчмарков. Оптимизация гадание, движимое интуицией, а средние единственная сообщаемая метрика.
  • Уровень 2, Развитие: Некоторые команды профилируют во время инцидентов и хранят несколько бенчмарков, но практика непоследовательна и зависит от энтузиазма отдельных людей. Бюджеты существуют неформально для одного-двух критических путей, процентили появляются на некоторых панелях, однако ничто не блокирует регрессию до выпуска, а каждая команда изобретает свой подход.
  • Уровень 3, Стандартизация: Критические пути несут письменные процентильные бюджеты, а профилирование это документированный ожидаемый первый шаг, прежде чем кто-либо оптимизирует. CI включает тесты производительности с регрессионными шлюзами, правила честного бенчмаркинга (прогрев, дисперсия, репрезентативные данные) записаны и соблюдаются по организации, и каждая команда следует одному методу, а не своему.
  • Уровень 4, Управление: Организация измеряет производительность как контролируемое свойство. Процентили задержки, пропускная способность, скорость выделений и число медленных запросов отслеживаются относительно явных базовых значений в эксплуатации и CI, регрессии количественно оцениваются относительно порогов, а не оспариваются, и бюджеты привязаны к бизнес-метрикам вроде конверсии или расходов на облако, так что нарушение запускает решение на основе данных. Свидетельства бенчмарков воспроизводимы и фиксируются с устройством, нагрузкой и средой для аудита.
  • Уровень 5, Оркестрация: Производительность непрерывно улучшается и интегрирована по организации. Бюджеты, профилирование, честный бенчмаркинг и анализ огненных графиков рутинные навыки, регрессионные шлюзы стабильны и пользуются доверием, а данные эксплуатации и CI замыкают петлю автоматически. Организация адаптирует бюджеты по мере смещения трафика, оборудования и бизнес-приоритетов, перебалансирует усилия к путям с наибольшей отдачей и защищает производительность как постоянное свойство, а не периодическую кампанию.

Идеи для обсуждения

  1. У какого из ваших критических путей сегодня есть письменный бюджет на основе процентилей и какие защищены только надеждой?
  2. Когда профилировщик в последний раз вас удивил и чему это вас научило о том, где, по вашему мнению, уходит время?
  3. Прогревают ли ваши бенчмарки, сообщают ли дисперсию и используют ли репрезентативные данные или они измеряют оптимизатор?
  4. Где вы тратите машины, чтобы замазать код, который кампания профилирования могла бы сделать дешевле?
  5. Какова последовательная доля вашей самой распараллеленной нагрузки и ограничивает ли закон Амдала ускорение, за которым вы гонитесь?
  6. Если бы коллега слил изменение, удвоившее задержку p99, как скоро кто-то заметил бы и как бы они узнали?

Главные выводы

  • Измеряйте, прежде чем оптимизировать; узкое место редко там, где вы гадаете, а преждевременная оптимизация стоит ясности без выигрыша.
  • Определяйте «достаточно быстро» как процентильный бюджет, потому что средние скрывают хвост, где живут реальные пользователи.
  • Предпочитайте алгоритмические выигрыши (лучший класс O-большого) микронастройке и знайте, нужна ли вам задержка или пропускная способность.
  • Уважайте пределы параллелизма (закон Амдала) и опасности кэширования (инвалидация и устаревание).
  • Делайте бенчмарки честно, с прогревом, дисперсией и репрезентативными нагрузками, и не доверяйте микробенчмаркам.
  • Контролируйте производительность в CI (глава 2.4) и наблюдайте в эксплуатации (глава 9.2); дополняйте системный взгляд из главы 3.5.
  • Производительность это стоимость для корпораций, доступ для государства, и её дёшево защищать непрерывно, но дорого дооснащать.

Источники и дополнительное чтение

  • Brendan Gregg, Systems Performance: Enterprise and the Cloud (profiling, flame graphs, and method).
  • Brendan Gregg, BPF Performance Tools (practical observability and profiling on Linux).
  • Donald E. Knuth, “Structured Programming with go to Statements” (ACM Computing Surveys, 1974): the source of the premature-optimisation maxim.
  • Donald E. Knuth, The Art of Computer Programming (algorithmic analysis and complexity).
  • Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms (Big O and algorithmic efficiency).
  • Gene M. Amdahl, “Validity of the Single Processor Approach to Achieving Large-Scale Computing Capabilities” (1967): the origin of Amdahl’s law.
  • Ulrich Drepper, “What Every Programmer Should Know About Memory” (the memory hierarchy and data locality).
  • Martin Kleppmann, Designing Data-Intensive Applications (latency, throughput, and tail behaviour in systems).
  • Aleksey Shipilev, “JMH and the pitfalls of microbenchmarking” (honest benchmarking practice on managed runtimes).
  • Ilya Grigorik, High Performance Browser Networking (client-side and network performance for low-bandwidth users).