Счет в $18.5k от Aurora: почему расходы на storage I/O увеличиваются при масштабировании?
Наша база данных AWS Aurora PostgreSQL объемом 12TB обходилась более чем в $18 500 ежемесячно из-за основного инстанса db.r6g.16xlarge, двух read replicas и неограниченного тарифообложения I/O. Стандартное ценообразование Aurora берет $0.20 за 1 миллион I/O-запросов. При гибридной нагрузке, генерирующей 45 000 read/write IOPS, только storage I/O составлял 42% нашего ежемесячного счета. Переход на Aurora I/O-Optimized снизил плату за запрос, но увеличил базовую стоимость compute на 30%, сохранив общие расходы на уровне $16 200 в месяц. Переход на managed bare metal с корпоративными локальными накопителями NVMe полностью устранил повременную оплату I/O, снизив ежемесячные расходы на оборудование до $7 800.
В октябре 2023 года мы потратили три недели на попытки оптимизировать запросы к базе данных, прежде чем поняли, что сама архитектура log-structured хранилища являлась первопричиной финансовых проблем.
Разбор механизма биллинга I/O в Aurora
Aurora разделяет compute и storage с помощью проприетарного log-structured распределенного тома. Каждая операция записи сбрасывает записи Write-Ahead Logging (WAL) на шесть узлов хранения в трех Availability Zones. Каждая запись лога фиксируется как тарифицируемый I/O-запрос. В высоконагруженных транзакционных системах с частыми обновлениями индексов избыточность записи (write amplification) приводит к нелинейному росту потребления I/O относительно объема данных.
При анализе метрик движка PostgreSQL через pg_statio_user_tables вместе с данными CloudWatch мы обнаружили серьезное проседание производительности из-за промахов буферного кэша во время ночной пакетной загрузки. Использования инстансов db.r6g.16xlarge с 512GB RAM было недостаточно, чтобы предотвратить падение коэффициента попадания в кэш ниже 94% при росте рабочего набора. Эти промахи кэша приводили к чтениям из хранилища, которые немедленно тарифицировались как read IOPS.
Как сопоставляются производительность и затраты Aurora и Managed Bare Metal?
Managed bare metal заменяет виртуализированный уровень хранения Aurora выделенными физическими серверами, подключенными напрямую к корпоративным NVMe-накопителям в RAID 10. Aurora реплицирует записи логов по сети между шестью узлами, что добавляет задержку записи при высокой транзакционной нагрузке. Bare metal инстансы обходят накладные расходы сетевого хранилища за счет прямого подключения дисков PCIe Gen4, обеспечивая чистую производительность записи без конкуренции на уровне гипервизора.
Развертывание физических узлов с процессорами AMD EPYC 9654 (96 ядер, 192 потока, 1.5TB RAM) и корпоративными дисками PCIe 4.0 NVMe снизило задержку записи p99 с 4.8ms в Aurora до 0.7ms на bare metal, а пропускная способность последовательного чтения выросла в четыре раза.
| Компонент метрики / архитектуры | AWS Aurora PostgreSQL (Standard) | AWS Aurora (I/O-Optimized) | Managed Bare Metal (RAID 10 NVMe) |
|---|---|---|---|
| Ежемесячная базовая стоимость (12TB DB) | $18,500 | $16,200 | $7,800 |
| Архитектура хранилища | Распределенная Log-Structured (сетевая на базе EBS) | Распределенная Log-Structured (сетевая на базе EBS) | Прямо подключенные PCIe Gen4 NVMe (RAID 10) |
| Плата за I/O | $0.20 за 1M единиц запросов | Включена в базовую цену compute | Не тарифицируется (включена в аренду) |
| Задержка записи (p99) | 4.8 ms | 4.5 ms | 0.7 ms |
| Ограничение пропускной способности чтения | Ограничена сетевым интерфейсом (до 40 Gbps) | Ограничена сетевым интерфейсом (до 40 Gbps) | Локальная шина PCIe (~26 GB/sec последовательно) |
| Накладные расходы на обработку соединений | Высокие (требуется RDS Proxy для >5k соед.) | Высокие (требуется RDS Proxy для >5k соед.) | Нативные + локальный PgBouncer (маршрутизация <1ms) |
Как заменить RDS Proxy на оптимизированный на уровне ядра PgBouncer?
Замена AWS RDS Proxy потребовала запуска инстансов PgBouncer в режиме transaction pooling на нашей инфраструктуре баз данных. RDS Proxy берет $0.015 за vCPU-час и добавляет до 3ms задержки на каждый транзакционный хоп. Развертывание PgBouncer на выделенных шлюзовых узлах bare metal с настройкой параметров сетевых сокетов ядра Linux позволило нам мультиплексировать 15 000 параллельных соединений приложений в 150 бэкенд-соединений на каждый инстанс базы данных.
Изначально мы пытались запустить PgBouncer внутри контейнера Docker на хосте в режиме транзакций, но столкнулись с жесткими ограничениями выделения сокетов во время всплесков трафика в январе 2024 года.
Оптимизация сокетов ядра и конфигурация PgBouncer
PostgreSQL порождает отдельный процесс операционной системы для каждого клиентского соединения, потребляя от 2MB до 10MB RAM в зависимости от настроек work_mem. Чтобы справляться с быстрыми всплесками соединений без RDS Proxy, мы настроили лимиты ядра в /etc/sysctl.conf и перевели PgBouncer в режим транзакций.
# /etc/sysctl.conf - Network kernel tuning for high-concurrency DB
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
vm.overcommit_memory = 2
vm.overcommit_ratio = 80Сопутствующий файл конфигурации pgbouncer.ini маршрутизирует кратковременные соединения микросервисов в долгоживущие пулы серверов:
[databases]
app_production = host=127.0.0.1 port=5432 dbname=app_production pool_mode=transaction
[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
max_client_conn = 20000
default_pool_size = 150
min_pool_size = 30
reserve_pool_size = 20
max_db_connections = 300
server_idle_timeout = 60Как обеспечить высокую доступность с помощью Patroni и etcd?
Замена автоматической репликации хранилища Aurora потребовала построения архитектуры высокой доступности с использованием Patroni, etcd и HAProxy в трех физических стойках. Patroni отслеживает потоковую репликацию PostgreSQL и выполняет failover с использованием консенсуса Raft в etcd при сбое основного узла. HAProxy обновляет маршруты проверки состояния (health-check) для направления входящих записей на вновь промотированный primary-узел.
Консенсус и предотвращение Split-Brain
Aurora полагается на проприетарный том кворумного хранилища для предотвращения состояний split-brain. На bare metal мы развернули кластер консенсуса etcd из 3 узлов на отдельных хостах управления. Patroni взаимодействует с etcd для удержания ключей лидера через распределенные блокировки.
- Primary Node: обновляет блокировку лидера в etcd каждые 10 секунд.
- Replica Nodes: поддерживают асинхронную физическую потоковую репликацию по протоколам WAL с
hot_standby = on. - HAProxy Layer: опрашивает HTTP-эндпоинт Patroni (
/primaryи/replica) на порту 8008 для маршрутизации запросов записи на активный primary.
Если на primary-узле происходит сбой оборудования, etcd отзывает ключ лидера. Оставшиеся узлы проводят выборы, повышают standby с минимальным отставанием WAL и уведомляют HAProxy в течение 8 секунд.
Как мы мигрировали 12TB данных с даунтаймом менее 4 минут?
Миграция работающей базы данных размером 12TB с AWS с минимальным простоем потребовала объединения физических базовых резервных копий через pgBackRest с логической репликацией PostgreSQL через pgoutput. Мы развернули целевой кластер, инициализировали физический снапшот, настроили слоты логической репликации на primary-узле Aurora и организовали потоковую передачу событий Change Data Capture (CDC) для синхронизации сред. Переключение включало перевод Aurora в режим read-only, применение оставшихся последовательностей WAL, проверку смещений последовательностей и обновление эндпоинтов DNS.
Пошаговая последовательность миграции
- Извлечение схемы: Выгрузили схемы и индексы с помощью
pg_dump --schema-only, настроив параметры под оборудование bare metal (например,random_page_cost = 1.1). - Настройка логической репликации: Создали публикацию на исходном инстансе Aurora для всех таблиц:
CREATE PUBLICATION migration_pub FOR ALL TABLES;. - Первоначальный снапшот: Использовали параллельное массовое копирование через
pg_dumpиpg_restoreс партиционированием таблиц для копирования базового состояния. - Синхронизация CDC: Подписали кластер bare metal на публикацию с помощью
CREATE SUBSCRIPTION migration_sub CONNECTION '...' PUBLICATION migration_pub WITH (copy_data = false);. - Синхронизация последовательностей и переключение: Приостановили запись приложений, проверили контрольные суммы таблиц, синхронизировали автоинкрементные последовательности с помощью кастомных скриптов
setval()и перенаправили эндпоинты HAProxy. Общая продолжительность паузы записи составила 3 минуты и 42 секунды.
Каковы особенности эксплуатации: жизненный цикл NVMe и резервное копирование?
Переход с AWS Aurora на managed bare metal возвращает инженерам ответственность за мониторинг износа дисков, обслуживание хостового оборудования и восстановление на момент времени (PITR). Автоматические оповещения отслеживают метрики износа дисков, в то время как непрерывное архивирование WAL через pgBackRest передает данные в объектное хранилище.
В феврале 2024 года наш мониторинг зафиксировал повышенный уровень износа накопителя NVMe после четырех месяцев интенсивных транзакционных нагрузок, что позволило нам заменить диск во время планового окна обслуживания до возникновения ошибок чтения.
Жизненный цикл корпоративных хранилищ и стратегия бэкапов
В отличие от облачных томов хранилища, скрывающих состояние физических дисков, диски NVMe на bare metal имеют ограниченный ресурс записи, измеряемый в Drive Writes Per Day (DWPD). Мы настроили Prometheus Node Exporter для отслеживания параметров SMART — в частности smartctl_nvme_percentage_used и smartctl_nvme_critical_warning — для создания тикетов на замену оборудования до возникновения сбоев.
Для аварийного восстановления (Disaster Recovery) непрерывное архивирование WAL работает через pgBackRest, отправляя сжатые 16MB сегменты WAL в S3-совместимое объектное хранилище каждые 60 секунд. Эта конфигурация обеспечивает восстановление на момент времени с точностью до миллисекунды, изолируя вычислительные накладные расходы на бэкап от узлов базы данных.