![SQL AlwaysOn 可用性组中的数据一致性](https://linux22.com/image/768506/SQL%20AlwaysOn%20%E5%8F%AF%E7%94%A8%E6%80%A7%E7%BB%84%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E6%80%A7.png)
我有一个 SQL Server 2019 的 AlwaysOn 群集,其中包含一个处于同步模式的 3 个副本的可用性组。根据Microsoft 文档:
- 辅助副本强化日志并向主副本返回确认。
- 在收到来自辅助副本的确认后,主副本完成提交处理并向客户端发送确认消息。
本文更详细地解释道:
- 在辅助副本中,日志接收从主副本获取日志记录并写入日志缓存。此过程在每个参与同步提交模式的辅助副本上重复。
- 在每个辅助副本上,都有一个重做线程,它将日志记录中提到的所有更改写入数据页和索引页。它会刷新日志以强化辅助数据库日志。
- 如前所述,在同步数据提交中,主副本等待来自辅助副本的确认。在此阶段,辅助副本发送确认,表示事务强化已在辅助副本上完成。
- 一旦主副本收到来自辅助副本的确认,它就会向客户端发送事务完成消息。
如果我理解正确的话: 如果我通过主副本成功更新记录,则此更新的值应该是立即地可供客户端查询辅助副本使用。
然而,当我测试这个时,这不起作用所以。我运行一个简单的批处理文件,如下所示:
sqlcmd -E -S tcp:SQL-AG-Listener -d TestDB -Q "BEGIN TRANSACTION; UPDATE TestSyncTable SET CurrentTime='%currentTime%'; COMMIT TRANSACTION;"
sqlcmd -E -S tcp:SQL-Server01 -d TestDB -Q "SELECT * FROM TestSyncTable" -K ReadOnly
sqlcmd -E -S tcp:SQL-Server02 -d TestDB -Q "SELECT * FROM TestSyncTable" -K ReadOnly
sqlcmd -E -S tcp:SQL-Server03 -d TestDB -Q "SELECT * FROM TestSyncTable" -K ReadOnly
因此,我CurrentTime
通过主副本(托管 AG 侦听器)更新字段,然后立即通过所有三个副本读取它。每个sqlcmd
命令都是一个单独的客户端进程,因此它会打开自己独立的 TCP 连接。
然后我看到了类似这样的内容:
SQL-Server01: CurrentTime = 20:02:19.93
SQL-Server02: CurrentTime = 20:02:16.94
SQL-Server03: CurrentTime = 20:02:19.93
(此处重新格式化了输出以提高可读性)
据我所知,主副本始终返回更新后的值。辅助副本也是如此 - 但只有短暂的延迟。
所以问题是:为什么?同步模式难道不应该保证读操作的结果与写操作的结果一致吗?如果辅助副本仅在其 Redo 线程更新数据页后才发送确认 - 那怎么可能呢?
谢谢,Mucius。
答案1
来自您在问题中引用的同一篇 SQL Shack 文章:
- 辅助副本还包含一个重做线程,它独立于 SQL Server Always on 中的日志块进程。重做线程从日志缓存中读取日志。重做线程处理时可能会有延迟,并且日志记录可能在日志缓存中不可用,因为它已经固化到磁盘。在这种情况下,重做线程从日志磁盘读取日志块。
我的理解是,日志强化过程不会使更改立即在辅助数据库中可用,而是辅助数据库中的重做线程需要先处理它们。