Pattern

Масштабирование без потери производительности

TimeIcon

5 мин.

EyeIcon

10

scroll iconScroll

Масштабирование — одна из самых важных характеристик надежности программного обеспечения. Если ваши сервисы не смогут отреагировать на рост нагрузки, это негативно повлияет на пользовательский опыт и, как следствие, приведет к потерям для бизнеса. Определить, как правильно масштабировать ПО, практически невозможно, так как нужно сразу учесть множество факторов и возможных проблем. Это бесконечный процесс, состоящий из компромиссов, соблюдения требований и постоянной модернизации компонентов системы.

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

Что такое производительность в применении к масштабируемости?

Словарь терминов, сопровождающий любое планирование архитектуры и конкретно методологии масштабирования, обязательно содержит слово «производительность».

Производительность, которую мы хотим достичь, масштабируя систему, может быть измерена самыми разными способами. Можно использовать простой подход — запустить бенчмарк и прокачать несколько терабайт. Это поможет в тюнинге системы, анализе консистентности кворума, шифровании и других моментах. Более сложные тесты подразумевают включение более глубокого анализа самих данных и паттернов доступа к ним. Например, сценарии машинного обучения должны использовать те данные, которые ранее могли быть сохранены на диске, чтобы не хранить их в базе и не накладывать эти ограничения на общую систему. Индустрия ищет инструменты, позволяющие хранить и масштабировать все данные, что позволяет анализировать их общность, а не части.

Например, есть система с N микросервисов и одной базой данных. Сервисы создают Connection Pools к базе данных. Одно открытое подключение может обработать один запрос в один момент времени. В зависимости от конфигурации Connection Pool может содержать от 1 до 100 подключений. Масштабируя микросервисы, можно увеличить производительность, но заполнить пул подключений, что приведет к ожиданию клиентов. Здесь присутствует как архитектурная задача (как правильно масштабировать сервисы), так и администраторская (например, настройка max_connections).

Масштабирование и ACID

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

Чтобы лучше понять проблематику выбора, отойдем в сторону. Существует две вечных проблемы распределенных систем, которые нужно масштабировать. Это либо попытка сбалансировать систему с использованием постулатов CAP-теоремы и ACID, либо BASE.

Вертикальное масштабирование

Когда в системе планируется один PostgreSQL, по умолчанию присутствует транзакционность, потому что один процесс, есть контролер, который может одному треду сказать: «Вот этот ты только читаешь, вот этот тред только пишет». В реляционной базе много чего есть, она многое умеет и все видит. Вертикальное масштабирование никак ACID не мешает, поэтому транзакции все еще чувствуют себя хорошо. Но бесконечно или даже приемлемо для некоторых типов нагрузки масштабировать вертикально не получится по разным причинам.

Как только мы начинаем говорить о больших нагрузках, десятках тысяч RPS или начинаем шардировать нашу базу данных, появляются распределенные транзакции.

Горизонтальное масштабирование

Несколько реплик. Write теперь идет только на мастер, но все лишние чтения могут направляться на реплики. Соответственно, появляется задержка репликации, которая также бывает двух видов: синхронная и асинхронная. Этот важный момент регулярно упускается в планировании архитектуры. Команде разработки приходится думать, что делать, когда балансировщик отправит запрос, но при этом репликация еще не закончилась. Из-за горизонтального масштабирования кластера клиент получает устаревшие данные. Классическая задача.

Поэтому подходить к масштабированию необходимо с учетом того, чтобы сохранять характеристики базы данных. Горизонтально масштабировать БД и сохранять ACID может быть (и обычно) сложно, так как ACID требует Strong Сonsistency и Isolation. Это идет вразрез с практиками распределения данных и обработки на нескольких серверах.

Одним из вариантов сохранить ACID при горизонтальном масштабировании может стать шардинг, когда данные бьются на небольшие партиции и раскидываются по узлам.

Практически во всех случаях реляционные базы плохо шардируются, и самое простое решение — это использование кэша. Но кэш надо инвалидировать. В Tarantool мы для клиентов часто применяем паттерн Write Through кэша.

Это усложняет и систему, и мониторинг, и разработку, позволяет увидеть, насколько грамотно была спроектирована система и подходы к ее масштабированию и сопутствующим задачам ДО начала ее разработки. Необходимо выбрать правильную архитектуру приложения, которая позволит масштабировать его горизонтально.

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

Микросервисы и Loose Coupling

Принцип слабой связи (Loose Coupling) помогает устранить или минимизировать зависимости между сервисами и их потребителями. Это становится особенно важным в микросервисной архитектуре, так как слабая связность позволяет реализовать архитектуру, которую значительно проще тестировать и развертывать, в том числе в автоматическом режиме, применяя практики DevOps/DevSecOps. Однако излишнее увлечение микросервисностью и слабой связностью может привести к Dependency Hell (большому количеству связей между компонентами, которые сложно поддерживать) и проблемам с мониторингом.

Слабая связность в приложениях с базами данных должна быть спланирована с учетом двух факторов:

Количество сервисов, которое будет задето при изменениях данных либо структуры баз данных.

Контекстная связность.

Согласно известному архитектору Neal Ford, идея архитектурного кванта подразумевает, что, если два сервиса раздельны, но используют одну базу данных, они все еще обладают высокой связностью и мы не можем рассматривать их как по отдельности. Разбиение на мелкие кванты полезно, большие кванты разбили на микросервисы, но монолит остался. Это фундаментальная проблема планирования перехода на микросервисы, когда изначальная проблема не решается, но на нее накладывается дополнительный слой планирования, скрывая некоторые важные детали имплементации.

Так, иногда берут классические паттерны, которые используются для приложений: функциональность приложения разбивается на компоненты, создается абстракция, после чего применяются архитектурные паттерны, чтобы предоставить это пользователю. Использование этого подхода к базам данных может привести к тому, что базы данных будут восприниматься просто как хранилища объектов, которые могут обработать любую ситуацию. В случае реляционных баз данных, как уже было описано выше, это действительно так. Однако даже минимальные изменения (например, добавления внешних ключей) могут привести к регрессии или затратам в планировании изменений в программном коде, эксплуатации и автоматизации. Не говоря уже о более существенных изменениях в структуре базы.

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

Если полный переход на микросервисы является невыполнимой на данный момент задачей, то можно использовать Middleware-подход.

Заключение

В этой статье мы посмотрели на несколько важных нюансов, которые должны быть обдуманы во время планирования архитектуры. Попадание этих проблем в продакшен вызовет значительное увеличение нагрузки на всех, включая разработчиков (так как во время проблемы не будет времени на перепроектирование, необходимо будет разработать какой-то Workaround), так и эксплуатацию и безопасность. Необходимо будет эскалировать процессы тестирования и проверки новых релизов, это однозначно скажется на Time-to-market решения и может снизить качество процессов.

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

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

Так, сетевые вендоры сумели воспользоваться ситуацией и модернизировали свои подходы, внедрив Software Defined-методологию — перейдя, например, от железного определения и управления сетями к Software Defined Networks, что позволило изменить подход не только к масштабированию, но и к поддержке и производительности.

Читайте также

Middleware для IoT и цифровых двойников

Цифровые двойники позволяют создавать точные копии физических объектов или процессов в цифровом пространстве. Этот термин известен еще с 2002 года и подразумевает создание цифровых двойников реальных объектов в виртуальном мире для оптимизации производственных процессов — например, определения оптимального расположения оборудования на заводе или оптимизации логистики.
ArrayIcon

Как правильно приготовить «данные»? Тренды разработки 2023

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