SQL Server 绑定了一个启动时并不存在的 VPN 地址
从启动日志一路追到实际监听器,弄清一次 SQL Server 绑定失败,然后给客户端一个稳定的专用地址,而不是 VPN 池地址。
在服务仍在运行时读到一条关于绑定失败的 SQL Server 日志,你发现的其实是启动顺序依赖,而不是崩溃。这个组合就是线索:引擎启动时,它被要求监听的那个地址在机器上还不存在。登录后才出现的 VPN 适配器,对无人值守的数据库服务来说是糟糕的前提条件,所以按引擎看到的顺序复盘这次失败。
从启动日志开始,而不是从客户端开始
打开实例错误日志,读网络初始化前后的条目,而不只是最后一行。引擎会记录它尝试了哪些地址、启用了哪些协议,而这份记录早于任何客户端连接。现在再看主机此刻存在什么。如果拥有所配置地址的接口只在用户登录并启动客户端之后才出现,那么这个地址在启动时并不存在,绑定失败也就完全解释得通了。
Get-NetIPAddress -AddressFamily IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixOrigin
Get-Content 'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\LOG\ERRORLOG' -Tail 40
把实例路径改成你自己的安装路径,并在下结论之前先读接口列表。一个存在但属于错误适配器的地址,与一个尚不存在的地址是不同的问题。
按引擎实际遵循的顺序走一遍绑定
引擎读取监听器配置,然后请求操作系统执行绑定。如果那一刻地址不在本机,该地址的绑定就会失败,而实例其余部分可能照常运行。这就是为什么其他协议或其他地址仍能工作,也是为什么“SQL Server 宕机了”是错误的结论。保留日志中精确的端点:地址、端口和协议,因为修复方式取决于这三者中哪一个错了。
适配器出现后重启服务通常能让监听成功,而这正是陷阱。它只是证明了依赖,并没有消除依赖,而且每次隧道重连都会切断所有已连接的用户。
像引擎那样去读监听器
在 SQL Server 配置管理器中打开实例的 TCP/IP 属性,在编辑单个地址之前先注意 Listen All 设置。当 Listen All 为 Yes 时,各地址的 Enabled 值会被忽略,所以编辑它们不会改变监听器使用的任何东西。按顺序记下三件事:你打算服务的地址、端口,以及监听器应覆盖所有地址还是只覆盖一个。然后通过受支持的重新启动流程应用更改,并读取下一次启动日志,确认引擎绑定的是你要求的地址。
监听所有地址并不是访问控制。如果确实需要宽泛的监听,那么每个可达接口都需要各自的防火墙和数据库授权决策,包括任何面向互联网的接口。
给客户端一个稳定的目标
客户端不需要让数据库主机披上池地址。在路由式设计中,服务器监听自己稳定的专用地址,VPN 网关把客户端流量转发给它,再把响应带回来。
Test-NetConnection -ComputerName 10.80.0.15 -Port 1433
tracert -d 10.80.0.15
如果客户端能到达 10.80.0.15,路径就得到了验证,数据库只需授权该客户端。如果到达不了,先修正路由和 DNS,再动监听器,因为服务器上的绑定问题从来不是客户端找不到它的原因。给服务器加一个假的池地址,或为了取悦监听器再加一个默认网关,只会在旧问题之上制造新的网络问题。让服务器的地址保持静态,让隧道把客户端送到它面前。
验证客户端实际使用的端点
最后用应用层检查收尾,而不是端口测试。用应用所使用的账号从客户端连接,并读取服务器端的连接详情,它会显示你的会话落到了哪个本地地址。
sqlcmd -S tcp:10.80.0.15,1433 -Q "SELECT local_net_address, local_tcp_port FROM sys.dm_exec_connections WHERE session_id = @@SPID"
把这个地址与你配置的监听器对比。不一致意味着存在第二个监听器,或某个名字在意外的地方被解析,这两点在下次重启替你检验修复之前都值得了解。然后在没有用户登录的情况下重启主机,确认绑定成功。正是这一次测试,区分了真正修好的监听器与下一个补丁之夜就会失效的绕行方案。