«Управляемый» (managed) сервис — это когда вы пользуетесь технологией, а её обслуживанием занимается провайдер. Своя база на сервере — это вы сами ставите PostgreSQL, настраиваете копии, по ночам чините. Управляемая база — та же PostgreSQL, но копии, замену сломанного узла и обновления делает Azure. Вы платите за это деньгами, но не временем и не бессонными ночами.
Главная ценность облака для backend-разработчика — не виртуальные машины, а именно управляемые данные: базы, кэши, очереди и брокеры. Эта статья — карта соответствий «то, что вы знаете по своему серверу → как это называется в Azure», и честный список того, что managed-сервис за вас не делает.
Четыре управляемых хранилища и то, что остаётся вашим у каждого: размер пула и способ подключения у базы, сроки жизни и политика вытеснения у кэша, идемпотентность у очереди, число разделов у потока.
Azure Database for PostgreSQL
Azure Database for PostgreSQL — тот же PostgreSQL, только вокруг него автоматика: резервные копии с восстановлением на момент в прошлом, зоно-избыточная высокая доступность, обновления версий в заданное окно. Аналог RDS в AWS. Полное имя сервиса — Flexible Server, и выбирать тут не из чего: прежний вариант Single Server выведен из эксплуатации, так что Single Server в старой документации — уже история.
Главное для новичка: managed-база снимает с вас эксплуатацию железа, но не проектирование данных. Она спасёт от сгоревшего диска, но не от запроса SELECT без индекса, перебирающего миллион строк. Схема, индексы, блокировки, безопасные миграции, тюнинг медленных запросов — по-прежнему ваша работа.
Грабли, на которые наступают почти все, — лимит соединений: у базы есть максимум одновременных подключений, и десяток приложений со своими пулами выедают его незаметно. Лечится дисциплиной размеров пулов и встроенным пулером — PgBouncer. Только это не галочка «включил и забыл»: его поднимают параметром сервера pgbouncer.enabled, он слушает отдельный порт 6432 (приложение переводят на него), а на самом дешёвом тарифе Burstable его нет вовсе. И грабля при переключении: по умолчанию пулер работает в режиме транзакций, где поддержка подготовленных выражений выключена (pgbouncer.max_prepared_statements = 0), — приложение, которое их использует, на порту 6432 начнёт падать, пока этот параметр не подняли. Рядом в семействе — управляемый MySQL и Azure SQL Database (управляемый SQL Server); модель у всех одинаковая.
Соединения: откуда потолок и почему помогает пулер
«Лимит соединений» — главные грабли управляемой базы, и механику стоит понимать, иначе лечение выглядит магией.
Почему у PostgreSQL есть потолок. Каждое соединение — это отдельный процесс операционной системы со своей памятью (единицы-десятки мегабайт, в зависимости от того, что делает запрос). Сто соединений — это сто процессов; тысяча означает, что память кончится раньше, чем процессор. Поэтому предел (max_connections) в управляемой базе задаётся платформой по объёму памяти выбранного размера: у самых маленьких это десятки соединений, у средних — несколько сотен. Посмотреть своё значение можно запросом SHOW max_connections;, и это первое, что стоит сделать до расчёта пулов.
Как это выедается незаметно. Пять экземпляров приложения по двадцать соединений в пуле — это сто соединений, которые держатся постоянно, даже когда запросов нет. Добавьте конвейер, миграции, инструмент аналитики, чью-то локальную отладку — и потолок близко. Симптом: новые подключения получают отказ too many connections, причём первым отказ получает не тяжёлый сервис, а тот, кто подключился последним.
Почему помогает пулер. Пулер (в управляемом PostgreSQL Azure есть встроенный) держит небольшое число реальных соединений к базе и мультиплексирует через них запросы многих клиентов: пока клиент не выполняет запрос, его соединение к базе не занято. Тысяча клиентов превращается в тридцать процессов на стороне базы.
Оговорка, без которой это ломается: в режиме мультиплексирования по транзакциям (обычный режим пулера) не работают вещи, привязанные к сеансу, — подготовленные запросы на уровне сеанса, временные таблицы, SET на сеанс, рекомендательные блокировки. Часть библиотек доступа к данным использует подготовленные запросы по умолчанию, и это надо либо выключить, либо перевести в режим, который пулер поддерживает.
Что делают на практике: считают сумму пулов по всем потребителям и сверяют с пределом базы (с запасом на служебные подключения), ставят размер пула от нагрузки, а не по привычке (десять соединений на экземпляр — обычно с избытком), включают встроенный пулер там, где потребителей много или они короткоживущие (функции, задачи), и ставят оповещение на число активных соединений — это одна из метрик, которые база отдаёт сама.
Как приложение дотягивается до базы
Выбор способа подключения делается при создании базы и потом не меняется — поэтому решить его надо заранее.
Приватный доступ (интеграция с виртуальной сетью). База получает адрес в вашей подсети и публичного адреса не имеет вовсе. Это правильный вариант для боевого контура: до базы нельзя дотянуться из интернета в принципе, права на сеть решают, кто к ней ходит. Цена: приложение должно быть в той же сети или в связанной — а значит, вариант размещения приложения выбирается вместе с этим решением (об этом статья про вычисления).
Публичный доступ с правилами межсетевого экрана. У базы есть публичный адрес, и доступ разрешён перечисленным диапазонам адресов. Проще в настройке и хуже по двум причинам: адреса исходящего трафика у платформенных сервисов меняются, так что правила приходится держать целыми диапазонами; и одна ошибка в правилах (или отдельная галочка «разрешить доступ сервисам Azure») открывает базу заметно шире, чем вы думали.
Отсюда простое правило: боевая база — приватный доступ, всегда. Публичный оставляют для стендов, где важнее простота, и даже там список разрешённых адресов не должен превращаться в «разрешить всё».
Две детали, которые идут в комплекте. При приватном доступе нужна приватная зона имён, иначе имя базы продолжает разрешаться в публичный адрес — это самая частая поломка, и разбирает её статья про сеть. А шифрование соединения (sslmode=require и проверка сертификата) включают независимо от способа доступа: приватная сеть не отменяет шифрования.
Azure Cache for Redis
Кэш — быстрое временное хранилище, куда кладут уже посчитанный результат, чтобы не считать заново. Azure Cache for Redis — управляемый Redis: кластер, реплики и переключение при сбое настраивает облако. Аналог ElastiCache в AWS.
Для новых проектов смотрите на преемника — Azure Managed Redis. Старую линейку Azure Cache for Redis (тарифы Basic, Standard, Premium) объявили уходящей: с 1 октября 2026 года новые такие кэши создать уже нельзя, а 30 сентября 2028 года оставшиеся отключат. Модель работы та же, меняются название и тарифы.
Применяют как обычный Redis: кэширование ответов с временем жизни (TTL), распределённая блокировка, ограничение частоты запросов. Главное правило новичку: кэш — это не база данных. Данные, потеря которых недопустима (заказы, платежи), в нём не хранят: кэш может сбросить содержимое в любой момент.
Что с кэшем, когда память кончилась
Про кэш сказано «это не база данных», и стоит добавить, что именно происходит при заполнении памяти — потому что от настройки зависит, что вы потеряете.
Политика вытеснения решает, кого удалять, когда память заполнена. Значения разные, и практический выбор — между двумя:
allkeys-lru— вытесняется любой ключ, к которому давно не обращались. Правильный выбор для чистого кэша: потеря записи означает лишний запрос к базе, и ничего больше.volatile-lru— вытесняются только ключи со сроком жизни. Правильный выбор, когда в том же кэше лежат вещи, терять которые нельзя молча (например, распределённые блокировки): у них срока жизни нет, и они защищены от вытеснения. Обратная сторона: если ключей без срока жизни станет много, память заполнится ими, и новые записи начнут получать отказ.
Отсюда практическое правило: если в кэше лежит только кэш — allkeys-lru и обязательный срок жизни у всего. Если в кэше живут блокировки, счётчики или что-то ещё важное — либо volatile-lru с дисциплиной, либо, что чище, отдельный экземпляр под такие данные.
И то, что теряется первым при любой политике: то, к чему давно не обращались. Значит, редко используемые, но дорогие в пересчёте значения — плохие кандидаты на кэш без запаса памяти.
Service Bus и Storage Queues
Сервис отправки писем лёг — и вместе с ним лёг заказ, который всего лишь хотел отправить письмо. Очередь развязывает отправителя и получателя: приложение кладёт задачу и идёт дальше, а обработчик разгребает её в своём темпе. Для очередей в Azure два инструмента:
- Storage Queues — простая очередь: положить задачу, забрать задачу. Годится для базовой разгрузки.
- Service Bus — полноценный брокер с очередями и темами (topics): темы дают модель «публикация-подписка», когда одно сообщение получают несколько независимых подписчиков; плюс дедупликация, транзакции и упорядочивание. Про порядок важно не обмануться: сам по себе он не гарантируется. Порядок держится либо внутри сессии (сообщения с одним идентификатором сессии достаются одному обработчику и идут подряд), либо когда получатель ровно один. Поставили рядом несколько конкурирующих обработчиков ради скорости — порядок сломался. Это выбор для серьёзной обработки сообщений.
Так сглаживают всплески и не теряют задачи при недоступности обработчика. Service Bus часто служит триггером для Azure Functions.
Event Hubs
Когда нужна не очередь задач, а поток событий, который читают несколько независимых потребителей и перечитывают историю, берут Event Hubs — сервис потоковой передачи, к которому можно подключиться по протоколу Apache Kafka. Здесь легко ошибиться с аналогией: это не управляемая Kafka, а собственный движок Azure, умеющий разговаривать по её протоколу. Часть кафкиных возможностей на нём недоступна: точки входа Kafka нет на базовом тарифе, транзакции и Kafka Streams живут только на старших. По модели он ближе к Kinesis Data Streams из AWS, чем к MSK — настоящая Kafka в AWS это как раз MSK. Разницу между очередью и брокером-логом и устройство Kafka разбирает раздел Kafka.
Управляемый против своего: как выбирать
| Управляемый | Свой на сервере | |
|---|---|---|
| Эксплуатация | Копии, переключение, обновления — облако | Всё ваше, включая три часа ночи |
| Цена | Надбавка к стоимости железа | Дешевле железом, дороже людьми |
| Контроль | Версии и параметры из списка облака | Любые расширения и тонкая настройка |
Разумное правило: компоненты с состоянием (базы, кэши, очереди) берём управляемыми, пока нет конкретной причины делать иначе. Прежде чем самому обслуживать базу при доступном managed-сервисе, честно ответьте, на что команда потратит время, которое сервис ей освобождает.
Где это применяется
Управляемые данные — костяк почти любого сервиса: база под основные данные, кэш перед ней, очередь для фоновых задач, брокер для событий. Всё это живёт во внутренней сети без публичных адресов и доступно приложению через managed identity.
Типичные ошибки новичков:
- хранят важные данные в кэше — теряют при сбросе;
- выедают лимит соединений к базе без пулера;
- берут свой сервер там, где хватило бы managed;
- дают базе публичный IP ради удобства — открывают её сканерам.
Глубже: реплики, обслуживание и обрывы соединенийрасширенное
Три свойства управляемой базы, о которых узнают в неподходящий момент.
Реплики для чтения. Управляемый PostgreSQL умеет создавать реплики, и с них можно читать — отчёты, аналитику, тяжёлые выборки. Две оговорки: реплика асинхронная, то есть данные на ней отстают (обычно миллисекунды, под нагрузкой больше), и приложение должно знать, что читать с неё можно не всё — прочитать только что записанное с реплики нельзя. Подключение к реплике — это отдельный адрес, то есть в приложении появляется второй источник данных и решение «какой запрос куда».
Окно обслуживания. Платформа обновляет базу (версии, исправления безопасности) в заданное окно — день недели и час, которые вы выбираете сами. Это лучше, чем «когда угодно», и это по-прежнему означает перерыв: обновление обычно перезапускает сервер.
И главное: обслуживание и переключение рвут соединения. Плановое обновление, переключение на резервный экземпляр при отказе зоны, масштабирование размера — всё это означает, что открытые соединения обрываются, а адрес остаётся тем же. Приложение обязано это переживать: пул должен обнаруживать мёртвые соединения и открывать новые, а запросы — повторяться на ошибке соединения (но не на ошибке выполнения, иначе повторится то, чего повторять нельзя).
Что настраивают в приложении, чтобы обслуживание проходило незаметно: проверку соединения перед выдачей из пула, ограничение времени жизни соединения (чтобы пул сам обновлял их), таймауты на подключение и на запрос, и повтор на ошибках соединения с небольшой паузой. Без этого плановое обслуживание в три часа ночи превращается в утренний разбор «почему сервис не поднялся сам».
Глубже: лавина одинаковых промаховрасширенное
Отдельная беда, которая случается ровно в момент, когда кэш нужнее всего. Популярный ключ истёк; в ту же секунду сто параллельных запросов не находят его в кэше — и все сто идут считать одно и то же в базу. База получает стократную нагрузку на ровном месте, отвечает медленно, запросы копятся, и дальше по знакомому сценарию.
Три приёма, которые это лечат:
Блокировка на пересчёт. Первый, кто обнаружил промах, берёт короткую блокировку (в том же кэше) и считает; остальные либо ждут результата, либо отдают чуть устаревшее значение. Реализуется в десять строк и закрывает самый острый случай.
Обновление до истечения. Ключ хранится с двумя сроками: «свежий до» и «годен до». Пока значение свежее, отдаём его; когда свежесть кончилась, но срок не вышел, — отдаём старое значение и запускаем пересчёт в фоне. Пользователь никогда не ждёт пересчёта, а лавины нет по определению.
Разброс сроков жизни. Если сто ключей записаны одновременно с одинаковым сроком, они и истекут одновременно. Добавление случайной добавки к сроку (скажем, ±10 %) размазывает истечение по времени — приём копеечный и работает.
Плюс общая мера, которая помогает и здесь: ограничение параллельных обращений к базе из приложения. Тогда даже лавина промахов не превращается в сто одновременных запросов.
Глубже: числа, по которым выбирают очередьрасширенное
Разница между простой очередью хранилища и служебной шиной сводится к нескольким конкретным пределам, и вот они.
| Свойство | Storage Queue | Service Bus (Standard) |
|---|---|---|
| Максимальный размер сообщения | 64 КБ | 256 КБ (у Premium — до 100 МБ) |
| Срок хранения сообщения | по умолчанию 7 дней (настраивается) | по умолчанию 14 дней |
| Порядок сообщений | не гарантируется | гарантируется внутри сеанса |
| Очередь недоставленных | нет (делают руками отдельной очередью) | встроенная |
| Темы и подписки (один ко многим) | нет | есть, с фильтрами |
| Транзакции и дедупликация | нет | есть |
| Цена | за операции, очень дёшево | за операции плюс уровень, дороже |
Как этим пользоваться при выборе. Простая очередь задач внутри своего сервиса, сообщения маленькие, порядок не важен — очередь хранилища: дешевле и проще некуда. Нужен порядок, очередь недоставленных из коробки, темы с подписками, дедупликация или сообщения больше 64 КБ — служебная шина.
И правило про размер, которое действует в обоих случаях: в сообщении едет ссылка, а не данные. Файл, изображение, большой отчёт кладут в хранилище объектов, а в сообщении передают путь. Тогда предел размера перестаёт быть ограничением вовсе, а очередь остаётся быстрой.
Глубже: Event Hubs: что нужно знать, кроме «это как Kafka»расширенное
Отсылки к статье про Kafka мало, потому что решения принимаются по четырём понятиям, и у них здесь свои имена.
Разделы (partitions). Поток делится на разделы, и это единица параллелизма: сообщения одного раздела читаются по порядку одним читателем. Число разделов задают при создании и обычно не меняют — значит, его считают заранее, от нужной пропускной способности и числа читателей. Правило то же, что в Kafka: разделов не меньше, чем планируется параллельных обработчиков.
Группы потребителей (consumer groups). Каждая группа читает поток независимо и держит своё положение. То есть один поток событий обслуживает и обработку заказов, и аналитику, и архивирование — каждый в своём темпе и со своим отставанием. Добавление новой группы не мешает существующим.
Срок хранения. События живут заданное время (у обычного уровня от одного до семи дней) и удаляются независимо от того, прочитал их кто-нибудь или нет. Отсюда практическое следствие: отставание читателя опаснее, чем кажется — если он отстанет больше срока хранения, данные уедут безвозвратно. Отставание группы — главная метрика, на которую ставят сигнал.
Единицы пропускной способности. Ёмкость покупается единицами, каждая даёт свой предел на приём и на отдачу в секунду (и по объёму, и по числу событий). Превышение — не отказ навсегда, а ограничение частоты: отправитель получает отказ и должен повторить. Единицы можно менять и можно включить автоматическое увеличение — это одна настройка, и её стоит включить, чтобы всплеск не превращался в потерю событий на отправителе.
Отдельно стоит знать про захват в хранилище (Capture): поток можно автоматически складывать в хранилище объектов файлами — дешёвый архив всех событий без единой строки кода. Это тот ответ, который нужен, когда «хотим хранить события год», а срок хранения потока — семь дней.
И выбор между потоком событий и очередью, если коротко: очередь — это задачи для одного получателя, которые исчезают после обработки; поток — это факты, которые читают несколько независимых подсистем и которые можно перечитать. Подробное сравнение двух моделей — в статье про выбор между брокерами.
Коротко
- Управляемый PostgreSQL снимает эксплуатацию железа, но не проектирование данных: копии, зоно-избыточная доступность и окно обновлений у облака, схема, индексы и размер пула ваши.
- Соединение это процесс с памятью, и пулы пяти экземпляров выедают потолок незаметно: считают сумму пулов, ставят размер от нагрузки и включают встроенный пулер, помня, что в режиме по транзакциям не работает сеансовое.
- Способ подключения выбирают при создании и потом не меняют: боевая база с приватным доступом и приватной зоной имён, публичный доступ по адресам только для стендов.
- Реплики для чтения асинхронные и отстают, окно обслуживания это перезапуск, а обслуживание и переключение рвут соединения: проверка соединения перед выдачей, ограничение срока жизни, таймауты и повтор при обрыве.
- Кэш это не база: для нового проекта Azure Managed Redis, allkeys-lru и обязательный срок жизни для чистого кэша, volatile-lru, если рядом живут блокировки.
- Лавину одинаковых промахов гасят блокировкой на пересчёт, обновлением до истечения, разбросом сроков жизни и ограничением параллельных обращений к базе.
- Storage Queue дёшев и прост для задач без порядка, Service Bus даёт темы с подписками, очередь недоставленных, порядок в сеансе, транзакции и дедупликацию; в сообщении едет ссылка, а не файл.
- Event Hubs это поток фактов для нескольких независимых читателей: разделы задают параллелизм и не меняются, группы потребителей держат своё положение, срок хранения удаляет непрочитанное, ёмкость покупается единицами, Capture складывает поток в хранилище.
- Компоненты с состоянием берут управляемыми, пока нет конкретной причины делать иначе, и считают полную цену владения.
Что почитать дальше
- Cosmos DB — когда обычной базы мало и нужен глобальный масштаб.
- Blob Storage — куда кладут файлы, на которые ссылаются сообщения.
- Подключение SDK — как обращаться к этим сервисам из кода.
- Управляемые данные в облаке — та же модель без привязки к провайдеру.