分布式可用性组拒绝使用 SUSPEND_FROM_CAPTURE 重新同步我的 FILESTREAM 数据库

Han*_*non 6 sql-server availability-groups distributed-availability-groups sql-server-2022

我的家庭实验室设置由跨两台物理主机在 HyperV 中运行的四台服务器组成。SQL Server 实例为 SQLAG101、SQLAG102、SQLAG201 和 SQLAG202。

SQLAG101 和 SQLAG102 是 SQLAG100 可用性组的成员,并且位于 192.168.0.0/24 网络上。

SQLAG201 和 SQLAG202 是 SQLAG200 可用性组的成员,并且位于 192.168.2.0/24 网络上。

流量在两个子网之间路由,这两个子网都是我的实验室的本地子网(即涉及的延迟非常小)。

SQLDAG 是跨越 SQLAG100 和 SQLAG200 的分布式可用性组。已经运行良好约 6 个月,AG 成员服务器之间的自动故障转移以及两个 AG 之间的手动故障转移工作正常,并且没有数据丢失。

在我的测试服务器上,我在使用以下命令的数据库的分布式 AG 转发器上看到以下错误FILESTREAM

操作系统在“F:\SQLServer\HV2019\FILESTREAM\dag_test_db\dag_test_db_fg_fs_f01\3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8”上尝试“CreateFileW”时返回错误“2(系统找不到指定的文件。)” -922c-4821-904e-7555c031630d\0000008f-000292b0-0006'位于'fsdohdlr.cpp'(2474)。

由于以下原因,数据库“dag_test_db”的 Always On 可用性组数据移动已暂停:“系统”(源 ID 3;源字符串:“SUSPEND_FROM_CAPTURE”)。要恢复数据库上的数据移动,您需要手动恢复数据库。有关如何恢复可用性数据库的信息,请参阅 SQL Server 联机丛书。

(顺便说一句,喜欢在线书籍参考)

为了排除故障,我已经完全放弃了dag_test_db转发器和辅助转发器。然后,我从主数据库中进行了完整备份,并将其恢复到转发器,并根据需要通过恢复日志备份进行前滚,然后再dag_test_db通过以下方式将备份添加到转发器可用性组中:ALTER DATABASE [dag_test_db] SET HADR AVAILABILITY GROUP = SQLAG200;

最初,转发器 AG (SQLAG200) 的可用性组仪表板显示数据库正在同步,但大约一小时后,同步状态显示NOT SYNCHRONIZING,同步运行状况原因描述显示SUSPEND_FROM_CAPTURE

chkdsk /f在 F: 驱动器上运行不会报告任何错误。

dbcc checkdb (dag_test_db)从主要返回没有错误。

我编写了一个查询来读取文件流中的所有数据;也许这会显示出一些有趣的东西。一旦获得测试结果,我将更新问题。该查询通过 sqlcmd.exe 使用ApplicationIntent=ReadOnly来连接到转发器实例。对于有兴趣的人来说,这是查询:

USE [dag_test_db];
GO
DECLARE @d varbinary(max);
DECLARE @f nvarchar(260);
DECLARE cur CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR
SELECT
      [f].[file_data]
    , [f].[original_file_name]
FROM [dbo].[files] [f];

OPEN cur;
FETCH NEXT FROM cur INTO @d, @f;
WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @f + N': ' + CONVERT(nvarchar(11), LEN(@d), 0);
    FETCH NEXT FROM cur INTO @d, @f;
END
CLOSE cur;
DEALLOCATE cur;
Run Code Online (Sandbox Code Playgroud)

也许一些英俊的年轻微软工程师可以帮助我理解是什么导致了错误fsdohdlr.cpp at 2474

DBCC CHECKDB ([dag_test_db]) WITH NO_INFOMSGS;全球初选没有腐败现象。

将错误消息中的文件名转换为十进制LSN,并fn_dblog在全局主节点上使用来显示日志内容,结果如下:

当前LSN 手术 语境 交易ID 日志块生成 标签位 日志记录固定长度 日志记录长度 上一个LSN 标志位 原木储备 分配单元ID 分配单元名称 页面ID 槽位号 上一页 LSN 分区ID 行标志 元素数量 行内偏移 修改尺寸 检查点开始 CHKPT 开始数据库版本 最大 XDESID 交易数量 检查点结束 CHKPT 结束数据库版本 最小LSN 脏页 最早的复制开始 LSN 下一个复制结束LSN 最后分布式备份结束LSN 最后分布式结束LSN Repl 最小保留 LSN 服务器UID SPID 开始日志状态 精确型 开始时间 交易名称 交易SID 父交易 ID 最旧的活动交易 ID 确切的ID 确切的节点 ID Xact节点本地ID 结束年龄 时间结束 交易开始 复制记录 最旧的活动 LSN 服务器名称 数据库名称 标记名称 主控XDESID 主控DBID Preplog 开始 LSN 准备时间 虚拟时钟 上一个保存点 保存点名称 Rowbits 第一位 Rowbits 位计数 Rowbits 位值 锁数量 锁信息 写入前的LSN 已写页数 命令类型 出版物 ID 文章编号 部分状态 命令 字节偏移量 新价值 旧值 新分页 已删除行 释放的字节数 CI 表 ID CI 索引 ID 新分配单元ID 文件组ID 元状态 文件状态 文件编号 物理名称 逻辑名称 LSN格式 行集ID 文本指针 列偏移 旗帜 字体大小 抵消 旧尺寸 新尺寸 描述 批量分配的盘区计数 批量行集 ID 批量分配单元 ID 批量分配第一个 IAM 页 ID 批量分配盘区 ID 添加了 VLF 无效缓存 ID 无效缓存键 CopyVerionInfo 源页面 ID CopyVerionInfo 源页面 LSN CopyVerionInfo 源插槽 ID CopyVerionInfo 源槽计数 行日志内容 0 行日志内容 1 行日志内容 2 行日志内容 3 行日志内容 4 行日志内容 5 压缩日志类型 压缩信息 页面格式 页面类型 页面格式页面标志 页面格式页面级别 页面格式 页面统计 页面格式格式选项 日志记录
0000008F:000292B0:0006 LOP_FS_DOWNLEVEL_OP LCX_NULL 0000:0022f09f 0 0x0000 24 360 0000008F:000292B0:0005 0x0002 366 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 操作创建;文件 ID 65537;名称 3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8-922c-4821-904e-7555c031630d\0000008f-000292b0-0006 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 无效的 0x000018008F000000B0920200050002009FF022000000910001004A01010000007000C00001000000010001000000000000000000000046003A005C00530051004C005300650072007600650072005C004D005300530051004C00310035002E004800560032003000310039005C004D005300530051004C005C0044004100540041005C006400610067005F0074006500730074005F00640062005F00660067005F0066007300330065003600610030003700350037002D0037003400300035002D0034006500650032002D0062003800610038002D006400660038003700380062003800630064003700630065005C00610031003000650033006100650038002D0039003200320063002D0034003800320031002D0039003000340065002D003700350035003500630030003300310036003300300064005C00300030003000300030003000380066002D00300030003000320038006600360038002D0030003000310030000001

错误消息中引用的文件确实存在于转发器的文件系统上:

C:\Users\Hannah>dir F:\SQLServer\HV2019\FILESTREAM\dag_test_db\dag_test_db_fg_fs_f01\3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8-922c-4821-904e-7555c031630d\0 000008f-000292b0-0006
 驱动器 F 中的卷没有标签。
 卷序列号为 90BA-CEC3

 F:\SQLServer\HV2019\FILESTREAM\dag_test_db\dag_test_db_fg_fs_f01\3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8-922c-4821-904e-7555c031630d的目录

2023 年 4 月 28 日 10:27 下午 797,346 0000008f-000292b0-0006
               1 文件 797,346 字节
               0 个目录 123,663,937,536 字节可用

icacls对于转发器上有问题的路径显示:

icacls F:\SQLServer\HV2019\FILESTREAM\dag_test_db\dag_test_db_fg_fs_f01\3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8-922c-4821-904e-7555c031630d
F:\SQLServer\HV2019\FILESTREAM\dag_test_db\dag_test_db_fg_fs_f01\3e6a0757-7405-4ee2-b8a8-df878b8cd7ce\a10e3ae8-922c-4821-904e-7555c031630d NT 服务\MSSQL$HV201 9:(I)(OI)(CI)(F) )
                                                                                                                                           所有者权利:(I)(OI)(CI)(F)
                                                                                                                                           内置\管理员:(I)(OI)(CI)(F)

成功处理1个文件;处理 0 个文件失败

从我所看到的来看,权限看起来不错 - SQL Server 服务完全控制文件,实际上是F:\SQLServer\HV2019.

Han*_*non 1

我无法最终确定其根本原因是什么SUSPEND_FROM_CAPTURE。显然,此状态表明转发器(或辅助设备)无法再以允许辅助设备跟上主设备的方式从主设备读取日志流。

为了在转发器上解决此问题,我从 SQLAG200 可用性组主数据库(即转发器)中删除了数据库,然后将其从 SQLAG200 可用性组辅助数据库中删除。然后,我从 SQLAG200 辅助数据库和 SQLAG200 主数据库上的备份恢复数据库,确保恢复适用的事务日志备份,以使数据库的每个副本尽可能接近 SQLAG100 上数据库的全局主副本中的状态。恢复完成后,我可以通过以下方式让转发器赶上全局主节点:

ALTER DATABASE [dag_test_db] SET HADR AVAILABILITY GROUP = [SQLAG200];
ALTER DATABASE [dag_test_db] SET HADR RESUME;
Run Code Online (Sandbox Code Playgroud)

这会将新恢复的数据库关联到转发器可用性组,并通过分布式可用性组扩展至全局主可用性组。

货运代理上船后,我在二级货运代理上执行了以下操作:

ALTER DATABASE [dag_test_db] SET HADR AVAILABILITY GROUP = [SQLAG200];
ALTER DATABASE [dag_test_db] SET HADR RESUME;
Run Code Online (Sandbox Code Playgroud)

最后,它看起来很稳定。对我来说,这一切的收获是数据库的主副本在任何时候都不会脱机,或者对我的 C# Filestream 测试客户端不可用。它只是继续将文件写入dag_test_db文件流文件组。这可能需要一段时间,但只要主要在线,业务就不会太不安。

我很高兴有一个像这样的家庭实验室设置,在这里我可以练习如何在这些问题影响真正的生产数据库之前处理这些问题。

Microsoft CSS 有一个未记录的跟踪标志,可在 SQL Server 启动时使用它来禁用多个日志流,这是 SQL Server 2022 中的一项新功能。就我而言,启用该跟踪标志解决了问题;删除跟踪标志会导致问题几乎立即再次出现。