Пара 23 / декабрь
Нагрузка, задержки и ограниченные повторы Провести небольшой контролируемый эксперимент и объяснить очередь и timeout.
Провести небольшой контролируемый эксперимент и объяснить очередь и timeout. Скрипт load.py отправляет ограниченное число запросов к своему localhost и показывает статусы и длительности. Сравниваем concurrency=1 и 4 при одинаковом числе запросов. Это учебное измерение, а не production-бенчмарк: ноутбук, WSL, кеш и фоновые задачи влияют на результат. Для демонстрации DELAY_MS искусственно задерживает вычисление, чтобы увидеть связь нагрузки и времени. Это не имитация настоящей модели и не научная оценка её производительности. Перед опытом фиксируем настройки и версию, после возвращаем delay=0.
Контекст Меняем один фактор и измеряем результат.
Провести небольшой контролируемый эксперимент и объяснить очередь и timeout.
Скрипт load.py отправляет ограниченное число запросов к своему localhost и показывает статусы и длительности. Сравниваем concurrency=1 и 4 при одинаковом числе запросов. Это учебное измерение, а не production-бенчмарк: ноутбук, WSL, кеш и фоновые задачи влияют на результат. Для демонстрации DELAY_MS искусственно задерживает вычисление, чтобы увидеть связь нагрузки и времени. Это не имитация настоящей модели и не научная оценка её производительности. Перед опытом фиксируем настройки и версию, после возвращаем delay=0.
Эксперимент с нагрузкой Меняем один фактор и измеряем результат.
01 Фиксируем условия
→ 02 Меняем concurrency
→ 03 Измеряем
→ 04 Сравниваем / вывод
Аналогия: сравнение двух очередей возможно, если остальные условия одинаковы.
Скрипт load.py отправляет ограниченное число запросов к своему localhost и показывает статусы и длительности. Сравниваем concurrency=1 и 4 при одинаковом числе запросов. Это учебное измерение, а не production-бенчмарк: ноутбук, WSL, кеш и фоновые задачи влияют на результат. Для демонстрации DELAY_MS искусственно задерживает вычисление, чтобы увидеть связь нагрузки и времени. Это не имитация настоящей модели и не научная оценка её производительности. Перед опытом фиксируем настройки и версию, после возвращаем delay=0.
Среднее и медленный хвост Один медленный запрос может быть важнее среднего.
01 Распределение
02 p50
03 p95
04 Среднее
Аналогия: среднее время ожидания не гарантирует, что никто не стоял час.
Среднее зависит от распределения и может скрывать часть медленных запросов. p50 — медиана, p95 — хвостовая граница для большей части наблюдений. Прямой расчёт по 20 запросам и оценка histogram_quantile по buckets могут отличаться: разная выборка и дискретизация. Это не ошибка арифметики. Черезput и latency связаны с ограничением ресурсов и очередями. Не объявляйте прирост concurrency ускорением отдельного запроса: одновременно может увеличиться число ответов и ухудшиться время каждого. В таблице подписываем n и условия измерения.
Timeout, retry и идемпотентность Ограничиваем ожидание и не усиливаем сбой повторами.
01 Timeout
→ 02 Классификация ошибки
→ 03 Ограниченный retry
→ 04 Проверка идемпотентности
Аналогия: если кассир не ответил, повторная оплата может списать деньги второй раз.
Каждый сетевой вызов должен иметь разумный timeout. Retry помогает при некоторых временных ошибках, но повторять неверный вход 400 бесполезно. Число попыток ограничивают, задержку увеличивают, добавляют jitter, чтобы клиенты не повторяли синхронно. Повтор POST может дважды выполнить побочное действие, если сервер уже обработал запрос, но ответ потерялся. В StudyPulse POST сохраняет событие: повтор способен создать дубликат. В рабочем проекте контракт идемпотентности и ключи повторов нужно проектировать отдельно. На курсе не добавляем автоматический retry, который скрывает эту проблему.
Команды и наблюдения Ubuntu / Bash, lab
DELAY_MS=200 docker compose up -d --force-recreate app
python3 scripts/load.py --requests 40 --concurrency 1
python3 scripts/load.py --requests 40 --concurrency 4
curl --max-time 0.1 -H "Content-Type: application/json" -d '{"hours":4}' http://127.0.0.1:8000/predict
DELAY_MS=0 docker compose up -d --force-recreate appНагрузка имеет пределы; скрипт разрешает только loopback-адрес. Изменение delay передаётся через Compose environment, затем обязательно возвращается к 0. Ожидаемое наблюдение: Запрос curl с коротким timeout может оборваться до ответа; сервис мог уже начать обработку, поэтому повтор не объявляется безопасным автоматически.
Разбор результата Запрос curl с коротким timeout может оборваться до ответа; сервис мог уже начать обработку, поэтому повтор не объявляется безопасным автоматически.
Нагрузка имеет пределы; скрипт разрешает только loopback-адрес. Изменение delay передаётся через Compose environment, затем обязательно возвращается к 0.
Используйте scripts/load.py с максимумом 500 запросов и concurrency ≤ 16; для занятия достаточно 40/4. Запишите фактические результаты, не копируйте выдуманные числа. После curl timeout проверьте request-логи и количество событий: сервер мог завершить вычисление до обнаружения закрытого соединения. Вывод: статус клиента не всегда полностью описывает состояние серверной операции.
На macOS Метод эксперимента одинаков, но реальные числа нельзя напрямую сравнивать между ARM Mac и AMD64 WSL: CPU, виртуализация и эмуляция различаются. На каждой машине сравниваем серии при фиксированных условиях.
python3 scripts/load.py --requests 40 --concurrency 1
python3 scripts/load.py --requests 40 --concurrency 4Команды macOS необходимо проверить на конкретном устройстве. Метод эксперимента одинаков, но реальные числа нельзя напрямую сравнивать между ARM Mac и AMD64 WSL: CPU, виртуализация и эмуляция различаются. На каждой машине сравниваем серии при фиксированных условиях.
Один фактор, две серии Запишите версию, delay, число запросов и concurrency. Проведите две серии, сравните p50/p95 и суммарное время. Сделайте timeout короче delay, найдите событие запроса в логах. Объясните, когда retry допустим, а когда может создать дубликат; восстановите delay=0. Работа в парах: один оператор, второй проверяет гипотезу. Смена ролей в середине. Используйте scripts/load.py с максимумом 500 запросов и concurrency ≤ 16; для занятия достаточно 40/4. Запишите фактические результаты, не копируйте выдуманные числа. После curl timeout проверьте request-логи и количество событий: сервер мог завершить вычисление до обнаружения закрытого соединения. Вывод: статус клиента не всегда полностью описывает состояние серверной операции.
Что должно получиться Таблица измерений и объяснение пределов выводов.
Нагрузка только на свой ноутбук; задержка убрана; timeout не принимают за доказательство необработанного запроса.
Используйте scripts/load.py с максимумом 500 запросов и concurrency ≤ 16; для занятия достаточно 40/4. Запишите фактические результаты, не копируйте выдуманные числа. После curl timeout проверьте request-логи и количество событий: сервер мог завершить вычисление до обнаружения закрытого соединения. Вывод: статус клиента не всегда полностью описывает состояние серверной операции.
Ошибка для диагностики Количество потоков повышают бесконечно, пытаясь «ускорить» сервис.
Симптом → Гипотеза → Проверка
Используйте scripts/load.py с максимумом 500 запросов и concurrency ≤ 16; для занятия достаточно 40/4. Запишите фактические результаты, не копируйте выдуманные числа. После curl timeout проверьте request-логи и количество событий: сервер мог завершить вычисление до обнаружения закрытого соединения. Вывод: статус клиента не всегда полностью описывает состояние серверной операции.
Основные выводы Операция могла уже выполниться и повтор создаст второе действие. Нет, часть запросов может быть медленнее. Операция могла уже выполниться и повтор создаст второе действие.
Нет, часть запросов может быть медленнее.
После пары Описать timeout/retry-политику для чтения healthz и для POST с побочным действием.
Конспект, команды и разбор → Проверьте критерии сдачи и дайте возможность повторной попытки. Первоисточники: https://sre.google/sre-book/handling-overload/ https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/
Среднее и p95: увидеть медленный хвост Это искусственные числа для объяснения, не результат измерения. p95 считаем методом nearest rank: 19-е значение из 20. Prometheus оценивает квантиль по buckets и может дать другое число.
Пара 24 / декабрь
Backup, восстановление и стабилизация Сделать проверяемую копию учебного volume и восстановить данные в новый том.
Сделать проверяемую копию учебного volume и восстановить данные в новый том. RPO — допустимый интервал потери данных, RTO — целевое время восстановления. Это цели, а не измеренные факты до проверки. Для append-only учебного events.jsonl холодная копия после остановки app проще согласованного online-backup. Для базы данных одного tar работающего volume может быть недостаточно: нужен штатный механизм и консистентность. Для курсового проекта определяем учебную цель и измеряем реальное восстановление. Наличие архива не доказывает, что он читается, содержит нужные данные и подходит версии приложения.
Контекст Решаем, сколько данных и времени можем потерять.
Сделать проверяемую копию учебного volume и восстановить данные в новый том.
RPO — допустимый интервал потери данных, RTO — целевое время восстановления. Это цели, а не измеренные факты до проверки. Для append-only учебного events.jsonl холодная копия после остановки app проще согласованного online-backup. Для базы данных одного tar работающего volume может быть недостаточно: нужен штатный механизм и консистентность. Для курсового проекта определяем учебную цель и измеряем реальное восстановление. Наличие архива не доказывает, что он читается, содержит нужные данные и подходит версии приложения.
RPO и RTO Решаем, сколько данных и времени можем потерять.
01 RPO: сколько данных
02 RTO: сколько времени
03 Способ копии
04 Проверка восстановления
Аналогия: запасной ключ полезен, если он подходит к текущему замку.
RPO — допустимый интервал потери данных, RTO — целевое время восстановления. Это цели, а не измеренные факты до проверки. Для append-only учебного events.jsonl холодная копия после остановки app проще согласованного online-backup. Для базы данных одного tar работающего volume может быть недостаточно: нужен штатный механизм и консистентность. Для курсового проекта определяем учебную цель и измеряем реальное восстановление. Наличие архива не доказывает, что он читается, содержит нужные данные и подходит версии приложения.
Независимая копия Volume защищает от пересоздания, backup — от потери состояния.
01 Volume
→ 02 Согласованная копия
→ 03 Checksum
→ 04 Независимое хранение
Аналогия: копия документов в другом ящике того же сгоревшего шкафа не спасает.
Скрипт backup.sh останавливает только app, копирует events.jsonl через docker compose cp в отдельную папку и считает SHA-256. Затем вновь запускает app. Учебная копия на том же ноутбуке нужна для практики, но не защищает от отказа самого диска или кражи. Для реального проекта нужна независимая копия с подходящим доступом и политикой хранения. Не называем общую папку Windows независимым backup только потому, что у неё другой путь. Проверка checksum обнаруживает изменение байтов, но не гарантирует бизнес-корректность всех данных.
Восстанавливаем отдельно Не уничтожаем исходное состояние ради доказательства backup.
01 Новый том
→ 02 Проверка архива
→ 03 Запуск отдельно
→ 04 Smoke + данные
Аналогия: аварийную копию сначала проверяют на запасном приборе.
Скрипт restore-check.sh поднимает временный контейнер с новым volume, копирует архивные данные, запускает приложение на другом localhost-порту и проверяет healthz и строки. Исходный учебный volume не удаляется. Для восстановления проверяем формат JSON, checksum и контракт приложения. Затем фиксируем время и результат. После опыта временный контейнер и только его том удаляются. Это безопаснее упражнения «удали всё и надеясь восстанови». Стабилизация включает документированный запуск, ограничения, мониторинг, проверенный откат и восстановление, а не только бесконечные рестарты.
Команды и наблюдения Ubuntu / Bash, lab
bash scripts/backup.sh
# Use the exact backup path printed by the script
bash scripts/restore-check.sh backups/EXACT_DIRECTORY
# Review checksum, JSON validity, row count and health responseEXACT_DIRECTORY — обозначение, замените реально выведенным именем. Не запускайте эту строку буквально. Скрипты работают только с текущим учебным compose. Ожидаемое наблюдение: Созданы events.jsonl и SHA256SUMS; отдельный восстановленный сервис отвечает и читает сохранённые строки.
Разбор результата Созданы events.jsonl и SHA256SUMS; отдельный восстановленный сервис отвечает и читает сохранённые строки.
EXACT_DIRECTORY — обозначение, замените реально выведенным именем. Не запускайте эту строку буквально. Скрипты работают только с текущим учебным compose.
Выполняйте backup после наличия событий. Скрипт прекращает операцию при пустом/невалидном файле и восстанавливает запуск app через trap. Для restore нужен локальный образ studypulse:v1; получите его через docker build -t studypulse:v1 . заранее. Проверка использует новый именованный том и порт 8002, не трогая основной app. Документируйте любое несовпадение количества строк и не стирайте оригинал.
На macOS Скрипты комплекта выбирают sha256sum в Linux и shasum -a 256 в macOS автоматически. Все данные извлекаются через Docker, не через закрытые папки Desktop. Backup на том же Mac остаётся учебной копией.
bash scripts/backup.sh
# Replace EXACT_DIRECTORY with the printed backup path
bash scripts/restore-check.sh backups/EXACT_DIRECTORYКоманды macOS необходимо проверить на конкретном устройстве. Скрипты комплекта выбирают sha256sum в Linux и shasum -a 256 в macOS автоматически. Все данные извлекаются через Docker, не через закрытые папки Desktop. Backup на том же Mac остаётся учебной копией.
Проверить, а не просто скопировать Создайте минимум три события и сделайте cold backup. Запишите исходное число строк и checksum. Восстановите в отдельный временный volume, проверьте JSON и здоровье приложения. Запишите фактическое время; объясните, какие угрозы копия на том же ноутбуке не закрывает. Работа в парах: один оператор, второй проверяет гипотезу. Смена ролей в середине. Выполняйте backup после наличия событий. Скрипт прекращает операцию при пустом/невалидном файле и восстанавливает запуск app через trap. Для restore нужен локальный образ studypulse:v1; получите его через docker build -t studypulse:v1 . заранее. Проверка использует новый именованный том и порт 8002, не трогая основной app. Документируйте любое несовпадение количества строк и не стирайте оригинал.
Что должно получиться Архив, checksum и restore-report.md с измеренным результатом.
Основной том сохранён; восстановление действительно проверено; RPO/RTO не выдаются за достигнутые без измерения.
Выполняйте backup после наличия событий. Скрипт прекращает операцию при пустом/невалидном файле и восстанавливает запуск app через trap. Для restore нужен локальный образ studypulse:v1; получите его через docker build -t studypulse:v1 . заранее. Проверка использует новый именованный том и порт 8002, не трогая основной app. Документируйте любое несовпадение количества строк и не стирайте оригинал.
Ошибка для диагностики Архив оказался пустым или относится к другому Compose project.
Симптом → Гипотеза → Проверка
Выполняйте backup после наличия событий. Скрипт прекращает операцию при пустом/невалидном файле и восстанавливает запуск app через trap. Для restore нужен локальный образ studypulse:v1; получите его через docker build -t studypulse:v1 . заранее. Проверка использует новый именованный том и порт 8002, не трогая основной app. Документируйте любое несовпадение количества строк и не стирайте оригинал.
Основные выводы Нет, нужно проверить чтение, содержание и реальное восстановление. Отказ диска или потеря ноутбука затронут обе копии. Нет, нужно проверить чтение, содержание и реальное восстановление.
Отказ диска или потеря ноутбука затронут обе копии.
После пары Дополнить runbook восстановлением и планом независимого хранения для настоящего проекта.
Конспект, команды и разбор → Проверьте критерии сдачи и дайте возможность повторной попытки. Первоисточники: https://docs.docker.com/engine/storage/volumes/ https://sre.google/sre-book/data-integrity/