Этот пост: анонимизированный разбор шести месяцев валидаторских операций и prover farm для команды ZK rollup, которая вышла в мейннет в Q1 2025. Без имён, без названия протокола, без узнаваемых деталей по топологии. Что осталось: цифры, тайминги и один инцидент, который мы поймали и закрыли за 48 часов на пятом месяце эксплуатации.
Заголовочный результат: 6 месяцев в продакшене, ноль slashing-событий, p95 proof time на 22 процента ниже их внутреннего baseline до нашего онбординга. Один Sev-2 по дороге, в котором ETA пруфов поехало вверх на 15-40 процентов выше нормы, и который оказался не там, где мы сначала искали.
Setup
Команда: средняя по размеру, около 12 инженеров после Series A, делает ZK rollup на SP1-based zkVM с кастомным proof aggregator поверх. Sequencer у них собственный, форк OP Stack. До нас они девять месяцев крутили инсентивированный тестнет и подошли к мейннету с уверенностью в коде и неуверенностью в том, кто будет держать инфру 24×7 без выгорания core команды.
Scope, который они отдали нам: validator/sequencer operations плюс prover farm на 24 GPU (12× H100 для тяжёлых aggregation-цепочек и 12× RTX 4090 для лёгких per-batch witness-задач), распределённо между двумя регионами. HSM key ceremony, runbook coverage, on-call ротация, follow-the-sun для покрытия EU и APAC окон. Их инженеры остались владельцами протокольной логики и application layer, мы взяли всё, что ниже уровня zkVM-кода: kernel, файловые системы, GPU drivers, наблюдаемость, инцидент-респонс.
Первые месяцы
Онбординг прошёл по нашему стандартному playbook. HSM key ceremony провели в первую неделю в двух географиях с двумя независимыми свидетелями со стороны клиента, теми же, кто потом подписывал генезис. К концу второй недели валидатор и sequencer ушли в мейннет, prover farm включался волнами: сначала 8 GPU как shadow-режим параллельно их существующему сетапу, через пять дней следующие 8, и через ещё неделю последние 8 с полным cutover. Их собственная prover-инфра ушла в hot-standby, через 30 дней её декомиссировали.
Runbook за первый месяц вырос с базовых 140 страниц до 320, в основном за счёт специфики SP1 для этого деплоя: per-circuit memory profile, особенности их proof aggregator под пиковую нагрузку, поведение sequencer при reorg в L1. С первого дня мейннета у нас стоял 24×7 мониторинг с MTTA целью под 15 минут.
За первые пять месяцев было пять инцидентов, все Sev-2 или ниже. Один раз CUDA driver на одной из H100-машин начал throwить ECC-ошибки, мы свапнули ноду за 22 минуты на hot-spare. Один раз L1 reorg на 3 блока заставил sequencer переотправить batch. Дважды алерт на queue depth срабатывал до того, как пруферы начинали реально отставать (false positive, перенастроили порог). Один раз kernel update на скрытом неподготовленном dependency edge замедлил один из RTX 4090 узлов, мы откатили в течение часа. MTTA по этим пяти: 11.4 минуты в среднем. Ни один инцидент не вышел в L1 как пропущенный batch или slashing-риск.
Это и есть нормальная steady state для validator ops, которой мы целимся: скучно, по runbook, ничего громкого.
Месяц 5: ETA пруфов начало плыть
Где-то в середине пятого месяца алерт сработал на per-circuit ETA: для aggregation-цепочки на H100 он начал стабильно превышать baseline на 15 процентов, а для самых тяжёлых witness-цепочек на RTX 4090 на 35-40 процентов. Aggregate throughput при этом выглядел почти нормально, потому что queue depth ещё не успел накопиться.
MTTA на этот алерт: 8 минут. Initial triage on-call инженером: 30 минут, и за эти полчаса стало понятно, что это не известный паттерн из runbook. Ни одного похожего сигнала за предыдущие пять месяцев. Эскалация на second-tier on-call, на этом моменте инцидент пошёл по полному циклу: совместный канал с клиентом, hourly status updates, dedicated bridge.
Часы 0-8: первые гипотезы
Первое, что мы проверили: вышел ли свежий релиз SP1 за последние две недели, который мог поменять профиль нагрузки. Вышел один, минорный, неделей раньше. Откатились на предыдущий билд на двух GPU как контрольную группу, разницы нет. Гипотеза снята.
Второе: GPU thermal. nvidia-smi dmon по всему пулу показал, что температуры на H100 в пределах 68-74°C, на RTX 4090 в пределах 71-77°C, ни одного throttling-события за окно последних 72 часов. Сняли.
Третье: backpressure от proof aggregator. Дашборды глубины очереди показали, что aggregator принимает witness-данные без задержек, очередь не растёт со стороны входа. Сняли.
К концу EU-смены было снято три гипотезы и поставлен handoff на APAC on-call с детальным списком того, что НЕ проблема, и того, что нужно проверить дальше.
Часы 8-24: расширили поиск
APAC-инженер за свою смену прошёл по следующим четырём слоям. CUDA driver: проверили версии на всех 24 GPU, identical. L2 fork timing: sequencer не наблюдал ничего аномального в окне последних 200 батчей. Client app submission latency: смотрели p95 и p99 по всем входным точкам, latency не изменился. Откат SP1 на полный пул: сделали rolling rollback, ETA не вернулся.
К концу APAC-смены, через 24 часа от первого алерта, у нас был длинный список того, что НЕ корневая причина: SP1, CUDA, thermal, aggregator backpressure, fork timing, submission latency. Шесть гипотез проверено, ни одна не подтвердилась. Это уже было информативно: проблема не в коде, не в драйверах, не в сети, не в нагрузке самой по себе.
Handoff обратно на EU. На утреннем bridge с клиентом честно сказали: знаем, где не лежит, не знаем, где лежит.
Час 28: правильный инструмент
Первый час EU-смены, один из инженеров вспомнил, что witness-данные SP1 пишутся на scratch-volume per-circuit, и что у нас есть метрика на aggregate throughput диска, но не на latency per file. Запустили filefrag на нескольких недавних witness-файлах на одном из H100 узлов.
Результат: 1400+ extents на одном 320MB файле. Дальше прошлись по остальным узлам: на одном из RTX 4090 нашли файл на 180MB с 1800+ extents. Filesystem: ext4 на NVMe scratch volume, mount-опции стандартные, никаких настроек под write-heavy workload.
После пяти месяцев непрерывной записи (proof job создаёт witness, читает его в случайном порядке для генерации proof, удаляет; объём записей на каждый GPU узел был порядка 200-400 ГБ в сутки) ext4 на этих томах накопила 18-22 процента фрагментации. iostat -xz 1 выглядел абсолютно нормально, потому что aggregate sequential throughput не упал. Упало per-circuit random-read latency для witness-чтения. Метрика, которой у нас не было.
Это и был root cause. Не SP1, не CUDA, не GPU. Скучный filesystem layer, который пять месяцев тихо деградировал под нагрузкой, для которой он не был оптимизирован при первоначальной настройке.
Часы 28-44: фикс
План раскатки сделали в две фазы, чтобы не создавать одновременного риска на всём пуле.
Phase 1, часы 28-34: hot-spare NVMe в той же машине отформатирован под свежий ext4 с mount -o noatime,nodiratime,data=ordered плюс предварительная аллокация большими экстентами. Дренировали первые 4 GPU (2× H100 + 2× RTX 4090), мигрировали scratch-volume, rolling restart proof-воркеров. Через час после рестарта собрали метрики: per-circuit ETA на этих четырёх GPU вернулся в диапазон -3...+1 процент от baseline. Гипотеза подтверждена.
Phase 2, часы 34-44: те же действия на оставшихся 8 GPU, по 4 одновременно с дренажём, без полной остановки prover farm. К часу 44 все 24 GPU работали на свежих scratch-томах с правильными mount-опциями.
Час 48: ETA вернулся к baseline
Через четыре часа после завершения phase 2, на отметке 48 часов от первого алерта, per-circuit ETA по всему пулу был на 23 процента ниже peak drift и в пределах SLA. Aggregate proof throughput вырос на 18 процентов относительно того, что было за 24 часа до инцидента (потому что random-read latency на witness-чтении подъедал производительность не только в peak window, а на протяжении нескольких недель до этого, просто ниже порога алертов).
Total incident window: ~48 часов от первого алерта до возврата в SLA. Severity: Sev-2 на пике, ни один batch не пропущен в L1, ни одного slashing-риска. Разбор инцидента для клиента ушёл через 22 часа после закрытия: 14 страниц, без поиска виноватых, с конкретным списком того, что попало в runbook.
Что попало в runbook
Из этого инцидента в наш внутренний runbook (и в их клиентскую копию) ушли четыре изменения:
- ext4 fragmentation check на 12-й неделе для любого GPU workload, который пишет >100 ГБ в сутки.
filefragпо выборке из 50 случайных файлов на scratch-volume, alert если медианное число extents на файл выше 200 или 95-й перцентиль выше 1000. filefragoutput ships в proof-job sidecar. Каждый proof job теперь логирует fragmentation своего witness-файла в structured log. Это даёт нам тренд per-circuit, а не только snapshot, и позволяет ловить деградацию до того, как она бьёт по ETA.- Per-circuit p95 ETA alert отдельно от aggregate throughput. Главный урок по метрикам. Aggregate показатель скрывал per-circuit регрессию на протяжении недель. Теперь алерт на p95 ETA каждого class circuit считается независимо.
- Hot-spare NVMe pre-formatted с явными опциями. В каждой prover-машине теперь второй NVMe заранее отформатирован под
ext4 + noatime,nodiratime,data=orderedи готов к hot swap. Это превратило phase 1 фикса из «найти и отформатировать диск» в «переключить mount-point», что сократило окно дренажа GPU с предполагаемых 90 минут до 22.
Урок
Скучный filesystem layer: это место, где регрессии прячутся после месяцев работы. Никакой код там не сломан, никакой драйвер не виноват, никакой релиз ничего не сломал. Workload просто накопил долг на слое, который не был профилирован под этот объём записей. Aggregate-метрики при этом продолжают выглядеть нормально, потому что они меряют не то, что деградирует. Когда мониторинг построен только на агрегированных показателях, он не увидит проблему до того, как она вылезет в SLA.
И 48-часовой бюджет на инцидент сработал не потому, что нам повезло. Сработал потому, что у нас была APAC и EU follow-the-sun ротация, которая не теряла контекст в handoff, hot-spare NVMe уже стояли в каждой машине, и формат разбора был отрепетирован на предыдущих Sev-2. Полтора суток на диагностику чужого filesystem-долга, ещё полсуток на двухфазную раскатку, ноль slashing на всём окне. Это и есть managed DevOps, который мы продаём: не «у нас не бывает инцидентов», а «инциденты случаются и закрываются в бюджете, который мы обещали».
Команда XIMTRX