175 lines
16 KiB
Markdown
175 lines
16 KiB
Markdown
# Автономное тройное ревью П39 · май 2021 · «Блокировки и конкуренция»
|
||
|
||
Статус: **авторское тройное ревью пройдено, затем пакет принят независимым
|
||
редактором в выпусковой набор**. Revision-модуль содержит ровно три
|
||
стабильных slug:
|
||
|
||
- <code>editorial-2021-05-practice-distributed-locks</code>;
|
||
- <code>editorial-2021-05-mechanism-distributed-locks</code>;
|
||
- <code>editorial-2021-05-field-distributed-locks</code>.
|
||
|
||
В <code>revisions</code> нет <code>date</code>, <code>author</code> или
|
||
подключения registry. Эта авторская партия не меняла
|
||
<code>articles.json</code>, README, очередь, стандарт, package config или Git.
|
||
Созданы только пять разрешённых файлов, перечисленных внизу документа.
|
||
|
||
## Проход 1. Факты, историческая рамка и техника — пройдено
|
||
|
||
| Утверждение или решение | Первичный / официальный источник | Зафиксированная граница |
|
||
| --- | --- | --- |
|
||
| Для исторической точки мая 2021 выбрана линия <code>etcd v3.4</code>: её <code>Lock</code> возвращает key на время владения; unlock или expiry/revoke связанного lease освобождает lock | [etcd v3.4 Concurrency API Reference](https://etcd.io/docs/v3.4/dev-guide/api_concurrency_reference_v3/) | Документация описывает lock внутри etcd. Она не объявляет возвращённый key универсальным числовым fencing token для внешней базы, файла или API. |
|
||
| <code>LeaseGrant</code> получает advisory TTL, а ответ возвращает TTL, выбранный server; без keepalive lease истекает, attached keys удаляются | [etcd v3.4 API Reference](https://etcd.io/docs/v3.4/dev-guide/api_reference_v3/) | Учебные 5000 мс не являются значением TTL для etcd, не проверяют keepalive, clock drift или clock correctness. |
|
||
| Lock сам по себе advisory; sequencer передаётся получателю операции, а получатель проверяет его актуальность и может отвергнуть request | [Mike Burrows, The Chubby lock service for loosely-coupled distributed systems, OSDI 2006](https://research.google/pubs/the-chubby-lock-service-for-loosely-coupled-distributed-systems/) | Chubby — исторический первичный пример boundary, не скрытая реализация fixture и не рекомендация установить этот сервис. |
|
||
| Выбор v3.4 не заносит будущую версию в текст мая: официальный анонс v3.5 датирован 15 июня 2021 года и ретроспективно называет запуск v3.4 августом 2019 года | [Announcing etcd 3.5](https://etcd.io/blog/2021/announcing-etcd-3.5/) | Эта ссылка служит редакторской проверкой датировки; сама статья не ссылается на будущий для мая анонс и не использует API v3.5. |
|
||
|
||
<code>runDistributedLockFixture()</code> — детерминированная state machine
|
||
только на <code>Map</code> и ручном счётчике времени. В ней нет системных
|
||
часов, сети или provider client:
|
||
|
||
1. worker-A получает <code>training-lease-1</code> и token 1 на 5000 мс;
|
||
2. учебный clock переходит к 6000 мс, lease-1 помечается истёкшим, но
|
||
worker-A не считается остановленным;
|
||
3. worker-B получает <code>training-lease-2</code> и token 2;
|
||
4. защищаемый ресурс принимает write worker-B, сохраняет v2 и highest token 2;
|
||
5. поздний write worker-A с token 1 получает
|
||
<code>rejected-stale-fence</code>;
|
||
6. старый release worker-A не снимает текущий lease worker-B;
|
||
7. отдельный намеренно unsafe ресурс без fencing показывает, что token 1
|
||
перезаписал бы v2.
|
||
|
||
Проверены девять assertions: выдача первого lease/token, pause после expiry,
|
||
выдача второго lease/token, принятие v2, отказ stale v1, защита release нового
|
||
lease, сохранение v2, небезопасный контраст без fencing и работа только в
|
||
памяти. Главный технический вывод узкий: **fence помогает только когда
|
||
защищаемый ресурс сам хранит и монотонно проверяет token в своей операции
|
||
записи**. Generic lock не выдан за доказательство безопасности.
|
||
|
||
Не проверялись реальный etcd/Redis/ZooKeeper, provider SDK, cluster,
|
||
keepalive, сеть, clock synchronization, база, файловый storage, HTTP,
|
||
внешний API, нагрузка или provider SLA. Fixture не заявляет exactly-once,
|
||
отмену старого request и корректность реальных часов.
|
||
|
||
Вердикт прохода: **пройден**. Историческая версия и ограничения названы рядом
|
||
с механизмом, а модель не переносит свойства учебной Map на настоящий
|
||
провайдер.
|
||
|
||
## Проход 2. Редактура, глубина и голос М4 — пройдено
|
||
|
||
| Revision | Симптом и цена в первых двух абзацах | Главный вопрос | Объём основного текста |
|
||
| --- | --- | --- | ---: |
|
||
| Практика | worker-A останавливается дольше lease, B уже обновляет отчёт, A может поздно перезаписать v2 | Как до критической секции разделить lifecycle lease, owner, handle и resource-side fence | **10 939** знаков body |
|
||
| Механизм | поздний request получает успешный ответ после нового владельца, поэтому команда ошибочно обвиняет lock provider | Почему token обязан проверять защищаемый ресурс, а не только authority перед началом работы | **10 293** знака body |
|
||
| Полевой разбор | после v2 в лог попадает «успех» старого A; цена — ложный диагноз и повтор той же гонки | Как собрать evidence и отделить stale generation от duplicate, bad release и безусловного write | **9 857** знаков body |
|
||
|
||
- Все статьи начинают с наблюдаемого симптома и цены, затем держат маршрут
|
||
«симптом → причина → проверка → действие → ограничение».
|
||
- В каждой revision есть table с <code>caption</code>/<code>thead</code>,
|
||
figure с самостоятельными <code>alt</code>/<code>figcaption</code>, не
|
||
менее двух технических примеров, нумерованный путь, три первичных или
|
||
официальных источника и явный тестовый interleaving.
|
||
- Голос М4 / мая 2021 продолжает пакеты о транзакции, кешировании и очередях:
|
||
автор называет owner, handle, ресурсную границу и инвариант, но не
|
||
изображает себя владельцем большой distributed platform. Речь короткая и
|
||
предметная: <code>token 1 ≤ highest token 2 → reject</code>, а не
|
||
«блокировка магически защищает данные».
|
||
- Убраны опасные подмены: expiry не назван остановкой процесса; token не
|
||
назван clock; lease key не объявлен готовым fence для внешнего ресурса;
|
||
fencing не отождествлён с idempotency или exactly-once.
|
||
- Заголовки и excerpts обещают ограниченный результат: понять boundary и
|
||
проверить stale write, а не получить универсальный рецепт distributed lock.
|
||
|
||
Вердикт прохода: **пройден**. Тексты лежат в диапазоне 5 000–15 000 знаков и
|
||
развивают T-shape автора от delivery/данных к одному проверяемому контракту
|
||
конкуренции без анахронизмов и техлидской позы 2027 года.
|
||
|
||
## Проход 3. Визуал, fixture и preflight — пройдено в границах пакета
|
||
|
||
- <code>distributed-lock-lease-timeline-2021.svg</code> показывает полный
|
||
interleaving от lease-1/token 1 до reject позднего token 1. После первого
|
||
Sharp-рендера длинная нижняя подпись была разбита на две строки.
|
||
- <code>distributed-lock-fence-boundary-2021.svg</code> отделяет authority от
|
||
ресурса и показывает, где именно хранится highest token. После первого
|
||
рендера нижняя карточка получила две короткие строки и большую высоту.
|
||
- <code>distributed-lock-diagnosis-2021.svg</code> ведёт от evidence packet к
|
||
stale generation, duplicate, resource without compare и bad release. После
|
||
первого рендера перенесены длинная итоговая подпись и строка atomic compare.
|
||
- У всех трёх SVG есть <code>title</code>, <code>desc</code>,
|
||
<code>role="img"</code> и вертикальный viewBox. В исходниках нет
|
||
JavaScript, <code>foreignObject</code>, external URL или data URI; обычный
|
||
XML namespace не является внешним asset.
|
||
|
||
### Фактически выполненные проверки
|
||
|
||
Команды запускались из <code>web/</code> после финальных правок:
|
||
|
||
<pre><code>node --check scripts/upgrade-2021-05.mjs
|
||
npm run audit:draft -- scripts/upgrade-2021-05.mjs
|
||
node scripts/upgrade-2021-05.mjs --verify-fixture
|
||
xmllint --noout \
|
||
public/assets/editorial/2021/distributed-lock-lease-timeline-2021.svg \
|
||
public/assets/editorial/2021/distributed-lock-fence-boundary-2021.svg \
|
||
public/assets/editorial/2021/distributed-lock-diagnosis-2021.svg</code></pre>
|
||
|
||
| Проверка | Реальный результат |
|
||
| --- | --- |
|
||
| <code>node --check</code> | PASS, code 0 |
|
||
| Import-safe export и draft gate | PASS: итоговые **10 939 / 10 293 / 9 857** знаков body; найдены три slug, sections, tables, figures, code, routes, sources и локальные visual assets |
|
||
| In-memory fixture | PASS: все девять assertions истинны; worker-B получил token 2 после expiry A, ресурс принял v2 и отверг поздний token 1, старый release не удалил lease-B |
|
||
| <code>xmllint --noout</code> | PASS, все три SVG — корректный XML |
|
||
| SVG safety scan | PASS: нет <code>script</code>, <code>foreignObject</code>, external asset URL или raster data URI |
|
||
| Sharp mobile preflight | PASS после корректировки длинных подписей: вручную просмотрены финальные PNG **375×740**, **375×781** и **375×844**; clipping, overlap и horizontal overflow внутри схем не обнаружены |
|
||
| Scope/self-review | PASS: созданы только пять разрешённых файлов; registry, <code>articles.json</code>, README, очередь, стандарт, package config, Git и чужие untracked files не менялись |
|
||
|
||
<code>npm run audit:draft</code> завершилась с code 0. npm вывел уже
|
||
существующие предупреждения о пользовательских <code>store-dir</code>,
|
||
<code>cache-dir</code> и <code>public-hoist-pattern</code>; эти настройки не
|
||
относятся к П39 и не менялись.
|
||
|
||
Не запускались strict audit после подключения registry, production build,
|
||
browser, screen reader, CI, deployment или публикация. Static SVG preflight не
|
||
заменяет browser review, accessibility audit и integration test выбранной
|
||
инфраструктуры.
|
||
|
||
## Итог
|
||
|
||
Статус автономного этапа: **тройное авторское ревью пройдено; П39 была готова
|
||
к отдельной интеграционной приёмке**. Commit и push на этом этапе намеренно не
|
||
выполнялись.
|
||
|
||
Созданы ровно пять файлов:
|
||
|
||
1. <code>web/scripts/upgrade-2021-05.mjs</code>;
|
||
2. <code>editorial/reviews/2021-05-draft.md</code>;
|
||
3. <code>web/public/assets/editorial/2021/distributed-lock-lease-timeline-2021.svg</code>;
|
||
4. <code>web/public/assets/editorial/2021/distributed-lock-fence-boundary-2021.svg</code>;
|
||
5. <code>web/public/assets/editorial/2021/distributed-lock-diagnosis-2021.svg</code>.
|
||
|
||
## Независимая интеграционная приёмка
|
||
|
||
Основной редактор 31 июля 2026 года подключил три revision к
|
||
<code>web/data/editorial-revisions.mjs</code>, сохранив базовый
|
||
<code>articles.json</code>, даты и автора архивных записей. В registry стало
|
||
112 revision, строгий аудит проходит 121 из 358 материалов.
|
||
|
||
Независимый факт-чек уточнил одну формулировку до выпуска: в etcd v3.4
|
||
<code>LeaseGrantRequest.TTL</code> назван advisory, а
|
||
<code>LeaseGrantResponse.TTL</code> — выбранным server значением. Поэтому
|
||
слова «запрошенный TTL — минимум» заменены на точную границу API. Учебные
|
||
5000 мс не стали claim о настройке etcd. Отдельно перепроверены: lifecycle
|
||
lock key при expiry/revoke lease и Chubby-подход с advisory lock/acquisition
|
||
count, который защищаемый server сравнивает от delayed write.
|
||
|
||
| Проверка после интеграции | Реальный результат |
|
||
| --- | --- |
|
||
| Import-safe export | PASS: три revision, без <code>date</code>/<code>author</code> |
|
||
| Строгий audit трёх slug | PASS: **10 939 / 10 293 / 9 857** знаков; у каждой статьи есть figure, table и code examples |
|
||
| In-memory fixture | PASS: все 9 assertions истинны; token 2 принят, token 1 после него отклонён, старый release не снял lease-B |
|
||
| Независимый SVG review | PASS: XML и active/external asset scan прошли; три PNG 375 px просмотрены повторно, clipping, overlap и overflow не обнаружены |
|
||
| Production build | PASS: Next.js собрал 374 статические страницы |
|
||
|
||
Ни этот отчёт, ни интеграция не утверждают запуск etcd, другого provider,
|
||
cluster, базы, HTTP, browser, SDK или внешнего API.
|
||
|
||
Выпусковой вердикт: **ACCEPT**. Commit и push выполняются отдельной
|
||
публикационной операцией; Git остаётся источником её фактической записи.
|