Введение
В условиях стремительно растущих объёмов данных и высокой интенсивности взаимодействия с цифровыми сервисами, управление транзакциями в распределённых базах данных стало критически важной задачей для обеспечения устойчивости и надёжности информационных систем. Системы, обрабатывающие большой объём транзакций, такие как финансовые, ритейловые и мультимедийные платформы, требуют стабильной работы при одновременном выполнении множества операций. Для достижения высокой доступности и масштабируемости традиционные реляционные базы данных зачастую оказываются недостаточно эффективными. В таких случаях на смену им приходят распределённые базы данных, которые способны обеспечивать непрерывность процессов даже при интенсивной нагрузке. Однако внедрение распределённых баз данных и управление транзакциями в условиях высокой нагрузки требует применения специальных подходов и технологий для поддержания согласованности данных и предотвращения ошибок.
В настоящее время в предприятиях существуют проблемы в процессе управления транзакциями в высоконагруженных системах, особенно при использовании распределённых баз данных. Они связаны с обеспечением согласованности данных, минимизацией задержек и управлением отказами. Что в свою очередь и обуславливает актуальность работы, вызванную необходимостью адаптации архитектур информационных систем к современным требованиям производительности и отказоустойчивости. В условиях, когда бизнесы переходят к микросервисной архитектуре и используют распределённые базы данных, возникает потребность в новых методах управления транзакциями, которые позволят снизить риск потери данных и повысить надёжность системы. Традиционные модели транзакций, в которых используются централизованные базы данных, оказываются недостаточно гибкими, чтобы удовлетворять потребности распределённых систем. В этом контексте особую роль играют такие подходы, как двухфазная фиксация и паттерн Saga. Они позволяют управлять транзакциями, охватывающими несколько баз данных, минимизируя риск ошибок и обеспечивая возможность восстановления данных при сбоях.
Написание данной работы и предложение наиболее подходящих вариантов управления транзакциями в высоконагруженных системах стало возможным благодаря наличию необходимого опыта, полученного как в «BrainRocket» – где ежедневно решались задачи управления распределёнными транзакциями, так и в ООО «Involta».
В статье рассматриваются подходы, позволяющие снизить сложности и риски, связанные с данными процессами, за счет использования: саг, идемпотентных операций и систем событийного управления, которые позволяют не только снизить зависимость между сервисами, но и обеспечить их стабильную работу. Акцент сделан на применении этих методов в реальных условиях высоконагруженных систем, что подтверждается практикой в компании «BrainRocket» и обобщением предыдущего опыта других компаний.
Цель работы – исследование методов управления транзакциями в высоконагруженных системах с использованием распределённых баз данных и анализ подходов, позволяющих поддерживать согласованность данных и отказоустойчивость в условиях высокой нагрузки.
Материалы и методы
Работа Pan J. J., Wang J., Li G. [1, с. 1591-1615] посвящена изучению систем управления векторными базами данных, с акцентом на индексирование, поиск ближайших соседей (ANN) и оптимизацию производительности. Авторы сравнивают архитектуры FAISS, Milvus и Weaviate, исследуя их сильные стороны в ускорении обработки запросов, также поднимают вопросы, связанные с масштабированием в условиях работы с данными. В связи с чем авторы уделяют внимание гибридным подходам, которые объединяют реляционные и векторные базы данных для улучшения совместимости с существующими системами.
Кравченко Д. А. отмечает, что микросервисная архитектура является одним из ведущих подходов в разработке современных распределенных систем [2, с. 43]. Она обеспечивает гибкость и масштабируемость за счет разделения приложения на независимые сервисы. Однако такой подход порождает сложности в обработке транзакций и обеспечении согласованности данных.
Фомин Д. С. и Бальзамов А. В. [3, с. 15-23] считают, что распределенная природа микросервисов усложняет управление транзакциями. В их работе анализируются проблемы, связанные с координацией транзакций между сервисами, и предлагаются методы для их эффективной обработки.
Вопрос согласованности данных в микросервисной среде исследован Малюга К. В., Перл И. А., Слапогузов А. П. [5, с. 473-481]. Авторы оценили применимость методов асинхронного программирования для решения данной проблемы. Они показали, что асинхронные подходы могут повысить производительность системы, но требуют тщательного управления для сохранения целостности данных.
Проблемы отказоустойчивости высоконагруженных систем рассмотрены в работе Рудометкина В. А. [6, с. 118-123]. Он подчеркивает важность разработки механизмов, позволяющих системе продолжать функционировать при сбоях отдельных компонентов, что особенно актуально в контексте микросервисной архитектуры.
Данилов А. Д. и Синюков Д. С. [7, с. 59-65] предложили подход к управлению транзакциями в гетерогенных распределенных реплицированных системах баз данных в реальном времени. Их метод позволяет обеспечить эффективную обработку транзакций и поддерживать согласованность данных между различными узлами системы.
Практический пример масштабирования микросервисной архитектуры представлен в интернет ресурсе о компании PayPal [8]. Несмотря на использование всего 8 виртуальных машин, им удалось обрабатывать миллиард транзакций в день. Это было достигнуто за счет оптимизации архитектуры и эффективного использования ресурсов.
Таким образом, текущие исследования фокусируются на преодолении трудностей, связанных с транзакционной обработкой и согласованностью данных в микросервисных системах, а также на повышении их отказоустойчивости и производительности.
Результаты и обсуждения
При разработке серверной части высоконагруженных приложений часто возникает необходимость в использовании распределённых транзакций. Этот подход становится актуальным, когда операции транзакции охватывают несколько физических систем или компьютеров в сети, в этом случае их называют распределёнными транзакциями. При переходе к микросервисной архитектуре система разбивается на отдельные компоненты – микросервисы. Например, в интернет-магазине могут быть выделены микросервисы OrderMicroservice и InventoryMicroservice, каждый из которых использует собственную базу данных. Когда пользователь отправляет запрос на заказ, происходит обращение к обоим микросервисам, и каждый из них вносит изменения в свою базу данных. Поскольку теперь транзакция затрагивает несколько баз данных в разных системах, она относится к категории распределённых транзакций [3, с. 15-23].
Ситуации, при которых несколько пользователей или процессов параллельно пытаются внести изменения в одну и ту же запись в базе данных, называются конкурентными обновлениями. В многопользовательских и мультипроцессорных средах такие обновления могут возникать, когда несколько сущностей одновременно запрашивают доступ к одним и тем же данным. Ниже в таблице 1 будут описаны основные риски, а также сложности при управлении целостными данными.
Таблица 1
Основные риски и осложнения при управлении целостностью данных
Потенциальный риск | Описание |
Несогласованность данных | Конкурентные обновления могут привести к противоречиям, когда в системе сосуществуют разные версии данных, нарушая её целостность и достоверность информации. |
Потеря данных | При перезаписи одного обновления другим результаты предыдущих изменений могут быть безвозвратно утеряны, что угрожает полноте данных. |
Грязное чтение | Если транзакция обращается к данным, которые одновременно изменяются другой транзакцией, может быть получена некорректная или промежуточная информация. |
Неповторяемое чтение | При повторном запросе тех же данных, но получении разных результатов из-за параллельных операций, возникают сложности с последовательностью чтения. |
Уровни изоляции в базах данных регулируют степень изолированности параллельных транзакций, управляя такими явлениями, как грязное чтение, потеря обновлений и другие виды аномалий. Выбор уровня изоляции зависит от требований к точности данных и уровня параллелизма, необходимого приложению. Более высокий уровень изоляции, как SERIALIZABLE, снижает риск нарушений целостности, но может замедлить параллельное выполнение, в то время как низкие уровни повышают производительность за счёт ослабленного контроля над данными.
Для предотвращения параллельного изменения данных используется SQL-запрос с конструкцией FOR UPDATE, позволяющей установить явную блокировку записи. Это обеспечивает надёжную защиту от конкурентного доступа, приостанавливая другие транзакции до завершения текущей. В Spring Boot и spring-data-jpa достаточно задать аннотацию для блокировки на уровне метода извлечения.
Оптимистический подход основывается на проверке версий записей. Каждая запись имеет атрибут версии, и при попытке её обновления приложение сверяет текущую версию с сохранённой в базе. В случае несоответствия возникает конфликт (Optimistic Lock Exception), предотвращающий обновление. Для применения в Spring Boot используется аннотация @Version, указываемая в поле сущности.
На практике пессимистическая блокировка обеспечивает надёжную защиту, но замедляет обработку данных, тогда как оптимистическая блокировка подходит для сценариев с низкой частотой конфликтов, минимизируя накладные расходы. Для распределённых систем, особенно работающих в нескольких экземплярах, рекомендуется применение распределённой блокировки на уровне приложения. Используя Redis и Spring Integration, можно создать блокировку, позволяющую одному экземпляру приложения получить доступ к ресурсу, в то время как другие процессы ожидают освобождения. Библиотека Spring Retry также полезна для повторного выполнения запросов в условиях временных сбоев.
При асинхронной обработке сообщений для снижения конкуренции данных можно использовать локальное кэширование идентификаторов запросов, что позволяет сгруппировать дублирующиеся запросы и оптимизировать обработку. В сценариях с большим количеством узлов вместо DelayQueue предпочтительнее использовать Redis для управления уникальными идентификаторами на уровне всей системы, снижая вероятность возникновения конфликтов [4, с. 15-18].
Далее рассмотрим пример абстрактного банковского приложения, поддерживающего функцию перевода денежных средств. Данная операция реализована через два микросервиса: первый отвечает за списание средств со счёта отправителя, а второй – за их зачисление на целевой счёт. В случае сбоя одного из сервисов или коммуникационной шины может возникнуть ситуация, когда деньги списаны, но не зачислены, что приводит к потере средств. В другом примере – системе электронного документооборота для крупных организаций – данные проходят через несколько микросервисов. Например, одна часть информации отправляется в бухгалтерскую систему, другая – в финансовую, а документы сохраняются в архиве. В отсутствие управления распределёнными транзакциями процессы могут стать неконтролируемыми, и при возникновении ошибки невозможно будет остановить или перезапустить операцию, а частичный результат не будет доступен пользователю.
Для предотвращения таких ситуаций используется паттерн Saga, который действует как координирующий сервис. Этот микросервис, подключённый к коммуникационной шине, отслеживает события, происходящие в других микросервисах. Существует два подхода к реализации Saga:
- Процессное управление: Saga проверяет шаблон процесса и отдаёт команды другим модулям.
- Событийное управление: Модули самостоятельно подписываются на интересующие их события и реагируют на них согласно процессному шаблону.
Данный подход позволяет использовать Saga как для краткосрочных процессов, так и для более длительных, состоящих из множества этапов и переходов между системами, иногда продолжающихся в течение нескольких дней [5, с. 473-481].
В системе управления цифровыми активами (DAM), где пользователи загружают одновременно множество файлов, каждый из которых проходит обработку через несколько микросервисов, паттерн Saga помогает координировать процесс. Пользователь получает уведомления о статусе загрузки, возможность внести дополнительные данные и отменить операцию, если обнаружен некорректный файл. Другой пример – система авансовых отчётов. Сотрудники пошагово вводят данные и загружают документы. Saga помогает организовать последовательное выполнение этих операций в строгом соответствии с корпоративными стандартами, упрощая интеграцию с бизнес-процессами и обеспечивая прозрачность работы системы. Помимо Saga, существуют иные методы:
- Координатор распределённых транзакций: Принцип схож с Saga, однако оркестратор взаимодействует напрямую с базами данных микросервисов. Однако данный подход более сложен технически, и если базы данных различных микросервисов различны, например, MS SQL и MongoDB, метод может оказаться неприменимым.
- Outbox-Inbox: Микросервисы обмениваются сообщениями напрямую. Например, при переводе средств один микросервис сохраняет отправленное сообщение в Outbox, а другой принимает его в Inbox. В случае сбоя можно восстановить согласованность данных путём сверки сообщений. Этот метод подходит только для простых процессов, поскольку при увеличении числа участников транзакции контроль взаимодействий усложняется [6, с. 118-123].
Эластичные транзакции, доступные в SQL Azure и Управляемом экземпляре Azure SQL, позволяют осуществлять транзакции, охватывающие сразу несколько баз данных. Такие возможности особенно актуальны для приложений, разработанных на платформе .NET с использованием ADO.NET и классов System.Transaction. Также транзакции можно выполнять с помощью Transact-SQL, что доступно в управляемом экземпляре SQL. В локальной среде обычно требуется запуск Microsoft Distributed Transaction Coordinator (MSDTC), но в SQL Azure эта необходимость отпадает: поддержка распределённых транзакций интегрирована непосредственно в SQL базу данных и Управляемый экземпляр SQL, обеспечивая прозрачную координацию.
Транзакции эластичной базы данных позволяют гарантировать атомарность изменений, затрагивающих несколько баз данных. Это особенно полезно для приложений с распределённой архитектурой, использующих вертикальное секционирование данных, когда разные виды данных располагаются в разных базах. Например, в Azure SQL эластичные транзакции помогают координировать обновления данных между несколькими базами данных в рамках одного приложения, сохраняя целостность.
Для приложений, использующих горизонтальное сегментирование, эластичные транзакции также являются надёжным решением. В сценариях, когда данные распределены между базами, например, для разных клиентов, эластичные транзакции позволяют координировать изменения в нескольких базах данных. Эластичные транзакции используют механизм двухфазной фиксации, обеспечивая гарантированную атомарность и минимизацию рисков при обработке до 100 баз данных в одной транзакции.
Для начала работы с эластичными транзакциями в .NET необходимо установить или обновить платформу .NET до версии 4.6.1 или более поздней. Обновления библиотеки System.Transactions.dll обеспечивают поддержку двухфазной фиксации, необходимой для работы с эластичными транзакциями. Включение этого механизма позволяет автоматически повышать уровень транзакций до распределённых, если они охватывают несколько баз данных.
Для управляемых экземпляров SQL поддержка распределённых транзакций также осуществляется на стороне сервера с использованием инструкций Transact-SQL, таких, как BEGIN DISTRIBUTED TRANSACTION. В этом сценарии несколько управляемых экземпляров SQL могут участвовать в транзакции, если они принадлежат одной группе доверия. Таким образом, серверные команды Transact-SQL и возможности платформы .NET могут быть объединены в рамках одной транзакции, что обеспечивает гибкость и универсальность в управлении данными.
Примеры кода на C# демонстрируют, как с помощью TransactionScope и классов System.Transactions организовать распределённые транзакции для выполнения сложных операций. Например, при наличии нескольких соединений в TransactionScope каждое подключение автоматически повышается до уровня распределённой транзакции, если используется команда BEGIN DISTRIBUTED TRANSACTION [7, с. 59-65].
Рис.
Распределенные базы данных становятся критически важными для компаний, которые управляют большим объемом транзакций в высоконагруженных системах. Такие системы необходимы для обеспечения высокой доступности, масштабируемости и отказоустойчивости. В таблице 2 будут рассмотрены преимущества и недостатки управления транзакциями в высоконагруженных системах с использованием распределенных баз данных.
Таблица 2
Преимущества и недостатки управления транзакциями в высоконагруженных системах с использованием распределенных баз данных
Аспект | Преимущества | Недостатки |
Высокая доступность | Обеспечение непрерывного доступа к данным даже при отказе отдельных узлов, что повышает отказоустойчивость и минимизирует время простоя. | Требует сложного механизма репликации данных и управления отказами, что может усложнять архитектуру системы. |
Горизонтальное масштабирование | Легкость добавления новых серверов для обработки возросшей нагрузки, что позволяет системе обрабатывать больше транзакций одновременно. | Координация транзакций между узлами увеличивает сложность и может привести к увеличению задержек из-за распределенной природы системы. |
Распределение нагрузки | Транзакции могут распределяться по разным узлам, снижая нагрузку на отдельные базы данных и улучшая общую производительность системы. | Возможны проблемы с согласованностью данных между узлами из-за временной разницы или неудачных обновлений, что усложняет поддержание целостности данных. |
Гибкость конфигурации | Возможность настраивать разные узлы для определенных задач или данных, что повышает адаптивность системы под изменяющиеся требования и нагрузки. | Необходимость разработки и поддержки сложных алгоритмов синхронизации и контроля целостности данных для обеспечения согласованности между различными узлами. |
Уменьшение риска потерь данных | Использование репликации для сохранения копий данных на нескольких узлах, что снижает вероятность потери данных в случае отказа отдельных серверов. | Поддержание репликации и обеспечение согласованности между репликами увеличивает временные и вычислительные издержки системы. |
Гибкость в выборе подходов к транзакциям | Возможность использования различных подходов к обработке транзакций (например, BASE вместо ACID) в зависимости от требований приложения. | Могут возникнуть компромиссы по надежности и согласованности данных, так как некоторые подходы могут быть менее строгими по сравнению с традиционной моделью ACID. |
Ниже будет приведен пример компании, которая успешно внедрила распределенные базы данных для управления транзакциями в условиях высоких нагрузок. Так PayPal применяет распределенные базы данных для управления финансовыми транзакциями, что позволяет обрабатывать миллионы платежей и переводов ежедневно. Для поддержания высокой доступности и безопасности транзакций компания использует комбинацию HBase и MySQL, что обеспечивает устойчивость к сбоям и надежную поддержку транзакционных операций. Платформа PayPal поддерживает как внутренние операции, так и интеграции с множеством внешних сервисов, и распределенная структура базы данных позволяет снизить задержку отклика и поддерживать стабильную работу даже при высокой нагрузке. Также для аналитики и отслеживания транзакций в реальном времени компания использует инструменты из экосистемы Hadoop, что обеспечивает точность и скорость обработки данных в условиях высоконагруженной среды [8].
Данный пример подчеркивает, как распределенные базы данных помогают ведущим компаниям справляться с высокими нагрузками, обеспечивая стабильность, масштабируемость и низкую задержку отклика.
Заключение
В заключение следует отметить, что управление транзакциями в высоконагруженных системах представляет собой комплексный процесс, требующий применения специализированных подходов для обеспечения согласованности и надёжности данных. В условиях интенсивной нагрузки и распределённой архитектуры использование традиционных централизованных механизмов транзакционной обработки оказывается недостаточным для удовлетворения требований к производительности и масштабируемости. Проведённый анализ показывает, что применение двухфазной фиксации и паттерна Saga позволяет эффективно управлять распределёнными транзакциями, снижая риск ошибок и несогласованности данных. Паттерн Saga особенно актуален для асинхронных систем, где требуется последовательное выполнение множества операций с возможностью компенсации в случае сбоя. Двухфазная фиксация обеспечивает согласованное завершение транзакций, но требует тщательной координации между узлами, что может снижать производительность при увеличении числа участников.
Таким образом, работа продемонстрировала, что для успешного управления транзакциями в высоконагруженных распределённых системах необходимо учитывать специфику распределённых баз данных и выбирать методы, соответствующие характеру системы. Оценка применимости различных подходов к управлению транзакциями показала, что для обеспечения надёжности и устойчивости системы критически важны правильный выбор стратегии фиксации данных и способность системы к быстрому восстановлению после сбоев.