VMware 安装 SQL Server 双节点 AlwaysOn 可用性组教程 —— WSFC、AG 与侦听器完整部署(系列核心篇)

13_VMware 安装 SQL Server 双节点 AlwaysOn 可用性组教程 ------ WSFC、AG 与侦听器完整部署(系列核心篇)

系列定位 :《SQL Server 数据库全栈运维实战系列》第 13 篇,与《MySQL 数据库全栈运维实战系列》同构对标(对标 MySQL 13 主从与 InnoDB Cluster 双节点教程,是全系列的重头戏)。适用版本 :SQL Server 2019/2022(2017 及以下差异随文标注)。官方文档:Microsoft Learn SQL Server 2019/2022 文档、Always On 可用性组、WSFC 与侦听器章节。


〇、本篇要做什么(一张总图)

本篇在 VMware Workstation 上,从零搭出一套 Windows 体系的双节点高可用环境:

  1. 第一层:Windows Server 故障转移群集(WSFC)------先把"谁是活节点、故障谁来判定"的集群底座搭好;
  2. 第二层:Always On 可用性组(AG)+ 数据库镜像端点 + AG 侦听器------把数据库升级成"主库写、备库读、节点故障自动切换、应用只认一个侦听器地址"的高可用集群。

图 1

概念/对象 说明 类比 MySQL
WSFC 故障转移群集 Windows 集群服务,管投票仲裁、节点健康、资源组 Group Replication 的 Paxos 选主
数据库镜像端点 TCP 端点,主副本把事务日志块发往次要副本 复制 IO 线程的 binlog 通道
Always On 可用性组 AG 一组数据库作为整体同步与故障转移单元 MySQL 主从复制、Group Replication
AG 侦听器 固定虚拟网络名与 IP,应用统一入口 MySQL Router 6446 读写端口、VIP
同步提交 主库提交等至少一个副本硬化日志才返回 半同步复制
异步提交 主库不等副本确认直接返回 普通异步复制

先读这一句再往下做 :AlwaysOn 的"自动故障转移"依赖 WSFC 多数仲裁投票。两个数据库节点加一个文件共享见证共 3 张票,挂掉任意一个节点,存活侧仍握有 2 张票(本机票 + 见证票),群集继续服务。如果两台 DB 节点都挂、或"节点+见证"所在机器同时挂,存活票数不足,群集按保护原则停服务。这个仲裁语义会贯穿全文,是 AlwaysOn 最重要的认知前提。


一、环境准备(VMware 虚机三台)

1.1 资源规划

角色 主机名 IP vCPU/内存/磁盘 说明
域控兼文件见证 DC 192.168.10.10 2C / 4G / 60G Windows Server 2019、AD DS、共享文件夹 witness
节点 1 主 SQLNode1 192.168.10.11 4C / 8G / 80G Windows Server 2019、SQL Server 2019
节点 2 备 SQLNode2 192.168.10.12 4C / 8G / 80G Windows Server 2019、SQL Server 2019

为什么要先有域控?WSFC 的所有节点必须加入同一个 Active Directory 域,群集虚拟对象、节点身份、SQL 服务账户都依赖域认证。生产环境这台 DC 是现有域,教学环境单独建一台。

1.2 VMware 注意事项(本篇相关,逐条照做)

事项 为什么 / 怎么做
网络模式 三台虚机用 NAT 或仅主机(Host-Only),网段与宿主机打通,方便宿主机用 SSMS 连入;不要桥接到公网
完整克隆与新 MAC 克隆 SQLNode1 之前先做完整克隆,再在虚机设置里生成新 MAC,否则 SQLNode2 会与 SQLNode1 IP/MAC 冲突,WSFC 心跳时断时续
时间同步 三台虚机都开 VMware Tools 时间同步,域认证与 Kerberos 对时间敏感,偏差超过 5 分钟直接认证失败
内存预留 SQL 节点 8G 内存里留给缓冲池 ~6G,虚机设置里预留全部客户机内存,避免 balloon 回收导致同步延迟抖动
磁盘控制器 数据盘用 NVMe 或准虚拟化 PVSCSI,别用 IDE;事务日志是顺序写,控制器不对会人为放大同步延迟
快照纪律 每完成一个大阶段(装好 SQL、建好域、建好群集、建好 AG)打一个命名快照,失败可整台回滚;注意 AlwaysOn 建好之后不要再挂快照,否则 VSS 与日志链会出问题
CPU 虚拟化 教学单机部署不需要;若要在虚机里再跑嵌套,需勾选"虚拟化 Intel VT-x/EPT"
主机名解析 三台必须互相能按主机名解析,DNS 由 DC 负责,hosts 兜底

1.3 系统基础配置(DC、SQLNode1、SQLNode2 都做)

复制代码
# ① 改主机名(解释:三台分别执行对应那一条,改完重启)
Rename-Computer -NewName "DC"; Restart-Computer -Force
Rename-Computer -NewName "SQLNode1"; Restart-Computer -Force
Rename-Computer -NewName "SQLNode2"; Restart-Computer -Force

# ② 固定 IP 与 DNS(解释:把 DNS 指向 DC,域解析靠它;三台按上表改)
# 查看网卡名后执行(示例接口名 Ethernet0)
New-NetIPAddress -InterfaceAlias "Ethernet0" -IPAddress 192.168.10.11 `
    -PrefixLength 24 -DefaultGateway 192.168.10.254
Set-DnsClientServerAddress -InterfaceAlias "Ethernet0" -ServerAddresses 192.168.10.10

# ③ 关闭防火墙或精准放行(解释:实验环境简化做法;生产按 WSFC 与 AlwaysOn 端口清单放行)
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False

1.4 建域控(DC 上执行一次)

复制代码
# ① 安装 AD 域服务(解释:corp.local 为本篇实验域名,生产用既有域)
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools

# ② 提升为域控(解释:目录服务还原模式密码按企业规范设置,这里写演示值)
Import-Module ADDSDeployment
Install-ADDSForest -DomainName "corp.local" -SafeModeAdministratorPassword `
    (ConvertTo-SecureString "Dc@2026!" -AsPlainText -Force) -Force
# 提升完成后自动重启,DC 成为 corp.local 的第一台域控

# ③ 在 DC 上建文件共享见证(解释:WSFC 仲裁用,域内成员只读即可)
New-SmbShare -Name "witness" -Path "C:\witness" -ChangeAccess "corp\Cluster$"
New-Item -ItemType Directory -Path "C:\witness" -Force

# ④ 两台 SQL 节点加域(解释:在 SQLNode1、SQLNode2 上分别执行,重启后用 corp\admin 登录)
Add-Computer -DomainName "corp.local" -Credential "corp\Administrator" -Restart

二、SQL Server 2019 安装(SQLNode1、SQLNode2 都做)

2.1 安装前域账户准备(在 DC 上做一次)

WSFC 与 AlwaysOn 的标准做法是用域托管服务账户 gMSA 跑 SQL 服务,避免手工改密码过期。教学环境也可先用域普通账号,但密码策略要配"永不过期"。

复制代码
# 在 DC 上:启用 gMSA 根 KDS 并创建 SQL 服务账户(解释:SQL 服务账户不绑死单机,改密码域自动管)
Add-KdsRootKey -EffectiveImmediately
New-ADServiceAccount -Name "sqlsvc" -DNSHostName "sqlsvc.corp.local" `
    -PrincipalsAllowedToRetrieveManagedPassword "SQLNode1$","SQLNode2$"

2.2 安装数据库引擎与 SSMS

复制代码
# ① 挂载 ISO 后无人值守安装数据库引擎(解释:实例名默认 MSSQLSERVER,服务账户用上面的域账号思路)
# setup.exe 常见参数(在 SQLNode1、SQLNode2 各执行一次,结构相同)
# setup.exe /Q /ACTION=INSTALL /FEATURES=SQLENGINE,Conn /INSTANCENAME=MSSQLSERVER `
#   /SQLSVCACCOUNT="corp\sqlsvc" /AGTSVCACCOUNT="corp\sqlsvc" `
#   /SQLSYSADMINACCOUNTS="corp\Administrator" /UPDATEENABLED=1

# ② 两台都装 SSMS(解释:SSMS 19/20 是独立下载的 SSMS-Setup-ENU.exe,不在安装介质里)
Start-Process "C:\temp\SSMS-Setup-ENU.exe" -ArgumentList "/quiet /norestart" -Wait

-- ③ 验证实例就绪(解释:两台都用 sqlcmd 或 SSMS 各连本机,能登录才算装完)
sqlcmd -S SQLNode1 -E -Q "SELECT @@VERSION, @@SERVERNAME;"
sqlcmd -S SQLNode2 -E -Q "SELECT @@VERSION, @@SERVERNAME;"

2019 vs 2022:本篇命令两版通用。差异点:2022 的智能查询处理增强、2019 引入的行存储批处理与 UCM(受控备份);AlwaysOn 端点语法、WSFC 依赖两版完全一致。


三、第一部分:Windows Server 故障转移群集 WSFC 配置

3.1 安装群集功能(两台 SQL 节点都做)

复制代码
# 安装故障转移群集功能与管理工具(解释:RSAT 群集 PowerShell 模块一并装上)
Install-WindowsFeature Failover-Clustering -IncludeManagementTools

3.2 群集验证(强烈建议先跑,不过别硬建)

复制代码
# 群集验证向导等价命令(解释:自动测网络、存储、AD 权限;失败项要逐条解决再建群)
Test-Cluster -Node SQLNode1, SQLNode2 -Verbose
# 输出报告 .mht 在 C:\Users\Administrator 下,先看 Errors 再决定是否建

3.3 创建群集 CLB1

复制代码
# 创建两节点群集(解释:群集名 CLB1、虚拟 IP 192.168.10.100;实验环境不带共享磁盘,加 -NoStorage)
New-Cluster -Name "CLB1" -Node SQLNode1, SQLNode2 `
    -StaticAddress 192.168.10.100 -NoStorage -Verbose

# 把文件共享见证挂到群集上(解释:两节点 + 见证 = 3 张票,后面 3.5 详解)
Set-ClusterQuorum -Cluster CLB1 -NodeAndFileShareMajority "\\DC\witness"

# 验证群集在线(解释:看节点状态、群集资源、仲裁配置)
Get-ClusterNode -Cluster CLB1
Get-ClusterResource -Cluster CLB1
Get-ClusterQuorum -Cluster CLB1
验证项 预期
Get-ClusterNode SQLNode1、SQLNode2 均 Up
群集 IP 资源 192.168.10.100 Online
仲裁模型 Node and File Share Majority

3.4 WSFC 心跳网络

WSFC 靠网络心跳判定节点死活:默认每分钟检测 3~5 次,连续失败超过阈值才判死,避免网络抖动误切换。实验环境两台节点同宿主机,心跳天然稳定。

复制代码
# 查看群集网络角色(解释:私有网络做心跳,公用网络对外服务)
Get-ClusterNetwork -Cluster CLB1
Get-ClusterNetworkInterface -Cluster CLB1

3.5 仲裁投票:3 张票的语义(本篇认知核心)

图 2

与 MySQL 侧对照:MySQL InnoDB Cluster 双节点挂一台就只读保护,因为 Paxos 要多数派;AlwaysOn 双节点之所以能"挂一台还能自动切",就是因为我们额外引入了文件共享见证这张票,把 2 票变成 3 票。这就是 SQL Server 体系"双节点可生产用"而 MySQL 双节点只能教学的本质差别。


四、第二部分:AlwaysOn 可用性组原理(官方:Always On 可用性组概述)

图 3

组件 作用 类比 MySQL
可用性副本 一份数据库的主或次要实例 主库、从库实例
数据库镜像端点 副本间日志传输通道,TCP 5022 复制通道、复制账号权限
可用性组资源 WSFC 里一个可漂移的资源组 MGR 组成员身份
AG 侦听器 虚拟网络名 + IP,应用只认它 MySQL Router 路由入口、VIP
只读路由 把读连接定向到次要副本 Router 6447 RO 端口

图 4

与 MySQL 的关键差别:AG 不是"一条复制链路",而是"一组数据库作为整体"。AG 内的数据库必须同生同死:要么整体在主副本可写,要么整体在次要副本待命。不能像 MySQL 那样一部分库复制、一部分不复制。


五、启用 AlwaysOn 并建镜像端点(两台 SQL 节点都做)

5.1 开启实例级 AlwaysOn

复制代码
# 在 SQLNode1、SQLNode2 分别启用(解释:启用后自动重启 SQL 服务,注意窗口)
Enable-SqlAlwaysOn -ServerInstance SQLNode1
Enable-SqlAlwaysOn -ServerInstance SQLNode2
# 或在 SSMS:实例属性 Always On 高可用 勾选启用 Always On 可用性组

5.2 创建数据库镜像端点

复制代码
-- 在 SQLNode1 执行(解释:端点名 db_hadr、TCP 5022、证书或 Windows 认证,域内用 Windows 认证即可)
CREATE ENDPOINT [db_hadr]
    STATE = STARTED
    AS TCP (LISTENER_PORT = 5022)
    FOR DATABASE_MIRRORING (ROLE = ALL);
GO
-- 在 SQLNode2 上执行同样的语句,两台端点互为通道

-- 端点防火墙放行 5022(解释:PowerShell 实验环境已整体关防火墙,生产补规则)
-- New-NetFirewallRule -DisplayName "HADR 5022" -Direction Inbound -LocalPort 5022 -Protocol TCP -Action Allow

-- 验证端点在线(解释:state_desc 为 STARTED 才算好)
SELECT name, state_desc, protocol_desc
FROM sys.endpoints
WHERE type_desc = 'DATABASE_MIRRORING';

六、数据库准备与创建可用性组

6.1 备库基线:完整恢复模型 + 一次完整备份

AG 里的数据库有硬性前置:必须完整恢复模型,且至少做过一次完整备份(日志链起点)。

复制代码
-- 在 SQLNode1(主)准备库(解释:教学库 MyApp;生产直接拿既有库做)
CREATE DATABASE MyApp;
GO
ALTER DATABASE MyApp SET RECOVERY FULL;
GO

-- 一次完整备份 + 一次日志备份(解释:日志链的起点,不做这步 AG 建不起来)
BACKUP DATABASE MyApp TO DISK = N'D:\bak\MyApp_full.bak' WITH INIT, COMPRESSION;
BACKUP LOG MyApp TO DISK = N'D:\bak\MyApp_log.trn' WITH INIT;

6.2 创建可用性组 MyAG(同步提交、自动故障转移)

复制代码
-- 在 SQLNode1 执行(解释:两个副本都 SYNCHRONOUS_COMMIT,辅助副本设自动故障转移、可读)
CREATE AVAILABILITY GROUP [MyAG]
WITH (AUTOMATED_BACKUP_PREFERENCY = PRIMARY)
FOR DATABASE [MyApp]
REPLICA ON
    N'SQLNode1' WITH (
        ENDPOINT_URL = N'TCP://SQLNode1.corp.local:5022',
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        FAILOVER_MODE = AUTOMATIC,
        BACKUP_PRIORITY = 50),
    N'SQLNode2' WITH (
        ENDPOINT_URL = N'TCP://SQLNode2.corp.local:5022',
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
        FAILOVER_MODE = AUTOMATIC,
        BACKUP_PRIORITY = 50,
        SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL, READ_ONLY_ROUTING_URL = N'TCP://SQLNode2.corp.local:1433'));
GO

-- 在 SQLNode2 上把自己加入 AG(解释:与主节点握手,准备接收数据)
ALTER AVAILABILITY GROUP [MyAG] JOIN;
GO
验证项 预期
SSMS Always On 高可用 可用性组 出现 MyAG
主副本 sys.availability_groups MyAG 已定义
次要副本 Join 后 进入"正在同步"状态

前置条件自查清单(报错时逐条核对):实例级 AlwaysOn 已开启并重启服务、两台镜像端点已 STARTED、域服务账号对端点有 CONNECT 权限、数据库完整恢复模型且做过完整备份、Windows 防火墙放行 5022。这五条缺一条,CREATE AVAILABILITY GROUP 或 JOIN 就会在对应环节报错。


七、次要副本初始数据同步

图 5

7.1 主副本备份流还原到次要副本

复制代码
# 把主库备份文件拷到 SQLNode2(解释:\\SQLNode1\D$\bak 共享访问,域账号有读权限)
Copy-Item "\\SQLNode1\D$\bak\MyApp_full.bak" "D:\bak\"
Copy-Item "\\SQLNode1\D$\bak\MyApp_log.trn"  "D:\bak\"

-- 在 SQLNode2 上还原(解释:必须 NORECOVERY,让库停在"准备接收日志"的还原中间态)
RESTORE DATABASE MyApp FROM DISK = N'D:\bak\MyApp_full.bak'
WITH NORECOVERY, REPLACE, STATS = 10;
RESTORE LOG MyApp FROM DISK = N'D:\bak\MyApp_log.trn'
WITH NORECOVERY;

-- 在 SQLNode2 上把还原好的库联入 AG(解释:之后日志由端点自动持续推送)
ALTER DATABASE MyApp SET HADR AVAILABILITY GROUP = MyAG;

SSMS 向导更省事:主副本右键 可用性组 使用新建可用性组向导,勾上"完全数据同步",向导会自动做备份拷贝还原。本篇用 T-SQL 写是为了看清每一步;生产两者等价。

7.2 验证同步状态

复制代码
-- ① 在主副本看副本与库级同步状态(解释:副本级 DMV 看健康,队列列只属于库级 DMV)
SELECT ar.replica_server_name,
       rs.role_desc,
       rs.operational_state_desc,
       rs.connected_state_desc,
       rs.synchronization_health_desc,
       drs.synchronization_state_desc,
       drs.log_send_queue_size,
       drs.redo_queue_size
FROM sys.availability_replicas ar
JOIN sys.dm_hadr_availability_replica_states rs
  ON rs.replica_id = ar.replica_id
JOIN sys.dm_hadr_database_replica_states drs
  ON drs.replica_id = ar.replica_id;

-- ② 端到端实测(解释:主副本写一行,次要副本可读应立刻看到)
-- 在 SQLNode1:
CREATE TABLE MyApp.dbo.t_hadr(id int primary key, msg nvarchar(50));
INSERT INTO MyApp.dbo.t_hadr VALUES (1, N'from primary SQLNode1');

-- 在 SQLNode2 上以只读连接查(解释:同步提交模式下主库提交即硬化,备库立刻可读)
SELECT * FROM MyApp.dbo.t_hadr;

八、配置 AG 侦听器(应用入口)

复制代码
-- 在主副本执行(解释:侦听器名 aglistener、虚拟 IP 192.168.10.110、端口 1433)
ALTER AVAILABILITY GROUP [MyAG]
ADD LISTENER N'aglistener' (
    WITH IP ((N'192.168.10.110', N'255.255.255.0')),
    PORT = 1433);
GO

# 验证侦听器注册(解释:DNS 自动登记 aglistener.corp.local;客户端用侦听器名即可)
Test-NetConnection -ComputerName aglistener -Port 1433
nslookup aglistener

# 应用连接串就写侦听器(解释:后续主副本漂移,应用连接串一个字都不用改)
# Server=aglistener; Database=MyApp; User Id=sa; Password=Sql@2026;

图 6

与 MySQL Router 对照:MySQL 要先起 Router 进程再 bootstrap;SQL Server 这边没有独立进程,侦听器是 WSFC 管的一个网络名资源,主副本切换时 WSFC 自动把资源组漂到新主,IP 不变。应用侧语义完全一致------永远连入口,不连具体机器。


九、故障转移演练

9.1 计划内手动故障转移(主副本正常)

复制代码
# 在主副本用 PowerShell 优雅转移(解释:必须在同步提交模式下执行;先停写再切)
Switch-SqlAvailabilityGroup `
    -Path "SQLSERVER:\SQL\SQLNode1\DEFAULT\AvailabilityGroups\MyAG"
# 切换后 SQLNode2 变主、可写

-- 验证新主(解释:现在在 SQLNode2 上可写了)
INSERT INTO MyApp.dbo.t_hadr VALUES (2, N'after manual failover');

9.2 模拟主副本宕机:自动故障转移

复制代码
# ① 在 SQLNode2 上看群集节点状态(解释:先把 SQLNode1 的群集节点资源停掉,模拟整机宕机)
Stop-ClusterNode -Cluster CLB1 -Name SQLNode1

# ② WSFC 判定 SQLNode1 失联后,自动把 AG 资源组漂到 SQLNode2
Get-ClusterGroup -Cluster CLB1

图 7

复制代码
-- ③ 验证自动切换结果(解释:应用无感知重连即可;新主 SQLNode2 已持有可写副本)
SELECT ar.replica_server_name, rs.role_desc, rs.synchronization_health_desc
FROM sys.availability_replicas ar
JOIN sys.dm_hadr_availability_replica_states rs ON rs.replica_id = ar.replica_id;

# ④ 恢复 SQLNode1(解释:开机后 SQL 服务自动起,副本自动重新联入并追平日志)
Start-ClusterNode -Cluster CLB1 -Name SQLNode1

9.3 故障转移对照表

场景 模式 是否自动 应用是否需改连接串
主副本正常维护 手动 Switch 否 否
主副本整机宕机、同步提交 自动 是 否
副本异步提交 手动或强制 否 否
双节点同时宕机 不可用 群集停服务 等恢复后按最后存活副本强制恢复

9.4 只读路由验证(读流量压到次要副本)

复制代码
-- ① 在主副本为次要副本配置只读路由列表(解释:读连接打到侦听器后,引擎按列表把它重定向到次要副本)
ALTER AVAILABILITY GROUP [MyAG]
MODIFY REPLICA ON N'SQLNode1' WITH (
    PRIMARY_ROLE (READ_ONLY_ROUTING_LIST = (N'SQLNode2')));
ALTER AVAILABILITY GROUP [MyAG]
MODIFY REPLICA ON N'SQLNode2' WITH (
    PRIMARY_ROLE (READ_ONLY_ROUTING_LIST = (N'SQLNode1')));

-- ② 只读连接串加 ApplicationIntent=ReadOnly(解释:与写连接串同侦听器,靠这个参数分流)
-- 写连接串:Server=aglistener; Database=MyApp; ApplicationIntent=ReadWrite
-- 读连接串:Server=aglistener; Database=MyApp; ApplicationIntent=ReadOnly
SELECT @@SERVERNAME;   -- 预期落到 SQLNode2,即只读副本
连接串参数 路由目标
默认 ReadWrite 当前主副本,可写
ApplicationIntent=ReadOnly 次要副本,只读分流

十、WSFC 仲裁与投票调优(生产进阶)

复制代码
# 实验环境是两节点 + 文件共享见证。生产常见变体:
# ① 三节点群集:默认奇数票,不需要见证
# ② 域控与 SQLNode1 同机:见证文件放独立文件服务器,避免"共享命运"
# ③ 手动关闭某节点投票(解释:跨数据中心部署时,把灾备中心节点票置 0,避免脑裂)
(Get-ClusterNode -Cluster CLB1 -Name SQLNode2).NodeWeight = 0
配置 总票数 可容忍故障数 说明
2 节点 + FSW 3 挂任意 1 个 教学与小生产标准配法
3 节点 3 挂任意 1 个 生产推荐
2 节点无见证 2 0 挂任意 1 个群集停服务,不可用

十一、AG 监控常用 DMV

复制代码
-- ① 副本健康与队列长度(解释:副本级看健康状态,队列列 JOIN 库级 DMV 取)
SELECT ar.replica_server_name,
       rs.role_desc,
       rs.operational_state_desc,
       rs.synchronization_health_desc,
       drs.synchronization_state_desc,
       drs.log_send_queue_size,
       drs.redo_queue_size
FROM sys.dm_hadr_availability_replica_states rs
JOIN sys.availability_replicas ar ON ar.replica_id = rs.replica_id
JOIN sys.dm_hadr_database_replica_states drs ON drs.replica_id = rs.replica_id;

-- ② 数据库级同步详情(解释:每个库一行,synchronization_state_desc 全 HEALTHY 才算健康)
SELECT database_name, synchronization_state_desc,
       log_send_rate, redo_rate, last_hardened_time
FROM sys.dm_hadr_database_replica_states;

-- ③ 当前主副本是谁(解释:应用排查时先看主在哪台)
SELECT ag.name, ar.replica_server_name, rs.role_desc
FROM sys.availability_groups ag
JOIN sys.availability_replicas ar ON ar.group_id = ag.group_id
JOIN sys.dm_hadr_availability_replica_states rs ON rs.replica_id = ar.replica_id
WHERE rs.is_local = 1;
监控项 健康基线
synchronization_health_desc 全部 HEALTHY
redo_queue_size 持续为 0,>100 页要查
log_send_queue_size 0;涨说明网络或副本磁盘慢;数据丢失量估算参考 PBM 的 @EstimatedDataLoss
复制代码
-- ④ AG 数据库故障准备状态(解释:is_failover_ready=1 表示该库已就绪、可参与故障转移;挂起状态去库级 DMV 取)
SELECT ag.name AS ag_name,
       ar.replica_server_name,
       adc.database_name,
       cls.is_database_joined,
       cls.is_failover_ready,
       cls.is_pending_secondary_suspend
FROM sys.availability_databases_cluster adc
JOIN sys.availability_replicas ar ON ar.group_id = adc.group_id
JOIN sys.availability_groups ag ON ag.group_id = adc.group_id
JOIN sys.dm_hadr_database_replica_cluster_states cls
  ON cls.group_database_id = adc.group_database_id
  AND cls.replica_id = ar.replica_id;

# ⑤ PowerShell 一行巡检(解释:脚本化巡检脚本里可直接引用这段)
Get-SqlAvailabilityGroup -Path "SQLSERVER:\SQL\SQLNode1\DEFAULT" |
    Get-SqlAvailabilityReplica |
    Select-Object Name, Role, AvailabilityMode, ConnectionState, SynchronizationState

十二、端口与参数速查

端口 用途
1433 数据库引擎默认端口、侦听器对外端口
5022 数据库镜像端点、副本间日志传输
3343 WSFC 节点间集群通信
135、445 RPC 与 SMB、群集管理流量
概念/对象 说明 类比 MySQL
镜像端点 5022 副本间专用通道 复制通道、复制账号权限
侦听器 1433 应用入口 VIP Router 6446、VIP
SYNCHRONOUS_COMMIT 主库等副本硬化 半同步插件
ASYNCHRONOUS_COMMIT 主库不等确认 普通异步复制
FAILOVER_MODE AUTOMATIC 自动故障转移 MGR 自动选主
FAILOVER_MODE MANUAL 仅计划内手动 手工 CHANGE MASTER

应用连接串永远写侦听器名。这和 MySQL 应用永远写 Router 地址是同一个道理------主副本漂移时,入口不变。


十三、扩展:异地容灾与读扩展

双节点同城高可用只是起点。把灾备中心挂成异步提交副本,就构成两地容灾:

图 8

复制代码
-- 异地副本用异步提交(解释:跨城延迟大,同步会拖垮主库写性能)
ALTER AVAILABILITY GROUP [MyAG]
ADD REPLICA ON N'SQLNodeDR' WITH (
    ENDPOINT_URL = N'TCP://SQLNodeDR.corp.local:5022',
    AVAILABILITY_MODE = ASYNCHRONOUS_COMMIT,
    FAILOVER_MODE = MANUAL);
部署形态 可自动故障转移 可容忍故障 适用场景
2 节点 + FSW 是 同城挂 1 台 教学、小生产
3 节点同城 是 挂任意 1 台 生产推荐
同城 2 同步 + 异地 1 异步 同城自动、异地手动 同城挂 1 台 两地三中心金融容灾

十四、备份恢复与常见故障处理

14.1 在 AG 上做备份

官方推荐"自动备份首选次要副本",把备份 IO 从主副本卸走:

复制代码
-- ① 备份作业在次要副本上执行(解释:AG 上下文里 BACKUP 只允许在主或配置允许的副本上做)
BACKUP DATABASE MyApp TO DISK = N'D:\bak\MyApp_secondary.bak' WITH INIT, COMPRESSION;

-- ② 还原单个 AG 库到新实例(解释:主副本完整备份 + 日志链,NORECOVERY 起手)
RESTORE DATABASE MyApp FROM DISK = N'D:\bak\MyApp_primary.bak' WITH NORECOVERY, REPLACE;

14.2 常见故障速查

故障 现象 处理
副本卡 SUSPENDED redo_queue 只涨不落 ALTER DATABASE MyApp SET HADR RESUME;
同步 HEALTHY 但 redo 慢 大事务回放阻塞 查副本磁盘,必要时扩 tempdb 与日志
侦听器连不上 DNS 没注册或防火墙挡 1433 nslookup aglistener + 补防火墙规则
群集资源 Failed 仲裁票不足或节点掉域 Get-ClusterResource 看起因事件日志
副本反复断连 端点证书过期、网络抖动 检查 5022 连通性与端点状态

十五、踩坑记录(实测汇总)

# 坑 现象 解决
1 克隆虚机没生成新 MAC SQLNode2 与 SQLNode1 网络时通时断,WSFC 建不起来 完整克隆 + 虚机设置里生成新 MAC
2 三台虚机时间不同步 域控提升失败、加域报 Kerberos 错误 开 VMware Tools 时间同步,偏差控制在 5 分钟内
3 没加域就建 WSFC New-Cluster 报权限或 AD 对象错误 两台 SQL 节点先加 corp.local 域
4 数据库还在 SIMPLE 恢复模型就建 AG CREATE AVAILABILITY GROUP 报"未做过日志备份" 先 ALTER 为 FULL,做一次完整备份 + 日志备份
5 备库还原用了 RECOVERY 库进入可写态,联入 AG 报错 备库还原必须 NORECOVERY
6 镜像端点没开 5022 防火墙 副本之间连不上,同步状态 SUSPENDED 补入站规则放行 TCP 5022
7 两节点没加文件共享见证 挂一台节点后群集停服务,以为自动切换失效 Set-ClusterQuorum 挂文件共享见证,凑 3 票
8 应用直连 SQLNode1 而非侦听器 故障转移后应用连接串要改、业务中断 连接串统一写 aglistener
9 跨城副本误配同步提交 主库写延迟飙到秒级 跨城一律 ASYNCHRONOUS_COMMIT
10 用域普通账号跑 SQL 服务且密码会过期 服务突然起不来,AG 资源 Failed 改用 gMSA,密码域自动轮换
11 建 AG 后给数据库打快照做测试 VSS 快照打断日志链,副本同步挂起 AlwaysOn 建好后禁止对 AG 库打快照
12 直接改 SQLNode1 IP 没动 DNS 侦听器与副本端点解析错乱 IP 规划前置,DNS 由 DC 统一登记
13 在次要副本上执行写事务测试 报"只读副本不允许写" 次要副本默认只读,写走侦听器
14 群集验证报错硬建群集 建完资源反复 Failed,日志一堆权限错误 先 Test-Cluster 逐条修 Errors 再建
15 SQL 服务启动账户对 5022 端点无连接权限 副本 JOIN 报连接被拒 给域服务账号授予 CONNECT ON ENDPOINT

十六、本文要点速记

  1. 部署顺序:三台虚机(DC + 两 SQL 节点)→ 建域、加域 → 装 SQL Server → 装群集功能建 WSFC → 启用 AlwaysOn、建端点 → 备库基线、建 AG → 配侦听器 → 故障转移演练。
  2. WSFC 是 AlwaysOn 的地基:没有群集就没有自动故障转移;两节点必须配文件共享见证凑 3 票。
  3. 备库铁律:数据库完整恢复模型、至少一次完整备份加日志备份;备库还原一律 NORECOVERY 再 JOIN。
  4. 应用只认侦听器 :Server=aglistener,主副本漂移连接串不变。
  5. 同步提交保数据、异步提交扩异地:同城同步、跨城异步,是两地三中心的标准配法。
  6. 类比 MySQL:AG ≈ 主从加 Group Replication 的合体,WSFC ≈ Paxos 仲裁层,侦听器 ≈ MySQL Router 入口,同步提交 ≈ 半同步复制。

十七、参考资料(官方正式文档)

主题 官方链接
Always On 可用性组概述 https://learn.microsoft.com/sql/database-engine/availability-groups/windows/overview-of-always-on-availability-groups-sql-server
创建可用性组 https://learn.microsoft.com/sql/database-engine/availability-groups/windows/create-an-availability-group-sql-server
配置侦听器 https://learn.microsoft.com/sql/database-engine/availability-groups/windows/create-or-configure-an-availability-group-listener-sql-server
WSFC 仲裁 https://learn.microsoft.com/sql/sql-server/failover-clusters/windows/wsfc-quorum-mode-voting-configuration
故障转移群集安装 https://learn.microsoft.com/windows-server/failover-clustering/create-failover-cluster
镜像端点 https://learn.microsoft.com/sql/database-engine/database-mirroring/the-database-mirroring-endpoint-sql-server
监控 AG 健康 https://learn.microsoft.com/sql/database-engine/availability-groups/windows/monitor-availability-groups-transact-sql

本文章属于《SQL Server 数据库全栈运维实战系列》高可用架构篇(系列核心篇)。欢迎收藏、交流。

相关推荐
测试界的小码农13 分钟前
【Linux 命令实战(06):Linux 文件权限管理,掌握 chmod、chown、chgrp】
linux·运维·服务器
wangruofeng18 分钟前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
茶栀(*´I`*)1 小时前
SQL 性能分析:从慢查询日志到执行计划的完整定位方法
数据库·sql
艺杯羹1 小时前
1Panel 装好后 ufw 仍是 inactive:一次服务器安全盲区复盘
服务器·数据库·安全·网络安全·系统架构·实战·1panel
陈希1231 小时前
负载均衡与高可用:LVS、HAProxy、Keepalived 实战
运维·负载均衡·lvs
Softmaxmap1 小时前
从零做一个中文小模型:600 亿 token 数据、mHC + Engram 结构、到强化学习的全流程(开源)
架构
你三大爷1 小时前
从 Hessian 迁移到 protostuff:深嵌套模型反序列化耗时与高并发类加载锁的根治实战
后端·架构
code2cat2 小时前
【随笔】MCP工具重试:任务已经创建,响应丢了怎么办
数据库·mcp
wuyk5554 小时前
Spider-第10讲-SQLite持久化与去重
数据库·爬虫·sqlite