Невозможность Фишера-Линча-Патерсона

— Вот если бы все связи были бы асинхронными… — Нет, это не решит проблему. — Почему?

Действительно, давайте разберемся.

Мне предстояло сделать очередную интеграцию. Требования рядовые: к публичному API обращается конечный пользователь, но обработка запроса происходит с обязательным участием внешней системы – крайне нестабильной и медленной, – от которой нужно дождаться положительный ответ для продолжения действий. При этом важны и атомарность, и производительность…

В этот момент начинается анализ требований и ограничений, в голове перебираются возможные варианты решений: от самых простых до самых сложных. Наш мозг пытается найти компромисс. В мыслях промелькивают ACID, гарантии доставки, transactional outbox, saga, request/response over async и много всего… Ведь никто в здравом уме не хочет включать внешний вызов в транзакцию БД; все хотят делать долгую работу асинхронно. И может возникнуть мысль: “А если бы все связи были асинхронными?!”

Ответ на этот вопрос нашли в уже далёком 1985 три учёных, которые доказали теорему “FLP Impossibility”:

В полностью асинхронной распределённой системе, где нет верхней границы на задержку сообщений и скорость процессов, никакой детерминированный протокол консенсуса, рассчитанный хотя бы на один crash-отказ, не может гарантировать, что все исправные процессы примут решение за конечное время. (M.J. Fischer, N.A. Lynch, M.S. Paterson)

Это самый известный, но не единственный результат научного трио. Ключевые статьи прикреплю в виде файлов ниже, а здесь попробуем взять из этой теории практический максимум. Итак, в распределённых системах:

  • Нет безусловных гарантий, есть только компромиссы. Узлы не могут гарантированно судить о состоянии друг друга. Ожидая ответ, неясно, существует ли удалённый процесс или он просто работает очень медленно. Поэтому гарантии консенсуса могут быть даны только в условиях принятых предположений.
  • Корректность функционирования должна рассматриваться только в контексте предусмотренных уровней прочности, надёжности и устойчивости. Следовательно, задача не имеет надежного решения без дополнительных предположений о вычислительной среде и ограничений на допустимые типы сбоев.
  • Частичная синхронность и рандомизация – два классических способа обойти ограничения FLP. Именно поэтому на практике появляются таймауты, heartbeat, retry, jitter, deadline propagation и прочие техники, которые позволяют обнаруживать отсутствие прогресса и обходить последствия сбоев.

Между тем, FLP – это теорема о задаче консенсуса, т.е. когда все участники должны выбрать одно и то же значение. Это в первую очередь задачи, которые решают разработчики распределённых БД, протоколы Paxos/Raft/Zab. А что с этого тем, кто не решает подобные проблемы, а просто пилит микросервисы?

Для простых смертных есть ещё одна полезная эвристика:

В принятой модели отказов приходится выбирать, чем жертвовать: корректностью функционирования (safety) или вычислительным прогрессом (liveness).

  • Выбираем корректность. При сбое система останавливается, вместо того чтобы функционировать неправильно. Например, лучше зависший заказ (потеря прогресса), чем двойное списание денег (потеря корректности).
  • Выбираем прогресс. При сбое результат работы может деградировать, т.к. недоступность обходится дороже. Например, системы нечеткого поиска, рекомендательные системы, реклама.

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

Дополнительная литература



Понравилась статья?

Посмею напомнить, что у меня есть Telegram-канал Архитектоника в ИТ, где я публикую материал на похожие темы примерно раз в неделю. Подписчики меня мотивируют, но ещё больше мотивируют живые дискуссии, ведь именно в них рождается истина. Поэтому подписывайтесь на канал и будем оставаться на связи! ;-)

Статьи из той же категории: