Идемпотентность¶
Идемпотентность это свойство операции давать одинаковый результат при повторном ее применении с одинаковыми параметрами.
Термин широко используется в контексте распределенных систем. Бэкенд разработка тесно связана с распределенными системами. В контексте REST сервисов идемпотентной операцией считается та, которая при повторном запросе не вызывает побочных эффектов и ее можно вызывать сколько угодно раз, не меняя конечное состояние сервера.
Где это нужно?
- кнопка оплата не должна снимать деньги повторно, если на нее кликнуть несколько раз;
- при retry операциях, когда сеть сбоит, мы не ожидаем, что сущности в БД создадут копии только из-за сбоя в сети;
Сетевые запросы¶
Сетевая среда достаточна нестабильна. Коммуникация в такой среде не может предоставить полные гарантии доставки сообщения другому хосту в сети.
Задача двух генералов¶
Прекрасной иллюстрацией на это является задача двух генералов:
Note
Две армии, каждая руководимая своим генералом, готовятся к штурму города. Лагеря этих армий располагаются на двух холмах, разделённых долиной. Единственным способом связи между генералами является отправка посыльных с сообщениями через долину. Но долина занята противником и любой из посыльных может быть перехвачен. Проблема заключается в том, что, генералы заранее (пока была связь) приняли принципиальное решение о штурме, но не согласовали точное время штурма
Для успешного штурма генералы должны атаковать город одновременно. Штурм, предпринятый только одной армией, приведёт к катастрофическим последствиям для атакующих. Требуется найти алгоритм обмена сообщениями, после которого каждый генерал был бы уверен, что они оба атакуют в указанное время.
В случе перехвата сообщения, когда генерал посылает посыльного, то у него нет гарантированного способа узнать, получил ли второй генерал послание, так-как подтверждение от второго генерала могло быть перехвачено, а могло быть и само предложение от первого перехвачено.
В википедии можно найти доказательство, что задача не имеет решения. Суть доказательства сводится к тому, что из-за фактора нестабильной среды любое сообщение может быть перехвачено, что рушит согласованность действий.
Факты:
- любое сообщение может быть перехвачено;
- для согласованности нужно как минимум 2 сообщения - предложение и ответ;
Вывод: Так-как любое сообщение может быть перехвачено, а для согласованности нужно обменяться как минимум двумя сообщениями, то нет способа в 100% случаев согласовать действия.
То есть основная проблема заключается в свойстве сети - нестабильности.
Решают эту проблему путем уменьшения вероятности перехвата -- например, отправив 100 посыльных за раз(вряд ли всю сотню посыльных перехватят).
Retry механизмы в приложениях¶
Представим ситуацию: клиент нажимает на кнопку "купить" в мобильном приложении. Сервер получает запрос, обрабатывает его и начинает возвращать ответ. В этот самый момент на мобильном устройстве на несколько секунд пропадает интернет. Мобильный клиент пытается делать retry и посылает запрос снова, думая что прошлый ответ не дошел(хотя на самом деле дошел). Бэкенд тем временем получает и второй запрос, а затем списывает деньги второй раз. Идемпотентность нарушена.
Это достаточно неочевидная проблема, если допускать, что сеть работает стабильно в 100% случаев. Однако правда в том, что из-за свойства среды сама сеть может сбоить. И случаться это может в очень редких случаях. Мы не можем полагаться просто на сеть. Баг достаточно серьезный - у клиента списались деньги дважды. Репутация подорвана, законы нарушены.