Перейти к содержанию

Идемпотентность

Идемпотентность это свойство операции давать одинаковый результат при повторном ее применении с одинаковыми параметрами.

Термин широко используется в контексте распределенных систем. Бэкенд разработка тесно связана с распределенными системами. В контексте REST сервисов идемпотентной операцией считается та, которая при повторном запросе не вызывает побочных эффектов и ее можно вызывать сколько угодно раз, не меняя конечное состояние сервера.

Где это нужно?

  • кнопка оплата не должна снимать деньги повторно, если на нее кликнуть несколько раз;
  • при retry операциях, когда сеть сбоит, мы не ожидаем, что сущности в БД создадут копии только из-за сбоя в сети;

Сетевые запросы

Сетевая среда достаточна нестабильна. Коммуникация в такой среде не может предоставить полные гарантии доставки сообщения другому хосту в сети.

Задача двух генералов

Прекрасной иллюстрацией на это является задача двух генералов:

Note

Две армии, каждая руководимая своим генералом, готовятся к штурму города. Лагеря этих армий располагаются на двух холмах, разделённых долиной. Единственным способом связи между генералами является отправка посыльных с сообщениями через долину. Но долина занята противником и любой из посыльных может быть перехвачен. Проблема заключается в том, что, генералы заранее (пока была связь) приняли принципиальное решение о штурме, но не согласовали точное время штурма

Для успешного штурма генералы должны атаковать город одновременно. Штурм, предпринятый только одной армией, приведёт к катастрофическим последствиям для атакующих. Требуется найти алгоритм обмена сообщениями, после которого каждый генерал был бы уверен, что они оба атакуют в указанное время.

В случе перехвата сообщения, когда генерал посылает посыльного, то у него нет гарантированного способа узнать, получил ли второй генерал послание, так-как подтверждение от второго генерала могло быть перехвачено, а могло быть и само предложение от первого перехвачено.

В википедии можно найти доказательство, что задача не имеет решения. Суть доказательства сводится к тому, что из-за фактора нестабильной среды любое сообщение может быть перехвачено, что рушит согласованность действий.

Факты:

  • любое сообщение может быть перехвачено;
  • для согласованности нужно как минимум 2 сообщения - предложение и ответ;

Вывод: Так-как любое сообщение может быть перехвачено, а для согласованности нужно обменяться как минимум двумя сообщениями, то нет способа в 100% случаев согласовать действия.

То есть основная проблема заключается в свойстве сети - нестабильности.

Решают эту проблему путем уменьшения вероятности перехвата -- например, отправив 100 посыльных за раз(вряд ли всю сотню посыльных перехватят).

Retry механизмы в приложениях

Представим ситуацию: клиент нажимает на кнопку "купить" в мобильном приложении. Сервер получает запрос, обрабатывает его и начинает возвращать ответ. В этот самый момент на мобильном устройстве на несколько секунд пропадает интернет. Мобильный клиент пытается делать retry и посылает запрос снова, думая что прошлый ответ не дошел(хотя на самом деле дошел). Бэкенд тем временем получает и второй запрос, а затем списывает деньги второй раз. Идемпотентность нарушена.

Это достаточно неочевидная проблема, если допускать, что сеть работает стабильно в 100% случаев. Однако правда в том, что из-за свойства среды сама сеть может сбоить. И случаться это может в очень редких случаях. Мы не можем полагаться просто на сеть. Баг достаточно серьезный - у клиента списались деньги дважды. Репутация подорвана, законы нарушены.

Способы достижения идемпотентности в веб-приложениях

События происходят не параллельно(без concurrency, без race condition)

Ключи идемпотентности и уникальность

События происходят параллельно(случай с concurrency и race condition)