1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p><strong>Наверняка вы слышали мнение, что доставка exactly-once (или однократная доставка) - невозможна. Это одна из самых сложных систем в сфере распределенных приложений, а ее практическое использование стоит слишком дорого. Существуют и логические ограничения - и сегодня речь пойдет именно о них.</strong></p>
1
<p><strong>Наверняка вы слышали мнение, что доставка exactly-once (или однократная доставка) - невозможна. Это одна из самых сложных систем в сфере распределенных приложений, а ее практическое использование стоит слишком дорого. Существуют и логические ограничения - и сегодня речь пойдет именно о них.</strong></p>
2
<p><em>Это адаптированный перевод статьи<a>The impossibility of exactly-once</a>Савваса Клеантоуса, программиста и специалиста по архитектуре CQRS. Повествование ведётся от лица автора оригинала.</em></p>
2
<p><em>Это адаптированный перевод статьи<a>The impossibility of exactly-once</a>Савваса Клеантоуса, программиста и специалиста по архитектуре CQRS. Повествование ведётся от лица автора оригинала.</em></p>
3
-
<p>Начнем с определения. Доставка exactly-once - это подход, при котором сообщение может быть доставлено получателю строго один раз, без дублей и п��тери данных. Проблема в том, что в реальном мире гарантировать это невозможно.</p>
3
+
<p>Начнем с определения. Доставка exactly-once - это подход, при котором сообщение может быть доставлено получателю строго один раз, без дублей и потери данных. Проблема в том, что в реальном мире гарантировать это невозможно.</p>
4
<h2>Содержание</h2>
4
<h2>Содержание</h2>
5
<ul><li><a>Доказательство противопоставлением и две общие проблемы</a></li>
5
<ul><li><a>Доказательство противопоставлением и две общие проблемы</a></li>
6
<li><a>Прямое доказательство</a></li>
6
<li><a>Прямое доказательство</a></li>
7
<li><a>Если гарантировать доставку exactly-once невозможно, что делать?</a></li>
7
<li><a>Если гарантировать доставку exactly-once невозможно, что делать?</a></li>
8
<li><a>Доставка at-most-once</a></li>
8
<li><a>Доставка at-most-once</a></li>
9
<li><a>Доставка at-least-once</a></li>
9
<li><a>Доставка at-least-once</a></li>
10
<li><a>Доставка без гарантии</a></li>
10
<li><a>Доставка без гарантии</a></li>
11
<li><a>Deus ex machina: обработка exactly-once</a></li>
11
<li><a>Deus ex machina: обработка exactly-once</a></li>
12
</ul><h2>Доказательство противопоставлением и две общие проблемы</h2>
12
</ul><h2>Доказательство противопоставлением и две общие проблемы</h2>
13
<p><em>Мы будем рассматривать проблему на примере задачи про двух генералов - мыслительного эксперимента, суть которого заключается в разработке алгоритма связи между двумя армиями, готовящимися атаковать один и тот же город. Противник находится строго между армиями, а атака только одной армией обречена на провал. Хотя организовать доставку сообщений между ними достаточно просто, гарантировать успех передачи данных - невозможно.</em></p>
13
<p><em>Мы будем рассматривать проблему на примере задачи про двух генералов - мыслительного эксперимента, суть которого заключается в разработке алгоритма связи между двумя армиями, готовящимися атаковать один и тот же город. Противник находится строго между армиями, а атака только одной армией обречена на провал. Хотя организовать доставку сообщений между ними достаточно просто, гарантировать успех передачи данных - невозможно.</em></p>
14
<p>Семантика доставки exactly-once очень похожа на задачу про двух генералов. И в том, и в другом случае есть две стороны, которые пытаются о чем-то сообщить друг-другу. В этом процессе пакеты данных могут потеряться: как два генерала должны согласовать время атаки, так и два процесса должны связаться с друг другом.</p>
14
<p>Семантика доставки exactly-once очень похожа на задачу про двух генералов. И в том, и в другом случае есть две стороны, которые пытаются о чем-то сообщить друг-другу. В этом процессе пакеты данных могут потеряться: как два генерала должны согласовать время атаки, так и два процесса должны связаться с друг другом.</p>
15
<p>Предположим, существует протокол, который гарантирует, что получатель точно получит сообщение - и это произойдет только один раз. Такой протокол мог бы решить проблему двух генералов - если это произойдет, первому генералу (отправителю) для доставки сообщения об атаке нужно будет только придерживаться протокола, чтобы второй генерал (получатель) получил информацию ровно один раз.</p>
15
<p>Предположим, существует протокол, который гарантирует, что получатель точно получит сообщение - и это произойдет только один раз. Такой протокол мог бы решить проблему двух генералов - если это произойдет, первому генералу (отправителю) для доставки сообщения об атаке нужно будет только придерживаться протокола, чтобы второй генерал (получатель) получил информацию ровно один раз.</p>
16
<h2>Прямое доказательство</h2>
16
<h2>Прямое доказательство</h2>
17
<p>Ниже я попытаюсь продемонстрировать, что гарантировать доставку сообщения ровно один, используя метод прямого доказательства, невозможно. Сначала уточним условия:</p>
17
<p>Ниже я попытаюсь продемонстрировать, что гарантировать доставку сообщения ровно один, используя метод прямого доказательства, невозможно. Сначала уточним условия:</p>
18
<ol><li><p>Отправитель и получатель работают в реальном мире, что означает ненулевое время транспортировки и обработки (и отсутствие строгой согласованности)</p>
18
<ol><li><p>Отправитель и получатель работают в реальном мире, что означает ненулевое время транспортировки и обработки (и отсутствие строгой согласованности)</p>
19
</li>
19
</li>
20
<li><p>Отправитель и получатель не имеют доступа к внутреннему состоянию друг друга. Это означает, что получатель не знает о намерении отправить сообщение, если отправитель об этом не сообщил</p>
20
<li><p>Отправитель и получатель не имеют доступа к внутреннему состоянию друг друга. Это означает, что получатель не знает о намерении отправить сообщение, если отправитель об этом не сообщил</p>
21
</li>
21
</li>
22
<li><p>Транспортировка сообщений ненадежна</p>
22
<li><p>Транспортировка сообщений ненадежна</p>
23
</li>
23
</li>
24
<li><p>Получатель обязательно должен выполнить обработку сообщения - то есть сообщение нельзя просто удалить или потерять</p>
24
<li><p>Получатель обязательно должен выполнить обработку сообщения - то есть сообщение нельзя просто удалить или потерять</p>
25
</li>
25
</li>
26
<li><p>Операция ограничена по времени: обработка должна быть завершена в течение не бесконечного периода времени.</p>
26
<li><p>Операция ограничена по времени: обработка должна быть завершена в течение не бесконечного периода времени.</p>
27
</li>
27
</li>
28
</ol><p>Пункты один и два исключают существование тривиального решения, которое основывалось бы на проверке внутреннего состояния получателя.</p>
28
</ol><p>Пункты один и два исключают существование тривиального решения, которое основывалось бы на проверке внутреннего состояния получателя.</p>
29
<p>Транспортировка сообщений ненадежна, поэтому отправитель не может заранее знать, что сообщение доставлено: для проверки нужно одно или несколько подтверждающих сообщений. Кроме того, невозможно отличить ошибку доставки или задержки, которая возникает при обработке или из-за ненадежности сети, от глобальной ошибки в доставке. Получатель, в свою очередь, вынужден отправлять ответное сообщение только после обработки (или сохранения для обработки), - то есть подтверждение перед обработкой в данном случае не сработает. Если получатель найдет ошибку перед обработкой, он потеряет сообщение.</p>
29
<p>Транспортировка сообщений ненадежна, поэтому отправитель не может заранее знать, что сообщение доставлено: для проверки нужно одно или несколько подтверждающих сообщений. Кроме того, невозможно отличить ошибку доставки или задержки, которая возникает при обработке или из-за ненадежности сети, от глобальной ошибки в доставке. Получатель, в свою очередь, вынужден отправлять ответное сообщение только после обработки (или сохранения для обработки), - то есть подтверждение перед обработкой в данном случае не сработает. Если получатель найдет ошибку перед обработкой, он потеряет сообщение.</p>
30
<p>Отправитель не имеет доступа к состоянию получателя, поэтому не может знать причину потери сообщения: например, сбой мог произойти в процессе подготовки к отправке, либо получатель просто работает слишком медленно.</p>
30
<p>Отправитель не имеет доступа к состоянию получателя, поэтому не может знать причину потери сообщения: например, сбой мог произойти в процессе подготовки к отправке, либо получатель просто работает слишком медленно.</p>
31
<p>Тут уже отправитель встанет перед выбором: продублировать сообщение (и адресат получит его дважды) или не делать этого. Во втором случае получатель может не обработать сообщение, если решить, что проблема возникла в процессе планирования обработки.</p>
31
<p>Тут уже отправитель встанет перед выбором: продублировать сообщение (и адресат получит его дважды) или не делать этого. Во втором случае получатель может не обработать сообщение, если решить, что проблема возникла в процессе планирования обработки.</p>
32
<h2>Если гарантировать доставку exactly-once невозможно, что делать?</h2>
32
<h2>Если гарантировать доставку exactly-once невозможно, что делать?</h2>
33
<p>Результат эксперимента, описанного выше, стоит принять во внимание при проектировании распределенных систем. При отсутствии логических ошибок система будет доставлять сообщение только один раз. Но если они возникнут, она будет действовать по одному из двух сценариев:</p>
33
<p>Результат эксперимента, описанного выше, стоит принять во внимание при проектировании распределенных систем. При отсутствии логических ошибок система будет доставлять сообщение только один раз. Но если они возникнут, она будет действовать по одному из двух сценариев:</p>
34
<p><strong>Доставка at-most-once.</strong>Сообщение не доставляется вовсе или доставляется, но теряется до того, как у получателя произойдут какие-либо изменения состояния. В результате получатель останется в том же состоянии, в котором он был до получения сообщения;</p>
34
<p><strong>Доставка at-most-once.</strong>Сообщение не доставляется вовсе или доставляется, но теряется до того, как у получателя произойдут какие-либо изменения состояния. В результате получатель останется в том же состоянии, в котором он был до получения сообщения;</p>
35
<p><strong>Доставка at-least-once.</strong>Сообщение доставится как минимум один раз.</p>
35
<p><strong>Доставка at-least-once.</strong>Сообщение доставится как минимум один раз.</p>
36
<h2>Доставка at-most-once</h2>
36
<h2>Доставка at-most-once</h2>
37
<p>При доставке at-most-once мы либо успешно доставляем сообщение, либо не доставляем его вовсе. Это простая гарантия для реализации и поддержки, поскольку она требует минимальных усилий:</p>
37
<p>При доставке at-most-once мы либо успешно доставляем сообщение, либо не доставляем его вовсе. Это простая гарантия для реализации и поддержки, поскольку она требует минимальных усилий:</p>
38
<ul><li>Отправитель отправляет сообщение получателю. Оба они игнорируют любые ошибки и тайм-ауты, а отправитель не требует подтверждения</li>
38
<ul><li>Отправитель отправляет сообщение получателю. Оба они игнорируют любые ошибки и тайм-ауты, а отправитель не требует подтверждения</li>
39
<li>Получатель также не делает ничего, либо подтверждает получение сообщение до того, как возникнут какие-либо проблемы.</li>
39
<li>Получатель также не делает ничего, либо подтверждает получение сообщение до того, как возникнут какие-либо проблемы.</li>
40
</ul><p>Это означает, что доставка at-most-once - самый простой вариант гарантии доставки как для разработчиков, так и для проектировщиков системы. Если этот подход соответствует условиям задачи, которая перед вами стоит, выбирайте его.</p>
40
</ul><p>Это означает, что доставка at-most-once - самый простой вариант гарантии доставки как для разработчиков, так и для проектировщиков системы. Если этот подход соответствует условиям задачи, которая перед вами стоит, выбирайте его.</p>
41
<p>Важно отметить, что в большинстве случаев требуется вести учет потерь при отправке сообщений. Это позволит сообщить о проблеме и даст возможность исправить ее вручную.</p>
41
<p>Важно отметить, что в большинстве случаев требуется вести учет потерь при отправке сообщений. Это позволит сообщить о проблеме и даст возможность исправить ее вручную.</p>
42
<h2>Доставка at-least-once</h2>
42
<h2>Доставка at-least-once</h2>
43
<p>Хотя предыдущий подход проще, на практике чаще применяется доставка at-least-once. Вот несколько причин, почему это происходит:</p>
43
<p>Хотя предыдущий подход проще, на практике чаще применяется доставка at-least-once. Вот несколько причин, почему это происходит:</p>
44
<ul><li>Пользовательский опыт улучшается: им не нужно повторять действие вручную, а единственное неудобство - небольшая задержка</li>
44
<ul><li>Пользовательский опыт улучшается: им не нужно повторять действие вручную, а единственное неудобство - небольшая задержка</li>
45
<li>Потери пакетов сводятся к минимуму</li>
45
<li>Потери пакетов сводятся к минимуму</li>
46
<li>Изменения, которые необходимо внести, действительно вносятся</li>
46
<li>Изменения, которые необходимо внести, действительно вносятся</li>
47
</ul><p>Доставка at-least-once не добавляет алгоритмической сложности, а для ее внедрения достаточно реализовать следующее:</p>
47
</ul><p>Доставка at-least-once не добавляет алгоритмической сложности, а для ее внедрения достаточно реализовать следующее:</p>
48
<ul><li>Отправитель ожидает подтверждение сообщения с учетом задержки. Если подтверждение не получено, доставка повторяется</li>
48
<ul><li>Отправитель ожидает подтверждение сообщения с учетом задержки. Если подтверждение не получено, доставка повторяется</li>
49
<li>Получатель сначала обрабатывает сообщение, реагируя на любые ошибки, и только в случае успеха подтверждает сообщение</li>
49
<li>Получатель сначала обрабатывает сообщение, реагируя на любые ошибки, и только в случае успеха подтверждает сообщение</li>
50
</ul><p>Часто описанные выше процессы обрабатываются на уровне инфраструктуры, чтобы результат был прозрачен на прикладном и доменном уровнях. Получая сообщение на уровне инфраструктуры, можно преодолеть проблемы интеграции, а затем передать его на уровень приложения, и уже там подтвердить получение.</p>
50
</ul><p>Часто описанные выше процессы обрабатываются на уровне инфраструктуры, чтобы результат был прозрачен на прикладном и доменном уровнях. Получая сообщение на уровне инфраструктуры, можно преодолеть проблемы интеграции, а затем передать его на уровень приложения, и уже там подтвердить получение.</p>
51
<h2>Доставка без гарантии</h2>
51
<h2>Доставка без гарантии</h2>
52
<p>Третья и самая простая альтернатива - доставка без гарантии. Проблема с таким подходом в отсутствии согласованности системы.</p>
52
<p>Третья и самая простая альтернатива - доставка без гарантии. Проблема с таким подходом в отсутствии согласованности системы.</p>
53
<h2>Deus ex machina: обработка exactly-once</h2>
53
<h2>Deus ex machina: обработка exactly-once</h2>
54
<p>Как уже говорилось ранее, единственные подходящие варианты реализации доставки - либо потерять сообщение, либо доставить его более одного раза. В случае с доставкой at-least-once мы сильно рискуем доставить сообщение дважды, что может катастрофические последствия для системы. Неужели мы обречены?</p>
54
<p>Как уже говорилось ранее, единственные подходящие варианты реализации доставки - либо потерять сообщение, либо доставить его более одного раза. В случае с доставкой at-least-once мы сильно рискуем доставить сообщение дважды, что может катастрофические последствия для системы. Неужели мы обречены?</p>
55
<p>Не совсем: хотя доставка exactly-once невозможна, но ведь обработка exactly-once вполне реализуема. Этот подход гарантирует, что мы обработаем сообщение только один раз - вне зависимости от того, сколько раз оно было отправлено. Реализовать его можно двумя способами:</p>
55
<p>Не совсем: хотя доставка exactly-once невозможна, но ведь обработка exactly-once вполне реализуема. Этот подход гарантирует, что мы обработаем сообщение только один раз - вне зависимости от того, сколько раз оно было отправлено. Реализовать его можно двумя способами:</p>
56
<ul><li>Дедупликация: удаление сообщений, если они получены более одного раза</li>
56
<ul><li>Дедупликация: удаление сообщений, если они получены более одного раза</li>
57
<li>Идемпотентная обработка: прием сообщения более одного раза имеет такой же эффект, как и их применение ровно один раз</li>
57
<li>Идемпотентная обработка: прием сообщения более одного раза имеет такой же эффект, как и их применение ровно один раз</li>
58
</ul>
58
</ul>