Pull to refresh

Comments 5

Неплохой обзор, но чуть добавлю.

  1. Непонятно, почему у оркестратора «средняя масштабируемость». Можно же запустить любое количество экземпляров оркестратора.

  2. Непонятно, почему в недостатках хореографии не указано наличие компенсирующих транзакций. Они там нужны так же, как и при оркестрации.

  3. Непонятно, где в 2PC сложная конфигурация. Сами же пишете, что существует множество готовых реализаций.

  4. Непонятно, почему у 2PC плохая масштабируемость. Если, конечно, вы хотите все транзакции пускать через единственный координатор, то да. Но ведь у каждой транзакции может быть собственный координатор! Например, так работает Apache Ignite.

  5. Падение координатора – не единственная проблема 2PC. Стандарт вообще не предусматривает потерю узла: предполагается, что у узла есть надёжное хранилище, и если узел упал, то через некоторое время он будет восстановлен, причём содержимое его диска сохранится. Восстановление после безвозвратной потери узла – каждый раз произведение искусства.

  6. Для полноты картины здесь можно было бы упомянуть детерминированные транзакции – это третий способ выполнения распределённых транзакций, пусть и не связанный с микросервисной архитектурой.

Статья хорошая как обзор.

Согласен с первым комментарием. Добавил-бы сагу с семантическими блокировками и соответствующей компенсацией. ИМХО, строгая консистентность в SOA, скорее, миф. Достигать ее занятие чисто академическое.

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

Невозможно гарантировать, что атомарная операция закончится и при этом сохранит строгую консистентность для всех узлов, независимо от отказов.

Можно либо:

• дождаться восстановления (может быть бесконечно долго);

• ослабить одно из свойств (допустить временную рассинхронизацию, часть не-ACID-свойств, компенсации и т. п.).

И все паттерны это просто баланс и приведение системы к приемлемым, но не идеальным параметрам.

Паттерны лишь «подбирают» приемлемую точку на треугольнике «консистентность – время – доступность».

Причем, «eventual consistency» — это не обещание «спустя ровно X секунд всё придёт в порядок».

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

Временная задержка (∆-visibility)

P(стала видима ≤ ∆) ≥ 1 – ε

Пример: «с вероятностью ≥ 99,9 % обновление разойдётся ≤ 850 мс».

Версионная задержка (k-staleness)

P(прочитал не более k устаревших версий) ≥ 1 – ε

Пример: «не более одной пропущенной версии в 99,99 % чтений

Возьмём маленький выдуманный сценарий и посчитаем ­— буквально на пальцах — сколько денег теряют три разных паттерна.

Ситуация

• Интернет-магазин принимает 100 заказов в секунду.

• Операция «оплатить + списать товар» длится 0,1 с.

• Каждый сервис (платёж, склад) «падает» в среднем раз в сутки.

• Связь между двумя дата-центрами рвётся раз в месяц, причём стоит «мертвой» 5 минут.

Переведём это в простые проценты, которые можно подставлять дальше.

Вероятность, что конкретный сервис откажет посреди одной операции

Раз в сутки = 1 сбой / 86 400 с.

Операция 0,1 с ⇒ шанс за 0,1 с ≈ 0,1 / 86 400 ≈ 0,0000012

То есть 0,00012 % (читаем: «одна десятимиллионная»).

Обозначим pf ≈ 0,0000012.

Вероятность попасть именно в сетевую партицию

Партиция раз в 30 дней = 1 раз / 2 592 000 с, длится 300 с.

Доля времени «канал мёртв» = 300 / 2 592 000 ≈ 0,00012 = 0,012 %

Для 0,1-секундной операции это почти то же число.

Обозначим pn ≈ 0,00012.

Теперь оценим, чего стоят ошибки (выдуманные цифры, но порядок реалистичен):

• Ca — простой (клиент жмёт «Оплатить», а мы висим): 50 руб. за каждую секунду задержки.

• Cd — «удвоенное списание» или «товар продан дважды»: 5 000 руб. за штуку.

• Cc — ручная разборка «заказ отменён, деньги вернули»: 200 руб. за один случай.

3 кандидата

A. 2PC (координатор + два подпроцесса)

– Если коорд. рухнет или связь между ДЦ рвётся, заказ «зависает» на 10 секунд тайм-аута.

Шанс «зависнуть» = pf + pn ≈ 0,00012 % + 0,012 % ≈ 0,012 % (партиция доминирует).

За 100 заказов/с это 0,012 заказа в секунду.

Ущерб за секунду: 0,012 × 10 с × 50 руб./с = 6 руб.

B. Quorum (3 реплики, пишем на 2)

– Партиция между ДЦ делит нас «2 к 1»: кворум сохранён, но есть риск, что третья реплика отстанет и кто-то прочтёт старые данные.

Пусть при такой партиции 1 % чтений видит устаревшее.

Сетевые партиции бывают 0,012 % времени → «грязные» чтения: 0,01 % × 0,012 % ≈ 0,0000012 % общего времени.

При 100 заказах/с это 0,0000012 заказа в секунду.

Каждая ошибка = двойной платёж 5 000 руб.

Ущерб за секунду: 0,0000012 × 5 000 ≈ 0,006 руб.

C. Saga (два шага + компенсация)

– Если любой сервис падает в середине цепочки, второй шаг не выполнится и сработает компенсация.

Шанс сбоя любого из двух шагов: 2 × pf ≈ 2 × 0,0000012 % = 0,0000024 %

За 100 заказов/с это 0,0000024 заказа в секунду.

Каждая компенсация стоит 200 руб.

Ущерб за секунду: 0,0000024 × 200 ≈ 0,00048 руб.

Сводим рядом (руб./сек)

• 2PC ≈ 6

• Quorum ≈ 0,006

• Saga ≈ 0,0005

Вывод «по-человечески»

– 2PC дорог именно потому, что при меж-ДЦ партиции все заказы на 10 секунд стопорятся: много секунд × дорогая секунда.

– Quorum почти не страдает: партиции редкие, а грязные данные по нему проходят ещё реже.

– Saga обходится ещё дешевле: отдельные компенсации случаются реже, и каждая стоит почти в тысячу раз меньше, чем «двойное списание».

Поэтому при таких исходных цифрах дешевле всего жить на Saga.

Если бы «двойное списание» стоило бы дороже либо партиции стали бы чаще — цифры изменились бы, и баланс могло бы сместиться к Quorum или даже обратно к 2PC.

Sign up to leave a comment.

Articles