теория

Чем платят за сериализуемость

Раз сериализуемость спасает от write skew — почему бы не включить её на всю базу и не спать спокойно? Отличный вопрос, и ответ на него отделяет джуна от архитектора.

Достичь «как будто по очереди» можно тремя способами, и у каждого своя цена:

  • Настоящее последовательное выполнение — гнать транзакции по одному потоку. Просто и без гонок, но упирается в один процессор: годится, когда транзакции короткие и их не миллионы.
  • (2PL) — брать блокировки на всё, что трогаешь, и держать до конца. Надёжно, но параллелизм проседает, а блокировки любят собираться в дедлоки.
  • Сериализуемая изоляция снимков (SSI) — работать оптимистично, как со снимком, но на коммите проверять, не разъехались ли решения; если да — откатить и повторить. Быстро, когда конфликтов мало, и дорого, когда их много.

Видишь закономерность? За сильную изоляцию всегда платят пропускной способностью: либо ждём в блокировках, либо откатываем и переделываем. Поэтому серьёзные системы не задирают изоляцию глобально — они включают её точечно, вокруг инвариантов, которые нельзя нарушить: баланс, остаток, лимит. Всё остальное — каталог, история просмотров, лента — прекрасно живёт на слабой изоляции и радуется скорости.

И ещё одно, важное для нас. Помнишь, при выделении платежей мы обошли стороной и её ? Теперь понятно почему: 2PC — это те же блокировки, только растянутые по сети, с координатором, который сам может упасть посреди процесса и подвесить всех участников. За сетью цена сериализуемости взлетает до небес. Дешевле держать денежный инвариант внутри одного сервиса-владельца — и там уже включать сериализуемость локально.

Мораль модуля: деньги требуют сериализуемости ровно там, где ошибка непростительна. Всё остальное переживёт согласованность в конечном счёте — и скажет тебе спасибо за скорость.

← назад