Initialize
Continous integration / Tests (push) Canceled after 0s
Testing clients / Build beanstalkd (push) Canceled after 0s
Continous integration / Docker build (push) Canceled after 0s
Testing clients / Test Pheanstalk PHP (push) Canceled after 0s
Testing clients / Test Greenstalk Python (3.9) (push) Canceled after 0s
Testing clients / Test Pystalk Python (3.10) (push) Canceled after 0s
Continous integration / Tests (push) Canceled after 0s
Testing clients / Build beanstalkd (push) Canceled after 0s
Continous integration / Docker build (push) Canceled after 0s
Testing clients / Test Pheanstalk PHP (push) Canceled after 0s
Testing clients / Test Greenstalk Python (3.9) (push) Canceled after 0s
Testing clients / Test Pystalk Python (3.10) (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# 01. Контракты И Baseline
|
||||
|
||||
Статус: не начат. Зависимости: нет.
|
||||
|
||||
## Цель
|
||||
|
||||
До изменения модели исполнения зафиксировать проверяемые границы совместимости, интерфейсы процессов и условия сравнения производительности. Принятое архитектурное направление не является утверждением всех деталей ниже.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Сопоставить `doc/protocol.txt` с `prot.c`, `conn.c`, `job.c`, `tube.c` и WAL. Зафиксировать значимые расхождения кода и документации, не исправляя их попутно без отдельного решения.
|
||||
2. Описать роли supervisor, frontend, owner; определить число frontend и способ принятия соединений. Не создавать центрального диспетчера всех queue-операций без измерения его предела.
|
||||
3. Определить opt-in нового режима, конфигурацию топологии и совместимость со старым запуском, TCP/Unix sockets, socket activation, сменой пользователя и сигналами.
|
||||
4. Снять baseline существующей версии: CPU, throughput, latency, память и WAL I/O. Сохранить воспроизводимые команды и параметры.
|
||||
5. Подготовить таблицу состояний сессии, ожидания reserve, передачи ответа, аварии frontend и owner. Указать точки изменения состояния и подтверждения операции.
|
||||
|
||||
## Решения До Реализации
|
||||
|
||||
| Вопрос | Ограничение для решения | Где реализуется |
|
||||
| --- | --- | --- |
|
||||
| Переход и legacy | Выбрать сохранение отдельного legacy с opt-in либо согласованный переход на новую архитектуру. Два режима не являются уже утверждённым обязательством; новый режим с одним owner не равен прежнему серверу по возможностям | 04, 05, 06, 07 |
|
||||
| Multi-watch reserve | Не выбирать первую tube и не выдавать `TIMED_OUT` как будто очередь пуста. Выбрать документированный отказ/закрытие или явно согласованное расширение; не объявлять такой ответ стандартом 1.13 | 04 |
|
||||
| Наблюдение одной tube, резервации нескольких | Сохранить `reserve-job`, смену watch list и проверки TTR/`DEADLINE_SOON` по всем резервациям сессии; дополнительное ограничение требует отдельного согласования | 03, 04 |
|
||||
| Неизвестный результат мутации | Не повторять `put` автоматически. Определить закрытие соединения и судьбу сессии при разрыве IPC; request ID не даёт durable exactly-once | 03, 06 |
|
||||
| Сбой владельца | Выбрать политику затронутых TCP-сессий; безопасная исходная стратегия: закрыть затронутые сессии и очистить их ссылки у остальных владельцев. Не продолжать старые резервации после replay как будто аварии не было | 03, 05, 06 |
|
||||
| Формат топологии | Фиксировать hash/version/seed при наличии, число разделов, карту, slot IDs, fingerprint. Проверять до открытия WAL для записи | 02, 05 |
|
||||
| Job ID | Decimal uint64 на wire; уникальность, маршрутизация, порядок внутри tube, переполнение и частичные перезапуски. Определить импорт старых ID | 04, 05 |
|
||||
| Старый WAL | Выбрать явный offline import либо контролируемый отказ нового режима; исходные данные не изменять автоматически. Если legacy сохраняется, он должен читать прежние данные | 05 |
|
||||
| Диагностика | Определить смысл `pid`, `id`, `uptime`, `rusage-*`, binlog-полей и счётчиков после частичного перезапуска | 04, 06 |
|
||||
| Платформы | Определить поддерживаемые платформы новой архитектуры и политику остальных; если legacy сохраняется, его существующие платформы не регрессируют. Linux-first допустим только как явная граница | 03, 06, 07 |
|
||||
| Численные лимиты | Утвердить лимиты IPC/body buffering, сроки очистки умерших сессий, restart policy и критерии производительности | 03, 06, 07 |
|
||||
|
||||
Открытые решения оформлять в соответствующем документе как выбранный контракт с обоснованием. Внешние ограничения сверх одной наблюдаемой tube выносить на согласование, а не выбирать неявно в коде.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Матрица: одна/много tubes, один/много клиентов, короткие/крупные bodies, ready/delayed workload, WAL off/on, обычный fsync и `-f 0`.
|
||||
- Генератор нагрузки не должен насыщать CPU раньше сервера. Фиксировать CPU affinity, оборудование, ОС, compiler/CFLAGS, размеры данных и семя распределения.
|
||||
- Измерять завершённый lifecycle `put -> reserve -> delete` и отдельные операции; точно определить единицу throughput.
|
||||
- Выполнить профилирование: обход tubes в `next_awaited_job` и `soonest_delayed_job`, системные вызовы, копирование, WAL. Не считать кандидатов доказанными bottlenecks без профиля.
|
||||
- Не менять алгоритмы исходной версии в рамках снятия baseline.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Для каждой строки таблицы есть выбранное поведение либо явно блокируемая ею реализация; блокирующие решения закрыты до начала зависимых изменений.
|
||||
- Сценарии transient multi-watch, смены tube с живой резервацией и `reserve-job` другой tube присутствуют в тест-плане.
|
||||
- Есть спецификация запуска, топологии, session identity, command ownership и ошибок.
|
||||
- Есть сохранённый baseline и заранее заданные критерии сравнения для эпика 07.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`main.c`, `util.c:optparse`, `net.c`, `serv.c`, `prot.c:dispatch_cmd`, `conn.c`, `dat.h`, `Makefile`, `testserv.c`.
|
||||
@@ -0,0 +1,56 @@
|
||||
# 02. Владение Динамическими Tubes
|
||||
|
||||
Статус: не начат. Зависимости: 01.
|
||||
|
||||
## Цель
|
||||
|
||||
Однозначно назначать процесс всем возможным именам tubes без постоянного реестра самих очередей и без конкурентного claim при каждом создании.
|
||||
|
||||
## Контракт
|
||||
|
||||
```text
|
||||
partition = stable_hash(validated_tube_name) % PARTITION_COUNT
|
||||
owner_slot = partition_map[partition]
|
||||
```
|
||||
|
||||
- Hash работает с точными байтами имени по протоколу: без изменения регистра, locale-зависимой обработки и рандомизации между процессами.
|
||||
- `PARTITION_COUNT` фиксирован и не равен числу живых процессов по определению. Число разделов, алгоритм и карта выбираются в 01.
|
||||
- Owner slot не является PID. Перезапуск процесса не меняет принадлежность имён.
|
||||
- Все процессы подтверждают одинаковые fingerprint/version топологии до обслуживания запросов.
|
||||
- Данные с несовместимой картой не открываются для записи. Отсутствующая или повреждённая метаинформация не должна вызывать создание новой карты поверх существующих данных.
|
||||
- Без WAL карта всё равно должна быть единой для живого логического сервера. При полном запуске без сохранённых данных допустима новая явно заданная конфигурация.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Реализовать проверку и загрузку карты разделов, стабильный router и тестовые векторы hash.
|
||||
2. Отделить разрешение владельца от локального поиска/создания объекта. `find` не имеет побочного эффекта `create`.
|
||||
3. Оставить `tube_find_or_make` или его минимально изменённый эквивалент внутри владельца. Реестр локальных tubes содержит только его объекты.
|
||||
4. Обрабатывать `use`, `watch`, `ignore` и disconnect через ссылки логических сессий. Подтверждать изменение клиентского состояния после корректного изменения ссылок; предусмотреть rollback частичного attach.
|
||||
5. Сохранять tube пока есть job любого живого состояния или удерживающая клиентская/системная ссылка. Удалять после освобождения последней ссылки без изменения карты.
|
||||
6. Определить `default`: одна логическая tube на всём сервере у вычисленного владельца, не отдельная пользовательская очередь в каждом процессе. Сохранить штатную системную ссылку, если она нужна для эквивалентности текущему `prot_init`.
|
||||
7. При WAL replay создавать tubes у соответствующего владельца; чужое имя в WAL должно выявлять неверную топологию/раскладку данных, а не тихо создавать вторую tube.
|
||||
|
||||
## Сценарий Одновременного Создания
|
||||
|
||||
Два frontend получают `use emails` и `watch emails`. Оба вычисляют один slot. Его event loop обрабатывает сообщения последовательно: первое создаёт tube, второе находит ту же tube и добавляет свою ссылку. Дополнительная distributed lock или таблица claims на имя не нужна.
|
||||
|
||||
Эксклюзивный claim требуется для самого owner slot и обеспечивается supervisor из эпика 06.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Hash-векторы одинаковы между процессами и перезапусками; тесты включают допустимые граничные имена, регистр и максимальную длину.
|
||||
- Параллельные `use`/`watch` одной новой tube через разные frontend создают один объект у одного владельца и корректные счётчики ссылок.
|
||||
- `stats-tube`/`pause-tube` несуществующего имени возвращают `NOT_FOUND` и не оставляют объект.
|
||||
- Tube с reserved job не удаляется после ухода остальных клиентов.
|
||||
- Пустая обычная tube удаляется после последней ссылки; повторное создание попадает в тот же slot.
|
||||
- `default` представлен один раз в `list-tubes`; подключения не создают локальные копии в остальных owners.
|
||||
- Авария frontend освобождает его ссылки; запоздалый attach старого поколения не воскрешает сессию.
|
||||
- Подмена hash, карты или числа разделов при существующих данных приводит к безопасному отказу запуска, а не перемаршрутизации.
|
||||
|
||||
## Не Делать
|
||||
|
||||
Никакого `hash(name) % live_owners`, переноса очередей при сбое, автоматического распределения новых tubes по текущей нагрузке или долговечного каталога пустых tubes.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`tube.c`, `conn.c:on_watch/on_ignore`, `prot.c:prot_init/dispatch_cmd/prot_replay`, `dat.h:Tube`, новый минимальный модуль топологии при необходимости.
|
||||
@@ -0,0 +1,45 @@
|
||||
# 03. IPC И Логические Сессии
|
||||
|
||||
Статус: не начат. Зависимости: 01, интерфейсы маршрутизации 02.
|
||||
|
||||
## Цель
|
||||
|
||||
Отделить TCP-соединение от состояния consumer у владельцев. Обеспечить межпроцессный обмен без общих указателей, неограниченных буферов и неявного повторения команд.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Реализовать неблокирующий IPC на Unix domain sockets с явным framing; выбрать stream или message-oriented транспорт с учётом крупных bodies и платформ.
|
||||
2. Определить versioned envelope: topology fingerprint, поколения endpoints, session ID, request ID, opcode, размеры метаданных и body. Не сериализовать C-структуры с padding/указателями как wire contract.
|
||||
3. Ввести session identity, уникальную в пределах поколения frontend, и идентичность запуска supervisor. Защититься от повторного использования PID/FD и запоздалых сообщений.
|
||||
4. Хранить у frontend транспортное состояние, `use`, watch list и маршруты резерваций. Хранить у владельцев логические ссылки, ожидания и принадлежащие сессиям jobs.
|
||||
5. Сохранить порядок команд и ответов на одном клиентском соединении, включая pipelined input. Не считать IPC request ID разрешением менять порядок протокола.
|
||||
6. Ввести лимиты на размеры frames, входящие запросы, ожидающие ответы и body buffering. Превышение лимитов вызывает backpressure/задокументированный отказ, а не переполнение памяти.
|
||||
7. Определить отмену reserve и detach сессии при disconnect, half-close, IPC failure и смерти frontend. Повторный detach должен быть безопасен; старый attach не должен отменять cleanup.
|
||||
8. Определить управление памятью ответа: тело job, передаваемое медленному клиенту, остаётся доступным после timeout/delete исходного job. Копия или явная pin/reference имеют ограниченный срок жизни.
|
||||
9. Не повторять мутации после неизвестного результата. Если предусмотрены повторы в живом канале, обеспечить дедупликацию в ограниченном окне с определённым моментом освобождения записей; не обещать сохранение dedup после crash без отдельного журнала.
|
||||
|
||||
## Межвладельческие Резервации Одной Сессии
|
||||
|
||||
Ограничение одной наблюдаемой tube не исключает сохранённые резервации у нескольких владельцев. Это возникает после смены watch list или `reserve-job`.
|
||||
|
||||
- Owner остаётся источником истины о job и его TTR.
|
||||
- При ожидании нового reserve необходимо учесть ближайший deadline всех резерваций сессии, а не только текущей tube.
|
||||
- Спроектировать обновления после `touch`, release/delete/bury, timeout и новой резервации, чтобы frontend/coordinator не принимал решения по устаревшему deadline.
|
||||
- Описать упорядочивание событий job available, timeout, `DEADLINE_SOON`, disconnect. Только один из конкурирующих результатов завершает ожидающий запрос.
|
||||
- Согласовать cleanup остальных владельцев при гибели одного owner и закрытии затронутой клиентской сессии.
|
||||
|
||||
Это координация состояния одной сессии, а не межшардовый выбор минимального priority из нескольких watch tubes. Смешивать эти задачи нельзя.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Тесты partial read/write, объединённых frames, некорректных длин, oversized body и разрыва IPC посреди сообщения проходят без повреждения состояния.
|
||||
- Старые поколения, неизвестные session IDs и несоответствующая топология отклоняются до мутации.
|
||||
- Медленный client/frontend не вызывает неограниченного роста памяти или блокировки всех owners.
|
||||
- Disconnect во время `put`, ожидания reserve, выдачи job и передачи большого body корректно освобождает ресурсы.
|
||||
- Авария frontend очищает все его сессии и резервации за установленное в 01 время; явно отличать завершившийся процесс от временно медленного.
|
||||
- Потеря ответа на `put` не вызывает скрытого второго `put`; неоднозначный результат виден как ошибка соединения по контракту.
|
||||
- Переключение tube при живой резервации, `reserve-job` другой tube и последующие `touch`/`DEADLINE_SOON` проверены через разные owners.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`dat.h:Conn/Socket/Job`, `conn.c`, `prot.c:conn_process_io/conn_timeout/reply_job`, платформенный event loop. Новый IPC-модуль должен иметь самостоятельные тесты framing и жизненного цикла.
|
||||
@@ -0,0 +1,61 @@
|
||||
# 04. Queue Engine И Протокол
|
||||
|
||||
Статус: не начат. Зависимости: 02, 03; ID/WAL интегрируются с 05.
|
||||
|
||||
## Цель
|
||||
|
||||
Все операции над заданиями исполняются владельцем соответствующей tube; frontend сохраняет протокольный контракт без общей памяти и центрального глобального планировщика.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Отделить parsing/response I/O от мутаций queue engine в `prot.c`. Сохранить существующие heaps, списки и однотредовое исполнение владельца, не переписывая их на shared memory.
|
||||
2. Удалить зависимость владения job от локального `Conn*` frontend. Использовать логическую сессию и локальное owner-side состояние.
|
||||
3. Сделать глобальные реестры и счётчики локальными роли процесса. Один процесс-владелец может сохранить process-local globals, если они не смешиваются с frontend; не вводить контейнеры/абстракции без необходимости.
|
||||
4. Перенести delayed jobs, pause и TTR в timer loop владельца. Согласовать reserve timeout и safety margin с управлением сессиями из 03.
|
||||
5. Реализовать маршрутизацию всех команд по таблице; подтвердить завершение каждой команды только в согласованной точке состояния/WAL.
|
||||
6. Сохранить проверки числовых диапазонов, framing body/CRLF, ошибки нехватки памяти и порядок ответов.
|
||||
7. Реализовать явно выбранную реакцию на multi-watch reserve. Не запретить промежуточный `watch target` при подключении с `default`.
|
||||
|
||||
## Маршрутизация
|
||||
|
||||
| Команды | Источник владельца/исполнитель |
|
||||
| --- | --- |
|
||||
| `use`, `watch`, `ignore` | Имена tubes и изменение ссылок сессии |
|
||||
| `put`, `peek-ready`, `peek-delayed`, `peek-buried`, `kick` | Текущая `use` tube |
|
||||
| `reserve`, `reserve-with-timeout` | Единственная наблюдаемая tube плюс состояние deadlines сессии |
|
||||
| `peek`, `delete`, `release`, `bury`, `touch`, `reserve-job`, `kick-job`, `stats-job` | Job ID; не текущая `use`/watch tube |
|
||||
| `pause-tube`, `stats-tube` | Явно указанное имя |
|
||||
| `list-tube-used`, `list-tubes-watched` | Подтверждённое состояние сессии frontend |
|
||||
| `list-tubes`, `stats` | Сбор данных владельцев/frontend по определённому контракту |
|
||||
| `quit` | Закрытие клиентской сессии и cleanup у всех затронутых owners |
|
||||
|
||||
## Совместимость
|
||||
|
||||
- Priority/FIFO сохраняются внутри tube. Текущий `job_pri_less` использует `(priority, id)`; изменение ID требует доказательства эквивалентности или отдельного ordering field.
|
||||
- `reserve-job` не привязывается к watch list и сохраняет выбор ready/buried/delayed job по ID.
|
||||
- `delete` чужой reserved job недопустим, но ready/delayed/buried jobs доступны по прежним правилам. `release`, `bury`, `touch` проверяют сессию-владельца резервации.
|
||||
- Disconnect возвращает резервации в очереди; timeout во время передачи body не приводит к use-after-free.
|
||||
- `use` не меняет watch list, а `ignore` не освобождает уже зарезервированные jobs.
|
||||
- Недоступный owner не трактуется как пустая tube или отсутствующий job. Ответы `NOT_FOUND`/`TIMED_OUT` не подменяют отказ инфраструктуры.
|
||||
|
||||
## Статистика
|
||||
|
||||
- Суммировать только действительно аддитивные job/command counters с определённым владельцем каждого счётчика.
|
||||
- Connection/producer/worker/waiting counters считают уникальные клиентские сессии, а не IPC endpoints и не число owner-side копий.
|
||||
- `list-tubes` объединяет реальные объекты, не все возможные имена, и не дублирует `default`.
|
||||
- Определить согласованность snapshot при конкурентных изменениях. Не обещать атомарный глобальный snapshot без реализации барьера.
|
||||
- Для `pid`, server `id`, `uptime`, `rusage-*` и binlog-полей применять контракт 01. Номера сегментов разных WAL нельзя бессмысленно суммировать.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Каждая строка routing table имеет успешные, ошибочные и межвладельческие тесты, где применимо.
|
||||
- Полный lifecycle ready/reserved/delayed/buried и приоритеты проходят на двух и более owners.
|
||||
- `use` одной tube при watch другой корректен, в том числе если owners различны.
|
||||
- Один consumer может держать несколько jobs; смена watch/`reserve-job` не теряет старые резервации.
|
||||
- Нулевая/положительная задержка reserve, safety margin, `touch`, pause/unpause и disconnect соответствуют выбранному контракту.
|
||||
- Гонки reserve vs delete, timeout vs touch, pause vs reserve и disconnect vs reply не дают двух активных резерваций или двух ответов.
|
||||
- Исходный `make check` используется по матрице совместимости 01. Если выбран отдельный legacy-режим, он проходит весь прежний набор, включая multi-tube; ограничение нового режима не переносится на legacy.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`prot.c`, `conn.c`, `job.c`, `tube.c`, `dat.h`, `testserv.c`, `testjobs.c`, `testheap.c`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# 05. WAL, Job ID И Восстановление
|
||||
|
||||
Статус: не начат. Зависимости: 01, 02; интеграция 03, 04.
|
||||
|
||||
## Цель
|
||||
|
||||
Изолировать журналы владельцев и обеспечить восстановление без пересечения ID, появления двух копий tube или незаметной потери совместимости данных.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Определить layout общего data root, метаданных топологии и отдельных каталогов owner slots. Каждый WAL имеет одного writer и собственную блокировку.
|
||||
2. Проверять топологию и layout до любых изменяющих операций с журналами; создавать начальные метаданные атомарно с необходимой durability, если сервер запускается с пустыми данными.
|
||||
3. Задать формат decimal uint64 job ID и маршрутизацию к владельцу без глобального mutable каталога каждого job на критическом пути, если выбранная схема это позволяет.
|
||||
4. Решить восстановление генератора ID при частичном restart: чтения максимального ID среди живых jobs недостаточно, если большие ID уже удалены. Учитывать старые сообщения/сессии и generation fencing; документировать срок гарантий уникальности.
|
||||
5. Определить переполнение и исчерпание диапазона ID: контролируемый отказ вместо wraparound и коллизий.
|
||||
6. Сохранить порядок FIFO внутри tube при изменении ID. Если вводится отдельный sequence, определить момент выдачи и запись/восстановление; не изменять порядок поступления относительно текущей версии без решения.
|
||||
7. Запускать replay каждого owner отдельно. До готовности replay его partition space недоступен; frontend не перенаправляет операции к соседям.
|
||||
8. Восстанавливать jobs в соответствии с текущей семантикой WAL, не считать клиентские резервации пережившими restart. Старые frontend-сессии не продолжают работу поверх восстановленных jobs.
|
||||
9. Проверить compaction, segment rotation, file references, disk-full/short write/fsync errors и взаимодействие с подтверждением команд.
|
||||
10. Реализовать выбранную в 01 политику старого WAL: отдельный offline import с сохранением оригинала либо явный отказ нового режима. Если отдельный legacy сохраняется, он читает прежний формат.
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Нельзя совместно писать независимыми owners в существующий binlog-каталог, даже если убрать `waldirlock`.
|
||||
- Tube descriptor не становится персистентным объектом: имя восстанавливается из живых jobs. Пустые клиентские tubes не обязаны переживать restart.
|
||||
- Частичный перезапуск без WAL теряет данные только соответствующего owner по заявленному контракту; это нельзя выдавать за восстановление или HA.
|
||||
- С `-b` границы потери данных определяются реальной записью и настройками fsync. Не требовать отсутствия любых потерь при `-F` и не ослаблять `-f 0` под видом ускорения.
|
||||
- При изменении `Jobrec` следовать процедуре `Walver` в `dat.h`, включая чтение старых версий. Многопроцессность сама по себе не требует изменения `Jobrec`.
|
||||
- Онлайн-миграция и изменение карты не входят в эпик. Увеличение числа slots с переназначением partitions требует отдельной offline-процедуры, не простого изменения config.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Два owners одновременно записывают задания, используют разные WAL и не пересекающиеся ID.
|
||||
- После удаления всех jobs и частичного restart генерация ID не создаёт опасных коллизий по утверждённому контракту; тест включает запоздалые сообщения старого поколения.
|
||||
- Неизменная топология восстанавливает jobs в правильных tubes и owners; несовместимая карта не меняет существующие файлы при отказе запуска.
|
||||
- Полный/частичный restart проверен с ready, delayed, buried и ранее reserved jobs; внешние сессии не сохраняют ложное владение восстановленными jobs.
|
||||
- Ошибка одного WAL не повреждает файлы другого. Реакция логического сервера соответствует 01/06.
|
||||
- Проверены crash windows до/после записи и подтверждения, compaction, rotation, недостаток места и повреждённый журнал.
|
||||
- Старые данные остаются пригодны для legacy либо импортируются явным инструментом согласно выбранной политике; исходник не уничтожается автоматически.
|
||||
- Документированы ID layout, topology metadata, срок гарантий ID, WAL compatibility и ограничения durability.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`job.c:make_job_with_id/next_id/job_pri_less`, `dat.h:Jobrec/Walver/Wal/File`, `walg.c`, `file.c`, `serv.c:srv_acquire_wal`, `prot.c:prot_replay`, WAL-тесты в `testserv.c`.
|
||||
@@ -0,0 +1,47 @@
|
||||
# 06. Supervisor И Эксплуатация
|
||||
|
||||
Статус: не начат. Зависимости: 02, 03; итоговая интеграция 04, 05.
|
||||
|
||||
## Цель
|
||||
|
||||
Сделать многопроцессный сервер управляемым сервисом с единой конфигурацией, предсказуемым запуском и корректной реакцией на сбои.
|
||||
|
||||
## Задачи
|
||||
|
||||
1. Ввести supervisor, запускающий owners/frontend с явно заданными ролями, slot IDs, generations и топологией.
|
||||
2. Обеспечить один активный процесс на slot. Перед заменой подтвердить завершение прежнего процесса; PID reuse не является подтверждением его идентичности.
|
||||
3. Организовать startup barrier: проверка config, locks и топологии, восстановление WAL, IPC handshake, готовность к клиентским операциям.
|
||||
4. Корректно закрывать лишние унаследованные listening/client/IPC/WAL descriptors. Не наследовать живые jobs/сессии через fork как способ совместного владения данными.
|
||||
5. Интегрировать выбранные CLI/config, `-u`, TCP/Unix sockets и socket activation. Проверить границы привилегий и права на IPC/data root.
|
||||
6. Реализовать согласованную обработку `SIGUSR1` drain и остановки. Drain прекращает новые `put` во всём логическом сервере, но не означает остановку выдачи существующих jobs.
|
||||
7. Ввести restart policy с ограничением частоты/числа попыток и диагностикой. Во время недоступности slot его имена не передаются другим owners.
|
||||
8. Определить поведение при смерти supervisor: оставшиеся процессы не продолжают принимать изменения без действующей управляющей эпохи; исключить запуск второго независимого сервера поверх тех же slots.
|
||||
9. Обеспечить логи с role/slot/generation и метрики IPC backlog, restart count, owner readiness, загрузки и WAL ошибок.
|
||||
10. Обновить эксплуатационную документацию: запуск, проверки готовности, restart, drain, резервное копирование/восстановление при остановленном сервере, запрет несогласованного изменения карты.
|
||||
|
||||
## Матрица Отказов
|
||||
|
||||
| Событие | Требуемое свойство |
|
||||
| --- | --- |
|
||||
| Смерть frontend | Владельцы освобождают ссылки/ожидания/резервации всех его сессий; старое поколение больше не принимается |
|
||||
| Смерть owner | Затронутые сессии обрабатываются по контракту 01; очистка связанных сессий у остальных owners; перезапуск только того же slot |
|
||||
| Разрыв IPC | Неизвестные результаты не повторяются автоматически; endpoint/session fencing исключает поздние изменения |
|
||||
| Смерть supervisor | Нет бесконтрольных orphan writers и двух поколений активного сервера |
|
||||
| Ошибка WAL | Явная диагностика и согласованная политика отказа; не тихое переключение на другой owner |
|
||||
| `SIGUSR1` | Глобально согласованный drain, включая owners/frontend, перезапущенные во время drain |
|
||||
| Остановка | Нет новых принятых операций после согласованного барьера; bounded shutdown, явная политика незавершённых ответов |
|
||||
|
||||
## Приёмка
|
||||
|
||||
- Запускаются один и несколько owners/frontend с одинаковой картой; ошибочная конфигурация не оставляет работающих дочерних процессов и занятых sockets.
|
||||
- Попытка второго владельца slot отвергается как с WAL, так и без WAL.
|
||||
- Kill/restart владельца сохраняет маршруты остальных tubes и не создаёт дубль упавшего slot.
|
||||
- Затронутые клиенты получают документированный отказ/закрытие, а не `NOT_FOUND` из-за отсутствующего процесса.
|
||||
- После перезапуска во время drain новый процесс не принимает `put` до снятия/завершения drain по контракту.
|
||||
- Проверены supervisor/frontend/owner crashes, частичный startup failure, сигналы и отсутствие утечек FD/zombie-процессов.
|
||||
- Запуск и платформы соответствуют выбранной в 01 политике перехода. Если legacy сохраняется, его startup и поддерживаемые платформы не регрессируют; неподдерживаемая платформа нового режима выдаёт явный отказ сборки/запуска.
|
||||
- Обновлены руководство и примеры запуска; статусы/метрики позволяют определить недоступный slot без анализа PID по догадкам.
|
||||
|
||||
## Точки Кода
|
||||
|
||||
`main.c`, `serv.c`, `net.c`, `util.c`, платформенные event backends, `Makefile`, `doc/beanstalkd.ronn`, `README.md`, `testserv.c`.
|
||||
@@ -0,0 +1,60 @@
|
||||
# 07. Приёмка И Производительность
|
||||
|
||||
Статус: не начат. Baseline зависит от 01; итоговая приёмка зависит от 02-06.
|
||||
|
||||
## Цель
|
||||
|
||||
Доказать корректность и полезность многопроцессного режима воспроизводимыми тестами. Наличие нескольких PID или рост общей загрузки CPU сами по себе не являются приёмкой.
|
||||
|
||||
## Функциональная Матрица
|
||||
|
||||
| Область | Обязательные сценарии |
|
||||
| --- | --- |
|
||||
| Регрессии | `make`, `make check` по матрице 01; полный прежний набор при сохранении legacy; новый режим с 1 и несколькими owners |
|
||||
| Создание tube | Одновременные `use`/`watch` через разные frontend, delete/recreate, единственный `default`, отсутствие создания на `stats-tube` |
|
||||
| Routing | Все команды из 04; `use` и watch на разных owners; операции по ID независимо от текущей tube |
|
||||
| Lifecycle | Ready/reserved/delayed/buried, kick/kick-job, приоритеты и FIFO, несколько резерваций на сессию |
|
||||
| Watch | `watch target` перед `ignore default`; отказ multi-watch reserve; смена tube с живыми резервациями |
|
||||
| Сессии | `reserve-job` другого owner, touch/delete старых резерваций, чужой reserved job, cleanup всех owners |
|
||||
| Таймеры | Reserve timeout 0/positive, TTR, `DEADLINE_SOON`, delay, pause/unpause; гонки на границах времени |
|
||||
| I/O | Partial requests/replies, pipelining, half-close, медленный client, large body, broken IPC, некорректные frame lengths |
|
||||
| Ресурсы | IPC backpressure, OOM, ограниченные buffers, утечки памяти/FD после многократного reconnect |
|
||||
| Отказы | Kill frontend/owner/supervisor, restart generations, stale messages, duplicate requests при наличии retry |
|
||||
| WAL | Раздельные logs, partial/full restart, удалённые максимальные ID, compaction, rotation, disk full, crash windows |
|
||||
| Эксплуатация | Drain, startup failure, невозможность двух writers, несовместимая карта, старые данные |
|
||||
| Статистика | Нет двойного счёта сессий, один `default`, корректные process/binlog поля, недоступный owner |
|
||||
|
||||
## Свойства Для Проверки
|
||||
|
||||
- Один job не имеет двух действующих резерваций, но обработка внешним worker может повториться после TTR. Не объявлять корректные TTR redeliveries дубликатами сервера.
|
||||
- Один ожидающий reserve завершается ровно одним исходом либо закрытием соединения; поздний IPC-ответ не меняет этот исход.
|
||||
- Зафиксированный набор полностью завершённых операций согласуется с итоговым состоянием при quiescent проверке. Не требовать атомарности произвольного распределённого `stats` snapshot.
|
||||
- После завершённого cleanup не остаются ссылки умершей сессии; сообщение старого поколения не создаёт их заново.
|
||||
- Успешные операции не теряются сверх заявленных гарантий WAL/fsync. Неизвестный результат при обрыве соединения учитывается отдельно от подтверждённого успеха.
|
||||
- Недопустимая топология отвергается без модификации исходных данных.
|
||||
|
||||
## Нагрузочная Матрица
|
||||
|
||||
1. Сравнить исходную версию, новый режим с одним owner, новый режим с 2/4/доступным числом owners и независимые исходные экземпляры как ориентир стоимости IPC.
|
||||
2. Выполнить равномерную нагрузку по многим tubes, одну горячую tube и перекошенное распределение. Отдельно измерить создание/удаление множества короткоживущих tubes.
|
||||
3. Варировать число frontend и клиентов; показать, не стал ли frontend/supervisor/генератор нагрузки новым bottleneck.
|
||||
4. Повторить сравнения для WAL off/on, одинаковых `-f`/`-F`, размера body, queue depth и смеси команд.
|
||||
5. Измерять throughput завершённых lifecycle и отдельных команд, p50/p95/p99 latency, CPU каждого процесса, RSS/суммарную память, IPC traffic/backlog, disk throughput/fsync latency.
|
||||
6. Использовать прогрев, несколько повторов, одинаковые параметры сборки и инфраструктуры. Публиковать разброс и сырые результаты, а не только лучший запуск.
|
||||
7. Сопоставить с численными критериями, зафиксированными в 01 после baseline и до итоговых тестов. Если пороги не выполнены, представить профиль и причину; эпик не считать пройденным автоматически.
|
||||
|
||||
## Средства
|
||||
|
||||
- Существующие команды: `make`, `make check`, `make bench`. Последняя является набором микробенчмарков, а не end-to-end испытанием.
|
||||
- Добавить Unix integration harness для запуска ролей, kill/restart и инъекции отказов; переиспользовать `ct/` и существующие подходы `testserv.c`, где это сохраняет ясность.
|
||||
- Для ошибок памяти использовать доступные sanitizers или эквивалентные средства на поддерживаемой платформе. Они не заменяют проверки межпроцессной семантики.
|
||||
- Не завязывать таймерные тесты только на короткие sleeps: использовать синхронизацию/наблюдаемые события и разумные временные допуски, чтобы избежать flaky результатов.
|
||||
|
||||
## Итоговые Артефакты
|
||||
|
||||
- Автоматические тесты и воспроизводимые команды их запуска.
|
||||
- Отчёт по compatibility matrix с явными ограничениями нового режима и политикой старых данных.
|
||||
- Отчёт по производительности с baseline, конфигурациями, численными результатами и выводом о bottlenecks.
|
||||
- Проверенные эксплуатационные инструкции и перечень оставшихся ограничений: одна tube последовательна, cross-shard watch reserve и live migration отсутствуют.
|
||||
|
||||
Реализация считается завершённой только после выполнения общей приёмки из [00-overview.md](00-overview.md), а не после успешного happy path на двух процессах.
|
||||
Reference in New Issue
Block a user