SQL Server Always On: настройка групп доступности

SQL Server Always On группы доступности настройка

Always On Availability Groups в SQL Server обеспечивает отказоустойчивость баз данных путём синхронной или асинхронной репликации между несколькими серверами. Для настройки нужен Windows Server Failover Cluster, минимум два сервера с SQL Server Enterprise (или Standard для Basic AG) и немного терпения (настройка с первого раза получается редко, но дальше работает как часы).

Что такое Always On AG

Короче, Always On Availability Groups это механизм высокой доступности. Есть primary-реплика (основная) и secondary-реплики (резервные). Данные синхронизируются автоматически.

Если primary падает, secondary автоматически становится primary. Простой измеряется секундами, а не часами. Грубо говоря, пользователи даже не заметят переключения (ну, может, одно-два соединения оборвутся, но переподключение произойдёт автоматически).

На самом деле, AG работает на уровне баз данных, а не экземпляра. Вы выбираете какие базы реплицировать. Системные базы (master, msdb) не реплицируются. Это и плюс (гибкость), и минус (логины, Agent Jobs, серверные настройки нужно синхронизировать отдельно, хотя в SQL Server 2022 появились Contained AG, которые решают эту проблему).

AG vs другие методы высокой доступности

На самом деле AG это не единственный способ обеспечить отказоустойчивость SQL Server. Но самый популярный.

МетодУровеньАвтоматический failoverЛицензия
Always On AGБаза данныхДа (синхронный режим)Enterprise (полный) / Standard (Basic)
Failover Cluster InstanceЭкземплярДаStandard или Enterprise
Log ShippingБаза данныхРучнойЛюбая (даже Express)
Database MirroringБаза данныхДа (с witness)Standard (deprecated)
ReplicationОбъекты БДНетStandard или Enterprise

Тут такое дело: Database Mirroring помечен как deprecated с SQL Server 2012, но до сих пор используется в некоторых организациях. Microsoft рекомендует AG как замену. Короче, не используйте mirroring в новых проектах. Если вы ставите новый проект, используйте AG, не mirroring.

Предварительные требования

Требований много, и каждый из них критичен.

  • SQL Server Enterprise (или Standard для Basic AG с 2 репликами и 1 базой)
  • Windows Server Failover Clustering (WSFC) на всех узлах
  • Одинаковая версия SQL Server на всех узлах
  • Базы данных в режиме Full Recovery
  • Сетевая связность между узлами (выделенная сеть для репликации рекомендуется)
  • Active Directory (все узлы в одном домене)
  • Одинаковая сортировка (collation) на всех экземплярах
  • Свободные IP-адреса для Listener и кластера

Если честно, самое сложное это WSFC. Кластер Windows нужно настроить до того, как вы начнёте работу с AG. И если кластер настроен криво, AG работать не будет.

Шаг 1: Настройка WSFC

# Устанавливаем компонент Failover Clustering на обоих серверах
# Это первый шаг, без него AG не работает
Install-WindowsFeature Failover-Clustering -IncludeManagementTools

# Проверяем готовность кластера
# Тест должен пройти без критических ошибок
Test-Cluster -Node "SQL01","SQL02" -Verbose

# Создаём кластер
# IP-адрес для кластера должен быть свободен в сети
New-Cluster -Name "SQLCLUSTER" -Node "SQL01","SQL02" `
    -StaticAddress "192.168.1.50" -NoStorage

Мой коллега Виталий из Самары потратил два дня на настройку кластера, потому что не прошёл Test-Cluster. Оказалось, на одном из серверов Lenovo ThinkSystem SR630 была неправильная маска подсети. Грубо говоря, всегда запускайте Test-Cluster и читайте отчёт. Каждый warning может превратиться в проблему при работе AG.

Шаг 2: Включение Always On в SQL Server

# Включаем Always On на обоих экземплярах SQL Server
# Требуется перезапуск службы SQL Server
Enable-SqlAlwaysOn -ServerInstance "SQL01" -Force
Enable-SqlAlwaysOn -ServerInstance "SQL02" -Force

# Или через SQL Server Configuration Manager:
# Properties экземпляра, вкладка Always On High Availability
# Поставить галочку Enable Always On Availability Groups

# Перезапуск службы SQL Server (обязательно!)
Restart-Service MSSQLSERVER

После включения перезапустите службу SQL Server на обоих узлах. Без перезапуска не заработает. Кстати, это означает downtime. Планируйте обслуживание заранее и предупреждайте пользователей.

Шаг 3: Подготовка баз данных

-- Переключаем базу в Full Recovery Mode
-- AG работает только с Full Recovery
ALTER DATABASE [MyDatabase] SET RECOVERY FULL;

-- Делаем полный бэкап (обязателен перед добавлением в AG)
BACKUP DATABASE [MyDatabase] TO DISK = 'D:BackupMyDatabase_Full.bak';

-- Делаем бэкап лога (тоже обязателен)
BACKUP LOG [MyDatabase] TO DISK = 'D:BackupMyDatabase_Log.trn';

-- Проверяем, что база готова к добавлению в AG
-- Recovery model должна быть FULL
SELECT name, recovery_model_desc FROM sys.databases WHERE name = 'MyDatabase';

Знаете что? Частая ошибка: люди забывают сделать бэкап лога. Полный бэкап есть, а лог нет. AG требует оба. Без бэкапа лога вы получите ошибку при добавлении базы в группу доступности.

Шаг 4: Создание группы доступности

-- Создаём Endpoint для репликации на обоих серверах
-- Порт 5022 стандартный для AG
CREATE ENDPOINT [Hadr_endpoint]
    STATE = STARTED
    AS TCP (LISTENER_PORT = 5022)
    FOR DATA_MIRRORING (ROLE = ALL);

-- Даём права на подключение к endpoint
-- Используем сервисную учётку SQL Server
GRANT CONNECT ON ENDPOINT::[Hadr_endpoint] TO [CONTOSOsvc-sqlengine];

-- Создаём группу доступности
CREATE AVAILABILITY GROUP [AG-Production]
WITH (
    AUTOMATED_BACKUP_PREFERENCE = SECONDARY,
    DB_FAILOVER = ON
)
FOR DATABASE [MyDatabase]
REPLICA ON
    N'SQL01' WITH (
        ENDPOINT_URL = N'TCP://SQL01.contoso.local:5022',
        FAILOVER_MODE = AUTOMATIC,
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        SEEDING_MODE = AUTOMATIC
    ),
    N'SQL02' WITH (
        ENDPOINT_URL = N'TCP://SQL02.contoso.local:5022',
        FAILOVER_MODE = AUTOMATIC,
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        SEEDING_MODE = AUTOMATIC
    );

-- Создаём Listener (DNS-имя для приложений)
-- Приложения подключаются к Listener, а не к конкретному серверу
ALTER AVAILABILITY GROUP [AG-Production]
ADD LISTENER N'AG-LISTENER' (
    WITH IP ((N'192.168.1.51', N'255.255.255.0')),
    PORT = 1433
);

На самом деле Listener это ключевой компонент. Приложения подключаются к имени Listener (например, AG-LISTENER), а не к конкретному серверу. При failover DNS-запись автоматически переключается на новый primary. Приложение даже не заметит, что сервер поменялся (ну, кроме разрыва текущего соединения).

Шаг 5: Присоединение secondary

-- На secondary-сервере (SQL02)
-- Присоединяем экземпляр к группе доступности
ALTER AVAILABILITY GROUP [AG-Production] JOIN;

-- Если используем Automatic Seeding
-- База скопируется автоматически
ALTER AVAILABILITY GROUP [AG-Production]
GRANT CREATE ANY DATABASE;

Знаете что? Automatic Seeding появилось в SQL Server 2016 и сильно упростило жизнь. Раньше нужно было вручную восстанавливать бэкап на secondary. Сейчас SQL Server делает это сам. По факту, для баз до 100 ГБ Automatic Seeding работает отлично. Для очень больших баз (500+ ГБ) может быть быстрее скопировать бэкап вручную.

Проверка и мониторинг

-- Проверяем состояние AG
-- synchronization_state должен быть SYNCHRONIZED
SELECT
    ag.name AS AGName,
    ar.replica_server_name,
    ars.role_desc,
    drs.synchronization_state_desc,
    drs.synchronization_health_desc
FROM sys.dm_hadr_availability_replica_states ars
JOIN sys.availability_replicas ar ON ars.replica_id = ar.replica_id
JOIN sys.availability_groups ag ON ar.group_id = ag.group_id
JOIN sys.dm_hadr_database_replica_states drs ON ars.replica_id = drs.replica_id;

-- Проверяем задержку репликации
-- Redo queue и send queue должны быть близки к 0
SELECT
    ag.name AS AGName,
    ar.replica_server_name,
    drs.database_name,
    drs.redo_queue_size AS RedoQueueKB,
    drs.log_send_queue_size AS SendQueueKB
FROM sys.dm_hadr_database_replica_states drs
JOIN sys.availability_replicas ar ON drs.replica_id = ar.replica_id
JOIN sys.availability_groups ag ON ar.group_id = ag.group_id;

В SSMS есть визуальный Dashboard для мониторинга AG. Правой кнопкой по группе доступности → Show Dashboard. Там видно состояние репликации, задержку, здоровье каждой реплики. Кстати, этот Dashboard реально удобный. Одним взглядом видно, всё ли в порядке.

Типичные проблемы

Если честно, AG капризная штука. И проблемы возникают чаще, чем хотелось бы. Вот частые проблемы:

  • Endpoint не доступен. Проверьте файрвол (порт 5022) и права на endpoint
  • База не синхронизируется. Проверьте Recovery Mode (должен быть Full) и наличие бэкапа лога
  • Automatic Failover не работает. Нужен кворум в кластере и режим SYNCHRONOUS_COMMIT
  • Медленная синхронизация. Отдельная сеть для репликации, проверьте пропускную способность
  • Логины отсутствуют на secondary. Синхронизируйте вручную или используйте Contained AG (SQL 2022)

Николай, DBA из Краснодара, настраивал AG на двух Dell PowerEdge R640. Синхронизация работала, но с задержкой 30 секунд. Оказалось, репликация шла через обычную сеть, которая была загружена бэкапами. Выделил отдельный VLAN для AG и задержка упала до миллисекунд. На самом деле, выделенная сеть для AG это не рекомендация, а необходимость для продакшена.

Лицензирование

Для полноценных AG нужен SQL Server Enterprise. Для Basic AG (2 реплики, 1 база) достаточно Standard. Passive secondary-реплика не требует отдельной лицензии, если используется только для отказоустойчивости (не для чтения).

Лицензии SQL Server Enterprise и Standard, и Windows Server для кластерных узлов можно приобрести в keytrust24.store. Ну и не забудьте, что каждому узлу кластера нужна своя лицензия Windows Server. Тут такое дело: экономить на лицензировании AG не стоит, потому что штрафы при аудите Microsoft обойдутся значительно дороже. А ещё, если используете secondary для чтения (read-only routing), на неё тоже нужна лицензия SQL Server.

Read-Only Routing: используем secondary для чтения

Кстати, secondary-реплику можно использовать не только для failover, но и для чтения. Это называется Read-Only Routing. Запросы на чтение (SELECT) идут на secondary, а запросы на запись (INSERT, UPDATE, DELETE) на primary. Нагрузка распределяется между серверами.

-- Настраиваем Read-Only Routing на primary
ALTER AVAILABILITY GROUP [AG-Production]
MODIFY REPLICA ON N'SQL01' WITH (
    PRIMARY_ROLE (READ_ONLY_ROUTING_LIST = (N'SQL02'))
);

ALTER AVAILABILITY GROUP [AG-Production]
MODIFY REPLICA ON N'SQL02' WITH (
    SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY),
    READ_ONLY_ROUTING_URL = N'TCP://SQL02.contoso.local:1433'
);

-- В строке подключения приложения добавляем:
-- ApplicationIntent=ReadOnly
-- Тогда приложение автоматически пойдёт на secondary

Грубо говоря, если у вас есть тяжёлые отчёты, которые нагружают primary, перенесите их на secondary через Read-Only Routing. Primary будет обслуживать только транзакционную нагрузку, а отчёты пойдут на вторичный сервер. Вот в чём прикол: вы получаете два сервера по цене одной дополнительной лицензии (ну, если используете secondary для чтения, лицензия на неё нужна).

Contained Availability Groups в SQL Server 2022

Кстати, в SQL Server 2022 появились Contained AG, которые решают одну из самых раздражающих проблем Always On: синхронизацию логинов, Agent Jobs и серверных настроек между репликами.

Раньше было так: создал логин на primary, забыл создать на secondary. При failover приложение не может подключиться, потому что логин не существует на новом primary. Знакомо? Каждый DBA хотя бы раз попадал в эту ситуацию.

-- Создание Contained AG (SQL Server 2022+)
CREATE AVAILABILITY GROUP [AG-Contained]
WITH (
    CONTAINED,
    DB_FAILOVER = ON
)
FOR DATABASE [MyDatabase]
REPLICA ON
    N'SQL01' WITH (
        ENDPOINT_URL = N'TCP://SQL01.contoso.local:5022',
        FAILOVER_MODE = AUTOMATIC,
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        SEEDING_MODE = AUTOMATIC
    ),
    N'SQL02' WITH (
        ENDPOINT_URL = N'TCP://SQL02.contoso.local:5022',
        FAILOVER_MODE = AUTOMATIC,
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        SEEDING_MODE = AUTOMATIC
    );

-- Создание логина внутри Contained AG
-- Этот логин автоматически реплицируется на secondary
CREATE LOGIN [app_user] WITH PASSWORD = 'StrongP@ssw0rd!';
-- Теперь при failover логин будет на обеих репликах

По факту, Contained AG это база master для группы доступности. Логины, Agent Jobs, учётные данные хранятся внутри AG и реплицируются автоматически. Это убирает целый класс проблем при failover. Если вы ставите новый проект на SQL Server 2022, используйте Contained AG. Без вариантов.

Тестирование Failover: как проверить, что всё работает

Знаете что, настроить AG это полдела. Нужно убедиться, что failover реально работает. Не ждите, пока primary упадёт в продакшене, проверьте заранее.

-- Ручной failover на secondary (из SSMS или T-SQL)
-- Выполняем на текущем secondary (SQL02)
ALTER AVAILABILITY GROUP [AG-Production] FAILOVER;

-- Проверяем, что SQL02 стал primary
SELECT replica_server_name, role_desc
FROM sys.dm_hadr_availability_replica_states ars
JOIN sys.availability_replicas ar ON ars.replica_id = ar.replica_id;

-- Переключаем обратно (выполняем на SQL01)
ALTER AVAILABILITY GROUP [AG-Production] FAILOVER;

По факту, тестируйте failover раз в квартал. Запланируйте обслуживание, предупредите пользователей, переключите реплики туда-обратно. Убедитесь, что приложения нормально переживают разрыв соединения. Лучше обнаружить проблему в плановом режиме, чем в 3 часа ночи при реальном сбое.

Короче, настройка AG это инвестиция. Она требует времени, знаний и денег (минимум два сервера + Enterprise). Но когда primary упадёт в 3 часа ночи, и secondary автоматически подхватит нагрузку, а вы узнаете об инциденте только утром из уведомления, вы скажете спасибо прошлому себе. Без AG вас бы разбудили звонком в 3 часа, и вы провели бы полночи, восстанавливая базу из бэкапа. По факту, AG это страховка вашего спокойного сна и SLA перед бизнесом. Если база критична для работы компании (а в 2026 году какая база не критична?), AG не опция, а необходимость.