Транзакции в highload-проектах | OTUS
⚡Подписка от OTUS!
Собери свой пул курсов на выгодных условиях. Подробности в чате →
Написать в чат

Курсы

Программирование
Unity Game Developer. Basic
-15%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-6%
Разработчик C#
-8%
Алгоритмы и структуры данных
-8%
Backend-разработчик на PHP
-8%
JavaScript Developer. Professional
-9%
iOS Developer. Professional
-8%
Базы данных
-12%
C# ASP.NET Core разработчик
-6%
Python Developer. Basic
-10%
Java Developer. Professional Web-разработчик на Python Android Developer. Basic PostgreSQL Software Architect Reverse-Engineering. Professional Kotlin Backend Developer React.js Developer VOIP инженер Нереляционные базы данных Scala-разработчик Супер-практикум по использованию и настройке GIT IoT-разработчик JavaScript Developer. Basic Advanced Fullstack JavaScript developer Unity Game Developer. Professional Супер-интенсив Azure
Инфраструктура
Супер-интенсив "Версионирование и командная работа с помощью Git"
-30%
Administrator Linux. Professional
-5%
Супер-интенсив «CI/CD или Непрерывная поставка с Docker и Kubernetes»
-30%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-6%
Administrator Linux. Advanced
-8%
Infrastructure as a code in Ansible
-12%
Network engineer
-4%
MS SQL Server Developer
-8%
Cloud Solution Architecture Highload Architect Разработчик голосовых ассистентов и чат-ботов Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по работе с протоколом BGP Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Архитектор сетей Супер-интенсив «IaC Ansible»
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Транзакции в highload-проектах

Все мы прекрасно знаем 4 главных требования к транзакциям: атомарность, изолированность, согласованность и долговечность (ACID — Atomicity, Consistency, Isolation, Durability). Давайте поговорим о транзакциях в контексте высоконагруженных проектов.

Когда мы рассуждаем о распределенных БД, мы предполагаем, что данные необходимо масштабировать. Чтение масштабируется прекрасно, поэтому тысячи транзакций могут параллельно читать данные без каких-либо проблем. Но если вместе с чтением другие транзакции осуществляют запись данных, то не исключены негативные эффекты. Например, достаточно просто получить ситуацию, когда одна транзакция будет читать различные значения тех же самых записей. Дабы не быть голословными, рассмотрим примеры.

Dirty reads

В этой транзакции мы дважды отправляем тот же самый запрос: сделать выборку всех юзеров с ID равным единице. Когда вторая транзакция изменит эту строчку, сделав потом rollback, наша база данных, с одной стороны, каких-либо изменений не увидит, а вот с другой — первая транзакция прочтет различные значения возраста для Joe.

qjzld6frtj0ogu9lpfoss5wva2k_1-1801-72698c.png

Non-repeatable reads

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

85wdugy_ypmk0cfxpxl1hy5pf_s_1-1801-aa434b.png

И если в первом случае клиент прочел данные, которые в БД отсутствовали, то во втором — клиент оба раза прочел данные из БД, которые оказались различными, хотя чтение осуществлялось в рамках одной транзакции.

Phantom reads

Речь идет о ситуации, когда мы в контексте одной транзакции повторно читаем какой-либо диапазон, получая различный набор строк. И где-то посередине влезает другая транзакция, вставляя либо удаляя записи.

k465yqehsgbjd0ertvg7poziaie_1-1801-604a12.png

Для исключения вышеописанных негативных эффектов СУБД реализуют: — механизмы блокировок (транзакция ограничивает доступ к данным иным транзакциям, с которыми она сейчас работает); — мультиверсионный контроль версий или MVCC (транзакция никогда не меняет ранее записанные данные, всегда создавая новую версию).

Существующий сегодня стандарт ANSI/ISO SQL определяет четыре уровня изоляции транзакций, влияющих на степень их взаимной блокировки. И чем выше уровень изоляции, тем меньше существует негативных эффектов. Плата за это — увеличение вероятности deadlocks и замедление работы приложения (дело в том, что транзакции чаще находятся в ожидании снятия блокировки с необходимых им данных).

0_iy4hwem9b4_mkupvpetxgc9so_1-1801-4f04f4.png

Самый приятный уровень для прикладного программиста — Serializable (отсутствуют негативные эффекты, а вся сложность обеспечения целостности данных перекладывается на СУБД). Но тут стоит подумать про наивную реализацию уровня Serializable — при осуществлении каждой транзакции мы просто выполняем блокировку всех остальных. Теоретически, каждая транзакция записи может выполняться за 50 мкс (речь идет о времени одной операции записи у SSD-дисков). Мы же хотим сохранять данные, допустим, на 3 машины. И если они располагаются в одном дата-центре, на запись уйдет 1-3 мс. Если же они находятся в нескольких разных городах, запись может занять и 10-12 мс. Таким образом, в случае наивной реализации уровня Serializable последовательной записью, мы получаем возможность выполнять не более 100 транзакций в сек. И это при том, что отдельный SSD-диск позволяет осуществлять около 20 тыс. операций записи в секунду.

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

Статья подготовлена по материалам блога компании Pyrus.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться