首页 / 资讯中心 / 文章详情

SQL Server 2016无域环境AlwaysOn高可用搭建指南

SQL Server 2016无域环境AlwaysOn高可用搭建指南 ★ FEATURED ARTICLE
先说明一个现实问题很多把 SQL Server 高可用拒之门外的团队不是买不起企业版而是卡在“必须有 Active Directory 域环境”这一步。AlwaysOn 可用性组在官方文档里的确推荐依赖域环境和 Windows 故障转移集群但真实生产环境里也存在大量边缘站点、小规模机房、测试交付项目这些地方没有条件或不想投入域控制器。SQL Server 2016 这个版本在无域环境下完全可以搭建 AlwaysOn只是绕路的地方有几个绕过去之后一样可以拿到自动故障转移、数据库副本、只读访问这些核心能力。这篇博客就是围绕“sqlserver2016无域alwayson搭建”这个主题写的。我会从为什么无域环境也能跑 AlwaysOn 的原理说起把证书认证、端点创建、集群搭建、可用性组配置这些关键动线都过一遍最后把我在实际排错中碰到的高频问题整理成速查表。整个方案不依赖任何域控制器适合在两台或三台 Windows Server 2016 物理机或虚拟机上复现。1. 无域 AlwaysOn为什么大家都想绕开域控1.1 无域是个概念不是缺陷一说到 SQL Server 高可用很多传统架构师的第一反应就是“先去搭域”然后才能做 Windows Server 故障转移集群。这个印象来自老版本的 SQL Server 集群那时候集群依赖域环境里的计算机账号和 Kerberos 认证缺了域基本上寸步难行。但从 SQL Server 2012 之后数据库镜像和 AlwaysOn 可用性组的内部通信早就改成走 TCP 端点了端点本身只认证书或者 Windows 集成认证不需要域控制器实时介入。无域环境的意思是这些服务器都加入同一个工作组没有统一的账号数据库也没有 Kerberos 票据中心。此时 Windows 集成认证受到很大限制但我们可以退一步把端点认证方式从 Windows 切换成证书认证。证书认证跟域无关只要每台 SQL Server 实例各自持有证书、互相导入公钥、配置好私钥权限就能完成双向身份验证。这个机制是官方支持的也是无域 AlwaysOn 搭建的理论基础。1.2 AlwaysOn 在无域下的定位无域环境下我们不能照搬企业内网那套复杂架构。举个例子在企业域环境里AlwaysOn 监听器可以注册成 AD 对象客户端通过 DNS 自动找到虚拟网络名称无域环境里没有这个条件所以要么用手写 hosts 文件加 IP 监听器要么干脆让客户端直接连当前主副本的实例名。对于内部系统、报表应用、开发和测试环境这个灵活性完全可以接受。我还要提醒一句SQL Server 2016 的 AlwaysOn 可用性组本身是构建在 Windows Server 故障转移集群之上的所以即便在无域环境里我们依然要在操作系统层面把故障转移集群组件装好、把集群配置起来。区别在于域环境里的集群用域账号管理无域环境里可以用本机管理员账号来管理注意权限分配和密码策略就好。对我来说无域 AlwaysOn 最适合两类场景一是企业内部边缘机房或灾备站点物理机数量少、没有专职域管理员二是软件交付项目中的预生产环境客户现场只有 SQL Server 授权不想额外维护一套活动目录基础架构。这类项目往往数据量不大但对连续性有要求无域 AlwaysOn 能花最小的成本换来一份最接近生产级的保障。2. 设计核心无域里决定成败的三个点2.1 端点的身份认证从 Kerberos 到证书AlwaysOn 副本之间通信依赖数据库镜像端点默认情况下端点使用 Windows 集成认证。域环境里有 Kerberos两个 SQL Server 进程可以顺利互认身份但无域环境里没有共享的身份验证中心继续依赖 Windows 认证就会反复出现“身份验证失败”或者“找不到服务器主体”。解决方案是在每台 SQL Server 实例上创建一个证书然后让端点采用证书认证。证书的创建和交换并不难难在三件事私钥必须能被 SQL Server 服务账号读到证书必须是有效的、尚未过期的对方 SQL Server 实例要信任并导入这个证书。只要这三个条件满足两个实例之间的加密握手就可以正常完成。这里我用一个生活化类比两个陌生人在没有身份证系统的区域做交易Windows 认证相当于问你要身份证件证书认证相当于交换各自的公钥印章以后每次通信都检查对方盖的章。公钥是公开的谁都可以拿去验证但私钥只有本人保存这就是身份证明。2.2 名称解析hosts 文件不解决一切无域环境里没有 DNS 自动注册最重要的前置工作就是让两台 SQL Server 能通过主机名互相解析。如果你的网络里没有内部 DNS 服务器最直接的办法是修改每台服务器 C 盘里的 hosts 文件把对方节点的主机名和 IP 对应关系写进去。需要注意hosts 文件不是万能的它只负责静态解析客户端应用如果也要连接监听器客户端的 hosts 文件同样要配置。如果你在集群配置阶段发现节点名称解析不了后面所有步骤都会卡住所以我会把 hosts 文件配置放在搭建的第一步。除此之外Windows 防火墙里必须允许 ICMP 回显请求吗其实不一定但保持 TCP 端口畅通是硬要求。名称解析只是第一步端口连通才是数据通道。2.3 权限模型SQL Server 里看不见的登录名AlwaysOn 的可用性组创建和自动故障转移过程中SQL Server 需要访问 Windows 故障转移集群对象、查看虚拟机信息、修改集群组状态。这些操作在域环境里由域账号完成在无域环境里则依赖本地系统账号NT AUTHORITY\SYSTEM或者在每个节点上建立的本地管理员账号。具体到 SQL Server 层我们需要做两件事。第一件把 NT AUTHORITY\SYSTEM 加到每个 SQL Server 实例的 sysadmin 角色里这个本机系统账号在集群和 SQL Server 通信时可以被识别。第二件如果 SQL Server 服务启动账号用的是某个本地账号那也要确保该账号有权读取证书私钥并加入本机管理员组。有不少人漏掉第二件症状是集群创建成功、AlwaysOn 向导跑到一半就报“无法访问本地证书”或者“服务主密钥无法打开”。这不是 SQL Server 版本问题而是私钥权限里没有给 SQL Server 服务账号授权。3. 动手之前平台、版本与架构清单3.1 版本怎么选SQL Server 2016 的 AlwaysOn 功能在标准版和企业版里都有但表现不同。标准版提供的是基本可用性组每个可用性组只能容纳两个副本没有只读路由也没有备份优先级的配置企业版支持最多八个副本、自动故障转移、只读副本、备份负载均衡这些完整能力。如果预算允许无域环境里我更推荐企业版。原因是搭建无域 AlwaysOn 本来就在绕路如果再用标准版限制住副本数量后面扩展灾备节点时还得重新做一套。标准版更适合纯粹的单数据库、双节点高可用这个定位要提前想清楚。还要注意SQL Server 2016 SP1 之后标准版同样支持若干高级特性但 AlwaysOn 的副本上限逻辑没有改变。所以请在项目启动前就把“企业版做多副本 标准版做双节点基础高可用”这个边界定好。3.2 我的参考环境为了让下面的操作步骤更具体我沿用一组通用主机名和实例配置。你可以直接替换成自己机房的主机名和 IP逻辑是一样的。角色主机名IP 地址实例SQL Server 版本系统版本主副本SQLNode110.10.10.11MSSQLSERVER2016 EnterpriseWindows Server 2016辅助副本SQLNode210.10.10.12MSSQLSERVER2016 EnterpriseWindows Server 2016见证节点SQLWitness10.10.10.13无 SQL无Windows Server 2016如果只有两台机器见证可以放在其中一个节点上也就是让主副本所在节点兼任见证但生产环境我建议独立第三台避免主节点宕机时连仲裁一起没了。数据方面我准备了一个测试数据库命名为 AlwaysOnDB里面放一张业务表和少量初始化数据用来验证同步效果。3.3 端口与防火墙规划无域环境里最容易踩坑的就是防火墙。SQL Server 本身只监听 1433 端口但 AlwaysOn 可用性组还需要数据库镜像端点端口我用的是 5022。Windows 故障转移集群内部通信还需要 UDP 1434用于 SQL 浏览器视情况而定以及集群通信用的多个端口。我一般会在搭建前一次性开放这些端口减少排错干扰。用途协议端口说明SQL Server 数据访问TCP1433应用连接数据库数据库镜像端点TCP5022AlwaysOn 副本间同步SQL 浏览器UDP1434用于实例解析集群通信TCP/UDP3343节点心跳集群动态端口TCP/UDP49152-65535高风险可自定义范围如果你在实验环境里最简单粗暴的方法是临时关闭防火墙来验证连通性但正式环境请按端口精确开放。4. 一步一步搭建无域 AlwaysOn4.1 准备 SQL Server 服务与证书搭建之前先把所有 Windows Server 2016 补丁打齐然后确认两台 SQL Server 节点的 sa 密码或本机管理员密码都是已知的。无域环境里没有活动目录统一管理密码所以我习惯在每台机器上建立一个独立的本地管理员账号并确保两台机器上该账号的密码一致这样后面集群配置时少很多麻烦。证书部分是整个无域方案的关键。在每台 SQL Server 节点上执行下面的 PowerShell 命令创建一张有效期五年的自签名证书New-SelfSignedCertificate -Subject CNAlwaysOnAGCertificate -CertStoreLocation Cert:\LocalMachine\My -KeySpec KeyExchange -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears(5)注意这里加了-KeyExportPolicy Exportable因为后面可能要把证书备份为 CER 文件并复制给对方节点。证书生成后同样是在每台节点上打开本地证书管理器MMC 添加证书管理单元在“个人 - 证书”里找到这张证书右键“所有任务 - 管理私钥”把 SQL Server 服务账号的读取权限加上。如果你记不清 SQL Server 服务账号是哪个可以在 SQL Server 配置管理器里查看 SQL Server 服务的“登录身份”通常是NT Service\MSSQLSERVER或者你自定义的本地账号。这一步千万别省否则后面 Create Certificate From File 会一直报无法访问私钥。证书权限处理完毕之后把 SQLNode1 的证书导出为.cer文件复制到 SQLNode2再把 SQLNode2 的证书导出复制到 SQLNode1。两个节点需要互相信任所以这个过程是对称的。4.2 创建证书端点现在在两台 SQL Server 实例上分别执行 T-SQL把对方的证书导入本实例然后建立使用证书认证的端点。先在 SQLNode1 上导入 SQLNode2 的证书USE master; GO CREATE CERTIFICATE AGNode2Certificate FROM FILE C:\Temp\SQLNode2.cer; GO CREATE ENDPOINT AG_Endpoint STATE STARTED AS TCP ( LISTENER_PORT 5022, LISTENER_IP ALL ) FOR DATABASE_MIRRORING ( ROLE ALL, AUTHENTICATION CERTIFICATE AGNode2Certificate, ENCRYPTION REQUIRED ALGORITHM AES ); GO再在 SQLNode2 上执行对应的反向导入和端点创建USE master; GO CREATE CERTIFICATE AGNode1Certificate FROM FILE C:\Temp\SQLNode1.cer; GO CREATE ENDPOINT AG_Endpoint STATE STARTED AS TCP ( LISTENER_PORT 5022, LISTENER_IP ALL ) FOR DATABASE_MIRRORING ( ROLE ALL, AUTHENTICATION CERTIFICATE AGNode1Certificate, ENCRYPTION REQUIRED ALGORITHM AES ); GO这里有个容易迷惑的地方端点上写的AUTHENTICATION CERTIFICATE AGNode2Certificate代表的是这个端点接受使用哪张证书对应的节点来认证所以 SQLNode1 上的端点要指定 SQLNode2 的证书SQLNode2 上的端点要指定 SQLNode1 的证书。两侧证书使用的加密算法要保持一致否则握手时算法协商不通过。端点创建完成后用下面的 T-SQL 查看状态SELECT endpoint_id, name, state_desc, protocol_desc, type_desc FROM sys.endpoints WHERE name AG_Endpoint;状态列显示STARTED就说明本机没问题下一步把权限授予系统账号。USE master; GO GRANT CONNECT ON ENDPOINT::AG_Endpoint TO [NT AUTHORITY\SYSTEM]; GO这条授权让 Windows 集群服务和 SQL Server 自己的系统上下文能够通过端点连接对方。如果集群用的是本地管理员账号建议也把这个账号的 CONNECT 权限一起授权很多奇怪的身份验证错误会因此消失。4.3 搭建 Windows Server 故障转移集群无域环境里创建故障转移集群和域环境操作基本一致只是集群名和各种对象不会注册到 AD。打开服务器管理器添加“故障转移群集”功能然后以本机管理员身份打开“故障转移群集管理器”点击创建群集。向导会让你添加要加入集群的服务器。这里输入 SQLNode1 和 SQLNode2 两个主机名然后它会做一次“验证”检测。无域环境下最好跳过完整验证或者只看警告因为节点名称解析、网络名称访问这些检查项在没有 AD 时本来就会报错但它们不影响我们用 IP 方式连接集群。创建集群时可以给集群起一个虚拟名称比如SQLCluster它不会提供像域环境那样的虚拟网络名称服务但必要的集群资源仍在。命令行创建也可以New-Cluster -Name SQLCluster -Node SQLNode1, SQLNode2 -StaticAddress 10.10.10.20这里的10.10.10.20是给集群分配的一个 IP虽然无域里客户端并不会通过集群名连数据库但 AlwaysOn 可用性组内部会用到这个对象所以保留它能避免不少路径校验问题。集群创建成功后在 SQL Server 2016 的实例上启用 AlwaysOn 功能。打开 SQL Server 配置管理器找到 SQL Server 服务右键“属性”在“AlwaysOn 高可用性”选项卡勾选“启用 AlwaysOn 可用性组”然后重启 SQL Server 服务。两台实例都要做。到这里为止基础设施才真正满足条件。很多人在这个节点才发现自己只开了数据库镜像而没有装集群导致后续可用性组向导提示“未启用 AlwaysOn”。4.4 创建可用性组与数据库副本先把要加入可用性组的数据库做好完整备份和事务日志备份因为 AlwaysOn 不会自动初始化已有数据它要求先从完整备份将数据库恢复到每个辅助副本上并且保持WITH NORECOVERY状态。在 SQLNode1 上新建可用性组时我习惯用 T-SQL 而不是 SSMS 向导因为无域环境下向导里很多验证逻辑会跳出来吓人T-SQL 更直接可控。假设已经做好备份恢复执行CREATE AVAILABILITY GROUP AG_AlwaysOnDB WITH ( AUTOMATIC_BACKUP_PREFERENCE SECONDARY, FAILURE_CONDITION_LEVEL 3, HEALTH_CHECK_TIMEOUT 30000 ) FOR DATABASE AlwaysOnDB REPLICA ON SQLNode1 WITH ( ENDPOINT_URL TCP://SQLNode1:5022, AVAILABILITY_MODE SYNCHRONOUS_COMMIT, FAILOVER_MODE AUTOMATIC, SEEDING_MODE AUTOMATIC, SECONDARY_ROLE(ALLOW_CONNECTIONS NO) ), SQLNode2 WITH ( ENDPOINT_URL TCP://SQLNode2:5022, AVAILABILITY_MODE SYNCHRONOUS_COMMIT, FAILOVER_MODE AUTOMATIC, SEEDING_MODE AUTOMATIC, SECONDARY_ROLE(ALLOW_CONNECTIONS ALL) ); GO注意ENDPOINT_URL这里必须用对方能够解析到的主机名。如果你在 hosts 文件里配好了 SQLNode1 和 SQLNode2 的解析这里可以直接写主机名比写 IP 好些。创建可用性组后辅助副本 SQLNode2 需要加入。在 SQLNode2 上执行ALTER AVAILABILITY GROUP AG_AlwaysOnDB JOIN WITH (CLUSTER_TYPE WSFC); GO然后为数据库加入副本ALTER AVAILABILITY GROUP AG_AlwaysOnDB ADD DATABASE AlwaysOnDB; GO如果初始化方式选择自动种子设定并且 SQLNode2 上没有数据库文件路径冲突数据会自动从主副本同步过去。我实际项目里更推荐手动备份还原因为可以顺便确认备份介质在无域环境里的共享权限。手动还原的命令大致是RESTORE DATABASE AlwaysOnDB FROM DISK \\SQLNode1\Backup\AlwaysOnDB.bak WITH NORECOVERY;备份目录要给辅助节点上的 SQL Agent 或本地账号足够的读写和列表权限否则还原过程会在权限上卡壳。检查同步状态SELECT replica_server_name, endpoint_url, availability_mode_desc, failover_mode_desc, synchronization_health_desc FROM sys.dm_hadr_availability_group_states g JOIN sys.dm_hadr_availability_replica_states r ON g.group_id r.group_id;只要两行的synchronization_health_desc都显示NOT_HEALTHY之外的正常状态说明主副本和辅助副本已经在同步。4.5 连接方式没有域也能用的监听策略无域环境里AlwaysOn 监听器有两种处理思路。第一种是建立一个 IP 型监听器不注册 DNS而是在客户端 hosts 文件里指过去。第二种是干脆不建监听器应用程序直接指向当前主副本的实例名靠连接字符串里的Failover Partner或应用层面的重连机制实现故障转移。T-SQL 创建 IP 型监听器的方式如下ALTER AVAILABILITY GROUP AG_AlwaysOnDB ADD LISTENER AGListener ( WITH IP ((10.10.10.30, 255.255.255.0)), PORT 1433 ); GO然后把这台监听器视为一个虚拟服务器把 SQLNode1 和 SQLNode2 的 hosts 文件里都加一行10.10.10.30 AGListener因为无域环境没有 Kerberos客户端连接监听器时一般要使用 SQL 登录名不要使用 Windows 集成认证否则在 WithoutKerberos 情况下很容易报“目标主体名称不正确”之类的错误。实际业务系统里我会优先选择第二种方式直接配置连接字符串里的Data SourceSQLNode1加Failover PartnerSQLNode2再配合数据库镜像重定向机制能少绕一大圈。4.6 配置见证节点完成自动故障转移自动故障转移需要集群具有仲裁。如果只有两个数据节点我强烈建议增加第三个见证节点否则故障转移条件满足仲裁缺失还能冻结可用性组。在没有域的环境里我们可以使用一个非常轻量的见证方式——文件共享见证。这个见证方案在当前节点集群上配置即可只需要在 SQLWitness 上开放一个共享目录然后把共享路径填到集群的仲裁配置里。在故障转移集群管理器里找到“配置群集仲裁”选择“选择仲裁见证 - 配置文件共享见证”输入\\SQLWitness\AGWitness配置完成后集群会动态计算投票。文件共享见证不需要 SQL Server也不需要域账号只要每台节点能通过网络访问该共享即可。这个目录建议启动共享时给予每台节点写权限否则仲裁心跳无法更新。5. 常见问题与排错实录5.1 端点和证书的坑最典型的报错是“连接到主副本的端点时失败错误代码 352xx”或者“镜像握手期间出错”。这类问题的根源百分之八十在证书倒数第二项SQL Server 服务账号没有私钥读取权限。排错时不要急着重建端点先去证书管理单元里检查私钥权限看看 SQL Server 服务账号是否在列表里。还有一类问题是证书过期后忘更换。自签名证书默认一年有效AlwaysOn 端点建立之后如果证书过期同步会断掉而且日志里报的往往是“身份验证失败”不是“证书过期”。我有一次排查了整整两个小时最后才发现是证书在半夜过期了。建议在规划阶段就把证书有效期设成五年并加入监控。5.2 同步异常的判断数据库状态长期是“正在同步”且synchronization_health_desc显示PARTIALLY_HEALTHY先确认辅助副本上的数据库是不是NORECOVERY状态。如果你在 SQLNode2 上执行RESTORE DATABASE AlwaysOnDB WITH RECOVERY数据库就会脱离可用性组的同步链条。另外可用性组中添加数据库时必须保证主副本数据库的恢复模式为FULL如果你用的是简单恢复模式加入时通常会直接报错。我记得有一个项目在验收测试时反复出现“无法为数据库创建副本因为它不是处于完整恢复模式”的提示把恢复模式调整后问题马上解决。日常工作里也可以用底下这条 T-SQL 查看每个副本的最后同步时间SELECT ar.replica_server_name, DB_NAME(agdb.database_id) AS DBName, dr.synchronization_state_desc, dr.last_sent_time, dr.last_received_time, dr.redo_queue_size FROM sys.dm_hadr_database_replica_states dr JOIN sys.availability_replicas ar ON dr.replica_id ar.replica_id JOIN sys.availability_databases_cluster agdb ON dr.group_database_id agdb.group_database_id;redo_queue_size持续增长说明辅助副本的重放速度跟不上主副本日志生成速度。处理思路包括增大辅助副本的磁盘日志文件、检查反病毒扫描干扰、控制主副本的大事务批次。5.3 防火墙与端口造成的“假不可达”无域环境中节点间通信完全依赖网络任何防火墙拦截都会表现为同步缓慢或端点连接超时。我在虚拟机实验环境中踩过最经典的坑是关闭了 Windows 防火墙但云安全组或虚拟交换机层面还留着隔离策略或者相反本机防火墙开着忘了对数个静态端口放行。排错命令我推荐用 PowerShell 而不是 telnet因为可以一次性测试多个端口Test-NetConnection SQLNode2 -Port 5022如果TcpTestSucceeded为 False先检查本机防火墙入站规则再检查对方防火墙入站规则最后检查物理网络设备和云平台安全组。很多“无域导致无法连接”的案子最后都是为了把问题归因到域环境其实纯属端口没放开。5.4 排错命令备忘把这些命令保存成脚本能在毫无头绪时快速定位故障边界。# 查看端点状态 sqlcmd -S SQLNode1 -E -Q SELECT * FROM sys.endpoints # 查看证书状态 sqlcmd -S SQLNode1 -E -Q SELECT * FROM sys.certificates # 查看可用性组状态 sqlcmd -S SQLNode1 -E -Q SELECT * FROM sys.dm_hadr_availability_group_states # 查看集群状态 Get-ClusterNode | Format-Table Name, State # 查看仲裁配置 Get-ClusterQuorum | Format-List *Quorum*群里看到Get-ClusterNode中节点状态不能是Down或者NotConfigured。仲裁配置最好显示NodeAndFileShareMajority或NodeMajority说明见证已经生效。另外SQL Server 日志文件是判断端点问题的第一现场打开ERRORLOG搜索hadr关键字。日志里通常会给出具体的错误状态码顺着状态码去查远比瞎猜高效。我把常见状态码整理成一张速查表现象可能原因处理方向连接端点超时5022 端口不通 / hosts 解析错误测试端口连通性检查 hosts握手失败证书未导入 / 端点认证指定错误确认双端证书互相导入端点上指定对方证书身份验证失败SQL Server 服务账号无证书私钥权限MMC 证书管理里增加服务账号读取权限同步停止、日志报 352xx证书过期 / 加密算法不一致更换证书并同步更新所有端点配置无法连接到数据库辅助副本数据库未处于 NORECOVERY重新还原数据库保持 NORECOVERY仲裁丢失缺少见证 / 文件共享不可达配置文件共享见证或独立节点见证在整个无域 AlwaysOn 的搭建过程里我最深的体会是这类环境真正复杂的地方不是 SQL Server 本身而是操作系统层面的集群理解和网络规划。只要把证书、名称解析、防火墙和仲裁这四个环节理清楚后续的可用性组配置基本水到渠成。SQL Server 2016 的无域方案虽然没有域环境那么“透明”但胜在轻量尤其适合预算有限、没有专职基础架构人员的中小型机房。搭建完成之后我通常会建议团队把主副本和辅助副本分别放在两个虚拟化宿主机上避免宿主机单点把整组副本一起带走。这个方案后面还可以继续扩展出只读访问、备份负载均衡和跨站点容灾只要企业版授权允许能力边界其实很宽。
阅读完成 · 觉得有帮助?
咨询建站