Экспресс-курс · No. 24
Работа над производительностью каждый раз ломается одинаково: кто-то гадает, что медленно, оптимизирует не то и добавляет сложность впустую. Дисциплина обратная — измерь, чтобы найти настоящее узкое место, почини его одно, потом измерь снова. Выучи, что на деле делает софт медленным, и слова для этого — и «сделай быстрее» станет методом, а не догадкой.
20 понятий · схема у каждого · шпаргалка в конце
Первое правило производительности — то, что нарушают все: не доверяй чутью о том, что медленно. Почти вся впустую потраченная оптимизация идёт от пропуска этого одного шага.
Интуиция о медленности обычно неверна
Врач, который назначает операцию по догадке, ни разу не сделав анализ, — уверенный, быстрый и слишком часто оперирующий совсем не то.
Разработчики известны тем, что плохо угадывают, куда уходит время. Часть, в медленности которой ты уверен, часто в порядке. Настоящий виновник сидит там, где ты не ждал: крошечная функция, вызванная миллион раз, или скрытый вызов базы.
Действовать по чутью — значит оптимизировать не то, добавить сложность и остаться с медленной программой. Первый ход — никогда не «почини», а узнай, куда на деле уходит время.
Карта: 20 понятий в семи группах
Карта метро: сначала видишь линии целиком, потом едешь по станциям.
Все понятия курса делятся на семь групп — по одной на главу. Сначала — как измерять. Потом — какой именно «быстро» тебе нужен. Потом — узкое место и классические починки. Потом — как не дать среднему себя обмануть, когда не надо оптимизировать, и как вести всю работу циклом.
Как читать курс
Механик не меняет детали наугад: сначала приборы, потом одна починка, потом проверка.
У каждого понятия одно и то же: английское название (запомни его — это термин из документации, профайлеров и дашбордов), образ из жизни, схема и карточка с полями что это, как работает, пример, подвох и связи.
Главная идея курса: производительность — это не набор трюков, а метод. Измерь → найди узкое место → почини одно → измерь снова → остановись на цели. Всё остальное в курсе — детали этого цикла.
Profiling — найди реальную стоимость
Детализированный счёт, где видно, куда ушли деньги, строка за строкой. Ты перестаёшь гадать и видишь, что бюджет съел один платёж — и не тот, на который ты думал.
Профайлер (profiler) — инструмент, который меряет, где программа на деле проводит время, функция за функцией. Он превращает «думаю, это медленно» в «эта одна функция — 80% времени выполнения». С этим ты чинишь то, что важно, а не то, что вообразил.
Профайлер ли это, логи с таймингами или метрики наблюдаемости (observability) — принцип один: пусть на проблему указывает измерение, а не интуиция.
- Что это
- Измерение того, где программа на деле тратит время, по функциям.
- Как работает
Профайлер (или логи с таймингами, или метрики) записывает время каждой части и показывает доли.
- Пример
«
getOrders()— 80% времени запроса» вместо «наверное, тормозит рендер».- Подвох
Профиль на игрушечных данных может указать не туда — меряй на реалистичной нагрузке.
- Связи
- Первый шаг Measure–Fix–Measure; именно он находит Bottleneck.
Measure–Fix–Measure — измерь, почини, измерь снова
Учёный меняет одну переменную, перезапускает опыт и проверяет результат — никогда не предполагая, что изменение помогло, всегда подтверждая.
Производительность — это цикл: измерь, чтобы найти медленную часть, измени её, потом измерь снова, чтобы подтвердить, что изменение правда помогло, — а не просто сдвинуло проблему или сделало хуже.
Без второго измерения ты гадаешь, улучшил ли что-то. Именно так «оптимизации» тихо делают всё медленнее. Относись к каждой починке как к гипотезе, которую проверяешь, — та же дисциплина, что эвалы для ИИ или тесты для кода.
- Что это
- Каждая починка проверяется вторым измерением до и после.
- Как работает
Один и тот же тест до изменения и после; меняешь одну вещь за раз, чтобы знать, что сработало.
- Пример
Добавил индекс: запрос был 400 мс, стал 40 мс — оставляешь. Не изменилось — откатываешь.
- Подвох
Без второго замера «оптимизация» может тихо замедлить систему, и никто не заметит.
- Связи
- Ядро Optimization Loop; родственник эвалов и тестов.
Интуиция о медленности обычно неверна. Профилируй, чтобы найти, куда реально уходит время, почини это и измерь снова, чтобы подтвердить, — никогда не оптимизируй по догадке.
До оптимизации знай, какой именно «быстро» тебе нужен. Две разные цели постоянно путают, и улучшение одной может ничего не дать другой.
Latency — ожидание одной вещи
Сколько занимает один кофе от заказа до чашки — опыт одного клиента, от начала до конца.
Задержка (latency) — сколько занимает одна операция от начала до конца: один запрос, одна загрузка страницы, один запрос к базе. Это то, что отдельный пользователь чувствует: ожидание.
Когда кто-то говорит «сайт медленный», он почти всегда имеет в виду задержку — паузу между действием и ответом. Снижать задержку — значит делать каждую отдельную вещь быстрее.
- Что это
- Время одной операции от начала до конца, обычно в миллисекундах.
- Как работает
Складывается из всех шагов пути: сеть, работа сервера, база, отрисовка.
- Пример
- От клика до готовой страницы — 800 мс.
- Подвох
Одна цифра задержки — обычно среднее, а оно прячет медленные случаи (глава 5).
- Связи
- Отдельная цель от Throughput; меряется через Percentiles.
Throughput — сколько обрабатываешь в секунду
Сколько кофе вся кофейня подаёт за час — не сколько занимает один, а общий поток через заведение.
Пропускная способность (throughput) — сколько работы система обрабатывает за единицу времени: запросов в секунду, задач в минуту. Это про общую ёмкость, а не про отдельное ожидание.
У системы может быть отличная пропускная способность (обслуживает тысячи разом), пока каждый пользователь всё равно ждёт (высокая задержка). Или низкая задержка, но ограниченная ёмкость. Это разные цели, и от того, какую ты гонишь, зависит, что ты чинишь.
- Что это
- Объём работы за единицу времени: запросов в секунду, задач в минуту.
- Как работает
Растёт, когда система обрабатывает больше параллельно или тратит меньше на каждую единицу.
- Пример
API держит 1 000 запросов в секунду; ночной конвейер — миллион строк в час.
- Подвох
Высокий throughput не значит, что пользователю быстро: каждый может ждать долго.
- Связи
- Часто растёт за счёт Latency через Batching.
Batching — пропускная способность ценой задержки
Мотоцикл довозит одного человека быстрее всех (низкая задержка); автобус перевозит больше всего людей за рейс (высокая пропускная способность). Лучший транспорт зависит от того, что тебе нужно.
Задержка и пропускная способность независимы, и оптимизация одной может навредить другой. Батчинг (batching) — группировка работы — часто поднимает пропускную способность, но добавляет задержку: каждый элемент ждёт, пока соберётся пачка.
Поэтому реши, что важно здесь. Страница для пользователя живёт или умирает на задержке; фоновый конвейер данных заботится о пропускной способности. Назови свою реальную цель — и не будешь оптимизировать число, которое не важно твоим пользователям.
- Что это
- Собирать много мелких операций в одну большую.
- Как работает
Накладные расходы (поездка по сети, запуск задачи) платятся один раз на пачку, а не на элемент.
- Пример
- Вставить 1 000 строк одним запросом вместо 1 000 отдельных.
- Подвох
- Каждый элемент ждёт, пока пачка наберётся, — задержка растёт.
- Связи
Меняет Latency на Throughput; та же идея, что лечит N+1 Query.
Задержка — это ожидание одной операции; пропускная способность — сколько обрабатываешь в секунду. Это независимые цели — а батчинг часто меняет задержку на пропускную способность.
Время не размазано ровно. Почти всегда одна часть доминирует — и оптимизировать что-то ещё бессмысленно, пока не починишь её.
Bottleneck — одна медленная часть доминирует
Цепь ровно настолько крепка, насколько её слабейшее звено. Усиливать крепкие звенья бесполезно — только слабое решает, выдержит ли она.
В большинстве медленных систем одно узкое место (bottleneck) отвечает за бо́льшую часть времени — один запрос, один медленный сервис, один плохой цикл. Всё остальное уже достаточно быстро.
Поэтому гадать так расточительно: весь навык — найти доминирующую стоимость, а не улучшать быстрые части.
- Что это
- Та одна часть, которая занимает бо́льшую часть общего времени.
- Как работает
Профиль показывает доли; обычно одна часть резко больше остальных.
- Пример
Страница грузится 500 мс, и 400 из них — один запрос к базе без индекса.
- Подвох
- Узкое место редко там, где ты его ждёшь, — поэтому сначала профиль.
- Связи
Находится через Profiling; почему его чинить — объясняет Amdahl's Law.
Limiting Step — система быстра настолько, насколько её самый медленный шаг
Шоссе свободно, пока не одно перекрытие полосы, где все ползут. Скорость всей поездки задаёт это одно место, а не свободные участки.
Запрос, который проходит десять шагов, ограничен самым медленным из них — это ограничивающий шаг (limiting step). Ускорить девять быстрых шагов — итог почти не сдвинется; темп задаёт медленный. Так что ты целишься именно в него.
И заметь: починка одного узкого места часто открывает следующее. Убери самый медленный шаг — появится новый самый медленный. Работа над производительностью — это повторяющийся поиск и расчистка того, что ограничивает систему сейчас.
- Что это
- Шаг, который сейчас задаёт скорость всего пути.
- Как работает
Убрал один ограничивающий шаг — ограничивающим становится следующий по медленности.
- Пример
Ускорили запрос в 10 раз — теперь рендер в 50 мс стал самым медленным шагом.
- Подвох
Узкое место не исчезает навсегда, оно переезжает — поэтому нужна цель, где остановиться.
- Связи
Причина, почему Optimization Loop — цикл, а Performance Target — его выход.
Amdahl's Law — оптимизация в другом месте впустую
Полировать кубок, пока у машины спущено колесо, — усилие там, где оно ничего не меняет, а то, что тебя на деле останавливает, лежит нетронутым.
Оптимизируешь часть, которая занимает 2% времени, — лучшее, что выиграешь, это 2%. Найди часть на 80% — и её починка меняет всё. Эту арифметику называют законом Амдала (Amdahl's law): выигрыш ограничен долей времени, которую занимает ускоряемая часть.
Время на оптимизацию чего угодно, кроме узкого места, по определению не может заметно помочь. Часто оно делает хуже — сложность и баги ради невидимого выигрыша. Измерение не даёт тебе любовно полировать часть, которую ты понимаешь, и заставляет взяться за ту, что правда стоит. Чини узкое место, остальное игнорируй — пока остальное само не станет узким местом.
- Что это
Ускорение части системы ограничено тем, какую долю времени эта часть занимает.
- Как работает
Часть на 10% даже при бесконечном ускорении сэкономит максимум 10%.
- Пример
Рендер (10%) вдвое быстрее: 500 → 475 мс. Запрос (80%) вдвое быстрее: 500 → 300 мс.
- Подвох
Приятно оптимизировать то, что понимаешь, — но если это не узкое место, выигрыша не будет.
- Связи
Математика за Bottleneck; аргумент против Premature Optimization.
Одно узкое место обычно доминирует во времени, и система быстра ровно настолько, насколько её самый медленный шаг. Чини его; оптимизация чего угодно ещё впустую, пока оно не станет узким местом.
Когда узкое место найдено, починка обычно одна из немногих классических. Эти несколько приёмов дают подавляющую часть реальных ускорений.
Better Algorithm (Big-O) — лучший алгоритм бьёт более быструю машину
Два маршрута в один город: быстрая машина на длинной извилистой дороге всё равно проигрывает медленной на прямом срезе. Маршрут важнее двигателя.
Крупнейшие выигрыши часто дают лучший алгоритм или структура данных, а не железо и не микроправки. Как растёт время с ростом входа, описывает Big-O. Цикл O(n²), заменённый на поиск O(n) через хеш-таблицу, может превратить минуты в миллисекунды — никакая более быстрая машина так не сможет.
Прежде чем оптимизировать мелочь, спроси, не неверен ли сам подход. Лучшая форма, как показывает курс о структурах данных, — самое дешёвое и самое крупное ускорение из всех.
- Что это
- Сменить подход так, чтобы работа росла медленнее с ростом данных.
- Как работает
Big-O показывает рост: O(n²) — вложенный цикл «каждый с каждым», O(n) — один проход.
- Пример
Найти общие элементы двух списков: вложенный цикл → множество (hash set) и один проход.
- Подвох
На маленьких данных разницы не видно — она взрывается, когда данных становится много.
- Связи
- Главный выбор Performance by Design; см. курс о структурах данных.
N+1 Query — слишком много круговых поездок
Двадцать отдельных походов в магазин за одной вещью каждый вместо одного похода со списком — твой день съедает дорога, а не покупки.
Огромная доля медленности — слишком много круговых поездок (round trips): повторные вызовы базы или сервиса, каждый дешёвый сам по себе, но разрушительный в массе.
Классика — запрос N+1 (N+1 query): достать список, а потом сделать ещё по запросу на каждый элемент. Один поход превращается в сотни. Лекарство — доставать оптом, спросить всё разом. Уменьшить число поездок обычно выгоднее, чем ускорять каждую, потому что сама поездка и есть стоимость.
- Что это
- Один запрос за список, потом по запросу на каждый элемент.
- Как работает
Каждая поездка в базу стоит сети и накладных расходов; N поездок умножают эту цену на N.
- Пример
100 заказов → 1 запрос за список + 100 запросов за клиентов. Починка: один запрос с
IN (…)или JOIN.- Подвох
ORM прячет это: код выглядит как простой цикл, а под ним — сотни запросов.
- Связи
- Лечится той же идеей, что Batching; частый Bottleneck.
Caching — не считай одно и то же дважды
Готовить блюдо с нуля каждый раз, когда кто-то просит, вместо того чтобы держать кастрюлю тёплой, — самая быстрая работа та, что не повторяешь.
Кэширование (caching) — запомнить дорогой результат, чтобы не пересчитывать его. Это один из крупнейших рычагов вообще (у него свой курс).
Первый запрос идёт по долгому пути и сохраняет результат; следующие получают его из памяти. Цена — память и риск отдать устаревшие данные.
- Что это
- Хранить результат дорогой работы и отдавать его повторно.
- Как работает
Проверяем кэш: есть — отдаём сразу (hit); нет — считаем, сохраняем, отдаём (miss).
- Пример
- Страница каталога собирается 300 мс; из кэша — за пару миллисекунд.
- Подвох
Кэш может отдать устаревшие данные; когда его сбрасывать — отдельная трудная задача.
- Связи
- Частный случай Doing Less; подробно — в курсе о кэшировании.
Doing Less — самая быстрая работа та, что ты пропустил
Не готовить то, что никто не заказал, и не накрывать стол на двадцать, когда пришли трое.
Ещё одна классика — делать меньше (doing less). Вычисляй вещи лениво (lazy) — только когда они правда нужны. Не загружай данные, которые не используешь. Пропускай работу, результат которой всё равно выбросишь.
Самая быстрая операция — та, что ты никогда не запускаешь. Часто лучшая оптимизация не в том, чтобы делать работу быстрее, а в том, чтобы не делать её вовсе.
- Что это
- Убрать работу, а не ускорять её.
- Как работает
Ленивые вычисления, загрузка только нужных полей, отказ от результатов, которые не нужны.
- Пример
Тянуть из базы 3 нужных поля, а не все 50; считать отчёт, только когда его открыли.
- Подвох
- Ленивая работа может выстрелить позже, в неудобный момент, — меряй.
- Связи
- Включает Caching (не повторять) и лечит часть N+1 Query.
Большинство ускорений — несколько классик: лучший алгоритм, меньше круговых поездок (убей N+1), кэширование дорогих результатов и просто меньше работы. Самая быстрая работа — та, что ты пропустил.
То, как ты меряешь производительность, может тебе врать. Среднее — самое утешительное и самое обманчивое число, и умение смотреть за него отделяет реальную работу над производительностью от самообмана.
Average — среднее прячет медленные случаи
В комнате девять человек в комфорте и один в огне — средняя температура приятная. Среднее стирает тот случай, который на деле важен.
Сообщать производительность как среднее (average, mean) опасно успокаивает: оно смешивает быстрое большинство с медленным меньшинством в одно счастливое число. Но пользователи не живут в среднем — каждый живёт в своём запросе, и медленные чувствуют каждую миллисекунду.
Среднее время ответа 200 мс может прятать, что один пользователь из двадцати ждёт пять секунд. Среднее говорит «всё в порядке», пока реальная доля пользователей страдает.
- Что это
- Сумма времён, делённая на число запросов.
- Как работает
- Смешивает быстрые и медленные запросы в одно число.
- Пример
- «Среднее — 200 мс», а каждый двадцатый ждёт 5 секунд.
- Подвох
Выглядит прилично, пока часть пользователей страдает. Нельзя ставить на нём цели.
- Связи
- Заменяется на Percentiles; прячет Tail Latency.
Percentiles — p50 и p99 показывают реальный опыт
Отчёт, где написано не только типичное ожидание, но и «самый медленный 1% людей ждал вот столько», — плохие случаи названы, а не усреднены.
Перцентили (percentiles) показывают то, что прячет среднее. p50 (медиана) — типичный случай: половина запросов быстрее. p99 — медленный хвост: 99% быстрее, так что это примерно худший опыт, который встречает реальный пользователь.
Следить за p99, а не только за средним, — вот как ты видишь тех, кто правда страдает. Хвост — это место, где живёт боль, а перцентили делают её видимой.
- Что это
- pN — время, быстрее которого N% запросов. p50 — медиана, p99 — хвост.
- Как работает
- Сортируешь времена ответа и берёшь значение на нужной позиции.
- Пример
- p50 = 120 мс (типично), p99 = 2 с (каждый сотый ждёт две секунды).
- Подвох
Перцентили нельзя усреднять между серверами — считай их по всем запросам сразу.
- Связи
- Делают видимой Tail Latency; на них ставят Performance Target.
Tail Latency — то, что пользователи помнят
Один ужасный ужин в ресторане перевешивает в памяти дюжину нормальных — худшие переживания, а не среднее, формируют то, как тебя судят.
Медленные запросы — хвост (tail latency) — непропорционально формируют то, как пользователи воспринимают продукт, потому что плохой опыт запоминается.
И в масштабе хвост задевает больше людей, чем кажется. Если страница делает много вызовов, шанс, что хотя бы один медленный, быстро растёт, — и почти каждый пользователь рано или поздно чувствует хвост. Поэтому серьёзные команды ставят цели на p99, а не на среднее: приручить худшие случаи — вот что делает продукт стабильно быстрым.
- Что это
- Время самых медленных запросов — p99 и дальше.
- Как работает
Когда один ответ собирается из многих вызовов, он ждёт самый медленный из них.
- Пример
Каждый вызов медленный лишь в 1% случаев, но страница из 100 вызовов попадает в хвост примерно в 63% случаев.
- Подвох
Чем больше вызовов в ответе, тем чаще «редкий» хвост становится нормой.
- Связи
- Видна через Percentiles; прячется в Average.
Среднее прячет медленные случаи, которые пользователи реально чувствуют. Следи за перцентилями — p50 для типичного, p99 для болезненного хвоста — потому что люди помнят худшее.
Есть ошибка, обратная игнорированию производительности: гнаться за ней слишком рано, везде, ещё не зная, что она важна. Знаменитое предупреждение об этом знаменито не зря.
Premature Optimization — корень всех зол
Укреплять каждую стену дома против землетрясения, которого может и не быть, до того как кто-то вообще въехал, — огромное усилие на проблему, которой у тебя пока нет.
Знаменитая фраза Дональда Кнута — «преждевременная оптимизация (premature optimization) — корень всех зол» — предостерегает от оптимизации до того, как ты знаешь, что́ и нужно ли вообще ускорять.
Оптимизировать код, который не медленный или даже редко запускается, не даёт ничего и стоит немало: сложность, баги и время, украденное у того, что важно. Большинству кода не нужно быть быстрым — ему нужно быть верным и ясным. Работа над скоростью — для частей, которые измерение доказало горячими (hot).
- Что это
- Оптимизировать до того, как измерение показало, что это нужно.
- Как работает
Ты платишь ясностью и временем за скорость в месте, где она никому не нужна.
- Пример
Неделя на хитрый кэш для страницы настроек, которую открывают раз в месяц.
- Подвох
Запутанный «быстрый» код мешает, когда настоящее узкое место всплывает в другом месте.
- Связи
Лечится Profiling; объясняется Amdahl's Law; не путать с Performance by Design.
Correct → Clear → Fast — сначала верно и ясно, быстро там, где важно
Ты пишешь рецепт так, чтобы любой мог по нему готовить, и упрощаешь только тот шаг, что делаешь сто раз в день, — не каждый шаг, только горячий.
Порядок такой: сделай верным (correct), сделай ясным (clear) и сделай быстрым (fast) только там, где измерение показывает, что это важно.
Ясный код легче оптимизировать потом — именно потому, что ты его понимаешь. Запутанный «быстрый» код трудно чинить, когда настоящее узкое место появляется в другом месте. Скорость почти всегда стоит читаемости, так что эту цену платишь только там, где она покупает реальный, измеренный выигрыш, а остальное держишь простым.
- Что это
- Порядок приоритетов: верность, ясность, и лишь потом скорость.
- Как работает
Скорость добавляешь точечно в горячих местах, когда ясный код уже есть и измерен.
- Пример
Пишешь простой понятный обработчик; профиль показал горячий цикл — оптимизируешь только его.
- Подвох
Оптимизация почти всегда стоит читаемости — трать её только на выигрыш.
- Связи
- Противоядие от Premature Optimization.
Performance by Design — но не игнорируй производительность в дизайне
Ты не делаешь сейсмоустойчивым сарай, но и не строишь небоскрёб на песке. Некоторые решения дёшево принять верно рано и разорительно чинить поздно.
Предупреждение — не «никогда не думай о производительности». Выбрать алгоритм O(n²) там, где O(n) был так же лёгок, или структуру, которая не масштабируется, — это ошибка дизайна, за которую дорого заплатишь потом.
Баланс такой: не микрооптимизируй рано, но и не делай архитектурных выборов, которые медленны по дизайну и дороги в откате. Большую форму выбери верно и дёшево заранее; детали оптимизируй, только когда измерение требует.
- Что это
Большие решения о форме системы сразу принимать с оглядкой на скорость.
- Как работает
Алгоритм, структура данных и архитектура выбираются рано; микротюнинг — потом, по замерам.
- Пример
Сразу выбрать поиск по индексу, а не перебор всей таблицы, — это не преждевременно.
- Подвох
Легко спрятать за этим принципом обычную преждевременную оптимизацию деталей.
- Связи
Граница Premature Optimization; главный инструмент — Better Algorithm.
Преждевременная оптимизация меняет ясность на скорость, которая никому не нужна. Сделай верно и ясно сначала, быстро — только там, где измерение доказало важность. Но не выбирай форму, медленную по дизайну, — о ней пожалеешь.
Хорошая работа над производительностью — спокойный повторяемый метод, а не героический аврал. Вся практика умещается в короткий цикл, который ты запускаешь, только когда есть реальная причина.
Optimization Loop — измерь, почини узкое место, повтори
Механик диагностирует приборами, чинит одну отказавшую деталь, потом проверяет снова — и никогда не меняет детали наугад в надежде, что стук пропадёт.
Метод простой и дисциплинированный: измерь, чтобы найти узкое место, почини его одно, измерь снова, чтобы подтвердить и увидеть следующее узкое место, и остановись, когда достаточно быстро.
Каждый проход целится в текущую доминирующую стоимость и игнорирует всё остальное. Цикл держит работу честной и эффективной: ты всегда знаешь, что работаешь над тем, что правда важно, и всегда знаешь, помог ли.
- Что это
- Повторяющийся цикл: измерить, найти, починить одно, проверить.
- Как работает
Каждый круг — один Measure–Fix–Measure против текущего Limiting Step.
- Пример
Круг 1: индекс на запрос. Круг 2: рендер стал узким местом — кэш шаблона. Цель достигнута — стоп.
- Подвох
- Без цели цикл никогда не заканчивается.
- Связи
- Собирает Profiling, Bottleneck и Performance Target вместе.
Performance Target — поставь цель, потом остановись
Ты утепляешь дом, пока не станет достаточно тепло, и останавливаешься — а не добавляешь утеплитель вечно, за пределом того, что кто-то может почувствовать.
У производительности нет естественного конца — всегда можно сделать чуть быстрее. Так что поставь цель (performance target) — «страницы быстрее 300 мс на p99» — и остановись, когда достиг.
Без цели оптимизация превращается в бесконечную яму времени с убывающей отдачей, а сложность вползает ради выигрышей, которых никто не замечает. Знать, что значит «достаточно быстро» для твоих пользователей и твоего случая, — вот что позволяет сделать ровно столько работы, сколько нужно, и пойти строить что-то ещё.
- Что это
- Конкретное число «достаточно быстро», привязанное к перцентилю.
- Как работает
Цикл оптимизации идёт, пока метрика выше цели, и останавливается, когда ниже.
- Пример
- «p99 главной страницы — меньше 300 мс».
- Подвох
- Цель на среднем обманет — ставь её на p99.
- Связи
- Выход из Optimization Loop; меряется через Percentiles.
Как всё связано
Карта маршрута целиком: видно, откуда начинаешь, через какие станции идёшь и где выходишь.
Понятия курса складываются в одну картину. Профилирование находит узкое место; цель — latency или throughput — говорит, что именно чинить. Узкое место обычно лечится одной из четырёх классик: лучший алгоритм, меньше круговых поездок, кэш или меньше работы. Потом — измерить снова, по перцентилям, против цели, и остановиться. А преждевременная оптимизация — то, что случается, когда пропускаешь измерение.
- Измерил ли я, куда на деле уходит время, или гадаю?
- Задержка или пропускная способность — какой «быстро» мне правда нужен?
- Где узкое место — та одна часть, что доминирует во времени?
- Это классика — плохой алгоритм, слишком много круговых поездок, нет кэша, лишняя работа?
- Слежу ли я за p99, а не только за средним, которое прячет медленный хвост?
- Есть ли цель, к которой я оптимизирую, чтобы знать, когда остановиться?
- Ты измеряешь до того, как что-то трогать, и измеряешь снова после.
- Ты чинишь узкое место и игнорируешь части, которые уже достаточно быстры.
- Твои выигрыши идут от алгоритмов, меньшего числа круговых поездок и кэширования, а не от микроправок.
- Ты судишь скорость по p99, а не по льстивому среднему.
- Ты оптимизируешь к цели и останавливаешься, держа остальное ясным и верным.
Шпаргалка: все 20 понятий
Измерение
- Profilingпрофилирование
Измерить, где программа на деле тратит время, функция за функцией.
- Measure–Fix–Measureизмерь, почини, измерь
Каждая починка — гипотеза, которую подтверждает второе измерение.
Цели скорости
- Latencyзадержка
Время одной операции от начала до конца — то, что чувствует пользователь.
- Throughputпропускная способность
Сколько работы система обрабатывает в секунду.
- Batchingбатчинг
Группировать работу: пропускная способность растёт, задержка тоже.
Узкое место
- Bottleneckузкое место
Одна часть, которая занимает бо́льшую часть времени.
- Limiting Stepограничивающий шаг
Система быстра, как её самый медленный шаг; починил — появится следующий.
- Amdahl's Lawзакон Амдала
Выигрыш ограничен долей времени ускоряемой части.
Крупнейшие выигрыши
- Better AlgorithmBig-O
Сменить подход: O(n²) → O(n) бьёт любое железо.
- N+1 Queryлишние round trips
Запрос на каждый элемент списка; лечится выборкой оптом.
- Cachingкэширование
Запомнить дорогой результат и не считать его снова.
- Doing Lesslazy evaluation
Не делать ненужную работу: лениво, только нужные данные, без выброшенных результатов.
Хвост
- Average (Mean)среднее
Одно спокойное число, которое прячет медленные случаи.
- Percentilesp50 / p99
p50 — типичный случай, p99 — примерно худший опыт реального пользователя.
- Tail Latencyхвостовая задержка
Самые медленные запросы; их помнят, и при многих вызовах их ловит почти каждый.
Сдержанность
- Premature Optimizationпреждевременная оптимизация
Ускорять до того, как измерение показало нужду.
- Correct → Clear → Fastmake it work, right, fast
Сначала верно, потом ясно, быстро — только в горячих местах.
- Performance by Designпроизводительность в дизайне
Большую форму (алгоритм, структуру, архитектуру) выбирай верно сразу.
Практика
- Optimization Loopцикл оптимизации
Измерь → почини одно узкое место → измерь снова → повтори.
- Performance Targetцель
Число «достаточно быстро» на p99 — где цикл останавливается.
Производительность — это спокойный цикл: измерь, почини одно узкое место, измерь снова, остановись на цели. Тянись к скорости только там, где доказано, что она важна, а всё остальное держи ясным.