блокеры разобраны замером: три стали задачами, один закрыт
- находки 48 и 49: единицы не менялись ни разу; настоящих столкновений 0.65%, несравнимых наборов полей нет, тай-брейк берёт меньшее в 96% случаев - edinicy-metriki-v-razreze закрыт: гипотеза не подтвердилась замером - тай-брейк отложен до каталога рода агрегации
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
# Разнести ответ приёма и свёртку доставки
|
||||
|
||||
**Приоритет:** блокеры
|
||||
**Приоритет:** высокий
|
||||
|
||||
Вынуто ревью кода задачи `razbor-metrik-v-obekty` (профиль `deep`, находка №4
|
||||
триажа, severity major).
|
||||
Была блокером, вынутым ревью кода задачи `razbor-metrik-v-obekty` (профиль
|
||||
`deep`, находка №4 триажа, severity major). **Решение принято** — ниже задача.
|
||||
|
||||
## Что решить
|
||||
## Что не так сегодня
|
||||
|
||||
Свёртка выполняется **синхронно внутри обработчика запроса**, поэтому время
|
||||
ответа равно времени свёртки. Вопрос: разносить ли их, и какой ценой.
|
||||
|
||||
## Оракул: измерено
|
||||
ответа равно времени свёртки.
|
||||
|
||||
`WriteTimeout` в Go ставится в `readRequest` — **до** чтения тела и до вызова
|
||||
обработчика (`net/http/server.go:993-997`, прочитано в исходниках). Значит
|
||||
@@ -46,28 +44,39 @@ client: elapsed=501ms err=EOF
|
||||
экспорт, — то есть ровно по тем, ради которых заведён инвариант «дыры
|
||||
закрываются сами».
|
||||
|
||||
## Варианты и цена
|
||||
## Что решено
|
||||
|
||||
**(а) Отвечать `200` сразу после архивации и учёта; свёртка — воркером в
|
||||
порядке журнала, с подбором `pending` при старте.**
|
||||
Цена: средняя — воркер, очередь, подбор при старте. Бонусом закрываются ещё
|
||||
две дыры: параллельные доставки одной автоматизации перестают гонять
|
||||
наследование слоя (сейчас вторая может не найти слоя первой и уйти в
|
||||
`failed`), и доставка, застрявшая в `pending` из-за сбоя записи, наконец
|
||||
кем-то подбирается.
|
||||
Вариант (а): **отвечать `200` сразу после архивации и учёта; свёртка —
|
||||
воркером в порядке журнала, с подбором `pending` при старте.**
|
||||
|
||||
**(б) Поднять `write_timeout` до согласованного с `foldTimeout`.**
|
||||
Цена: малая. Но худший случай (64 МиБ) всё равно минуты, и молчание
|
||||
`accessLog` остаётся.
|
||||
Почему он, а не альтернативы:
|
||||
|
||||
**(в) Оставить как есть, задокументировав потолок размера доставки.**
|
||||
Цена: нулевая. Широкие проходы продолжают рваться.
|
||||
- Поднять `write_timeout` до согласованного с `foldTimeout` — дёшево, но
|
||||
худший случай (64 МиБ) всё равно минуты, и молчание `accessLog` остаётся.
|
||||
Это лечит симптом.
|
||||
- Оставить как есть — широкие проходы продолжают рваться.
|
||||
|
||||
## Рекомендация
|
||||
Вариант (а) решает причину и попутно снимает две смежные дыры: параллельные
|
||||
доставки одной автоматизации перестают гонять наследование слоя (сейчас вторая
|
||||
может не найти слоя первой и уйти в `failed`), и доставка, застрявшая в
|
||||
`pending` из-за сбоя записи, наконец кем-то подбирается.
|
||||
|
||||
**(а).** Единственный вариант, который решает причину, а не симптом, и попутно
|
||||
снимает две смежные находки. Он же приближает `reindex`: подбор `pending` при
|
||||
старте — его половина.
|
||||
## Что делать
|
||||
|
||||
1. Воркер свёртки: одна горутина, очередь идентификаторов доставок, обработка
|
||||
**строго в порядке журнала** (`received_at`, `id`) — от этого зависит
|
||||
наследование слоя и воспроизводимость.
|
||||
2. Приём отвечает `200` после архивации и вставки доставки; свёртку ставит в
|
||||
очередь. Очередь переполнена — доставка остаётся `pending`, это не отказ.
|
||||
3. Подбор `pending` при старте, тем же путём. Это половина `reindex`, поэтому
|
||||
код должен быть общим с ним, а не соседним.
|
||||
4. Остановка сервиса дожидается текущей доставки: свёртка — одна транзакция,
|
||||
рвать её нечем, но очередь надо дренировать осознанно.
|
||||
5. Метка «доставка ждала свёртки дольше N» — в наблюдаемость, чтобы отставание
|
||||
воркера было видно до того, как оно станет отставанием на сутки.
|
||||
6. Тесты: порядок журнала соблюдается при конкурентных доставках; `pending`
|
||||
подбирается при старте; отмена контекста не оставляет половинчатого
|
||||
состояния; `task verify:archive` даёт то же состояние.
|
||||
|
||||
## Что стоит без решения
|
||||
|
||||
@@ -75,6 +84,9 @@ client: elapsed=501ms err=EOF
|
||||
широких доставках. Данные при этом не теряются — тело ложится в архив **до**
|
||||
свёртки.
|
||||
|
||||
Связано: [reindex-iz-arhiva](reindex-iz-arhiva.md),
|
||||
[stats-nablyudaemost](stats-nablyudaemost.md) — метка «ответ не уложился в
|
||||
таймаут» должна попасть туда.
|
||||
## Связано
|
||||
|
||||
- [reindex-iz-arhiva](reindex-iz-arhiva.md) — подбор `pending` это её половина;
|
||||
делать одним кодом.
|
||||
- [stats-nablyudaemost](stats-nablyudaemost.md) — метка «ответ не уложился в
|
||||
таймаут» и отставание воркера должны попасть туда.
|
||||
|
||||
Reference in New Issue
Block a user