Azure SQL .NET NHibernate 的异地复制 sp_wait_for_database_copy_sync 问题
Azure SQL Geo-Replication with .NET NHibernate sp_wait_for_database_copy_sync issue
在我们的应用程序开发过程中,我们引入了 Azure SQL 地理复制以改善不同地理位置的用户体验和响应能力。
目前在测试中我们有两个实例 - 一个主要实例和一个辅助实例*,其中一个在美国,另一个在欧洲。
问题
来自 primary 数据库的新更新数据在 secondary 数据库中似乎不可用,即使 sp_wait_for_database_copy_sync 是调用,这应该确保这一点。
重现问题的步骤
- 用户连接到 辅助 实例
- 用户更新数据('UPDATE' 或 'INSERT' 进入 主 数据库)
- 事务已提交
- 使用适当的参数调用 sp_wait_for_database_copy_sync 过程,以确保在更新调用解除阻塞时数据将复制到辅助实例中
- 更新调用解锁后,将尝试在 辅助 数据库上提取数据(包括新更新或插入的数据)。
- 新更新或插入的数据未包含在结果集中 - 尽管数据库复制同步过程无法确保数据将在更新调用取消阻止时被复制,但它出现在结果集中
技术实现细节
当实体即将更新,事务提交,数据同步保证时,依次调用以下三行代码:
ISession.Save(object obj)
用于保存新实体
ISession.Flush()
用于提交事务
ISession.CreateSQLQuery("EXEC sys.sp_wait_for_database_copy_sync
@target_server = N\'secondary-server\', @target_database
= N\'database\';").ExecuteUpdate()
用于执行呼叫阻塞同步程序
问题
以上三行代码可能有什么问题?
我看到的可能的罪魁祸首是:
ISession.Flush
没有同步执行,因此执行阻塞存储过程时事务还没有真正提交
ISession.CreateSQLQuery("EXEC sys.sp_wait_for_database_copy_sync
@target_server = N\'secondary-server\', @target_database
= N\'database\';").ExecuteUpdate()
实际上并没有被阻止。
如果您有任何关于如何解决上述两个问题或您看到的其他问题的想法,我们将不胜感激。
- 在这种情况下,主要和次要是关于异地复制设置。
Azure SQL 数据库异地复制是为用户数据库设计的,而不是为主数据库设计的。将更新文档以明确这一点。
当你在这里说"master"时,你指的是异地复制关系中的主数据库,还是逻辑主数据库?
NHibernate 是同步的。 ISession.Flush
总是同步的。但是,如果您在分布式 TransactionScope
中(检查 System.Transactions.Transaction.Current?.TransactionInformation?.DistributedIdentifier ?? default(Guid) != Guid.Empty
),则 MSDTC 会启动并导致数据库中的实际提交是异步的,最终发生在范围处置之后。 Read more here..
我不确定 Azure 是否接受分布式事务,所以这可能不是你遇到麻烦的原因。
如果您处于分布式事务的情况下,那么根据您的 queries/database 设置/...引起的锁定,您将不得不从数据库中读回您提交的数据,这取决于事务锁会阻止你,直到它被实际提交,然后执行你的同步。或者,如果你没有被锁定,轮询数据库直到看到你的数据(当然,这对性能来说是最糟糕的),然后执行你的同步。
顺便说一下,我不知道 Azure 异地复制是如何工作的,但如果它也使用 MSDTC,那么它本身可能会遇到那些异步问题。
关于 SQL Exec
没有被实际阻止,那将是一个 SQL Azure 问题。
我忘记了 post 这里,但问题是以下过程虽然阻塞,但实际上并不能保证一旦解除阻塞,数据将在所有实例中可用:
sp_wait_for_database_copy_sync.
在我们的应用程序开发过程中,我们引入了 Azure SQL 地理复制以改善不同地理位置的用户体验和响应能力。
目前在测试中我们有两个实例 - 一个主要实例和一个辅助实例*,其中一个在美国,另一个在欧洲。
问题
来自 primary 数据库的新更新数据在 secondary 数据库中似乎不可用,即使 sp_wait_for_database_copy_sync 是调用,这应该确保这一点。
重现问题的步骤
- 用户连接到 辅助 实例
- 用户更新数据('UPDATE' 或 'INSERT' 进入 主 数据库)
- 事务已提交
- 使用适当的参数调用 sp_wait_for_database_copy_sync 过程,以确保在更新调用解除阻塞时数据将复制到辅助实例中
- 更新调用解锁后,将尝试在 辅助 数据库上提取数据(包括新更新或插入的数据)。
- 新更新或插入的数据未包含在结果集中 - 尽管数据库复制同步过程无法确保数据将在更新调用取消阻止时被复制,但它出现在结果集中
技术实现细节
当实体即将更新,事务提交,数据同步保证时,依次调用以下三行代码:
ISession.Save(object obj)
用于保存新实体ISession.Flush()
用于提交事务ISession.CreateSQLQuery("EXEC sys.sp_wait_for_database_copy_sync @target_server = N\'secondary-server\', @target_database = N\'database\';").ExecuteUpdate()
用于执行呼叫阻塞同步程序
问题
以上三行代码可能有什么问题? 我看到的可能的罪魁祸首是:
ISession.Flush
没有同步执行,因此执行阻塞存储过程时事务还没有真正提交ISession.CreateSQLQuery("EXEC sys.sp_wait_for_database_copy_sync @target_server = N\'secondary-server\', @target_database = N\'database\';").ExecuteUpdate()
实际上并没有被阻止。
如果您有任何关于如何解决上述两个问题或您看到的其他问题的想法,我们将不胜感激。
- 在这种情况下,主要和次要是关于异地复制设置。
Azure SQL 数据库异地复制是为用户数据库设计的,而不是为主数据库设计的。将更新文档以明确这一点。
当你在这里说"master"时,你指的是异地复制关系中的主数据库,还是逻辑主数据库?
NHibernate 是同步的。 ISession.Flush
总是同步的。但是,如果您在分布式 TransactionScope
中(检查 System.Transactions.Transaction.Current?.TransactionInformation?.DistributedIdentifier ?? default(Guid) != Guid.Empty
),则 MSDTC 会启动并导致数据库中的实际提交是异步的,最终发生在范围处置之后。 Read more here..
我不确定 Azure 是否接受分布式事务,所以这可能不是你遇到麻烦的原因。
如果您处于分布式事务的情况下,那么根据您的 queries/database 设置/...引起的锁定,您将不得不从数据库中读回您提交的数据,这取决于事务锁会阻止你,直到它被实际提交,然后执行你的同步。或者,如果你没有被锁定,轮询数据库直到看到你的数据(当然,这对性能来说是最糟糕的),然后执行你的同步。
顺便说一下,我不知道 Azure 异地复制是如何工作的,但如果它也使用 MSDTC,那么它本身可能会遇到那些异步问题。
关于 SQL Exec
没有被实际阻止,那将是一个 SQL Azure 问题。
我忘记了 post 这里,但问题是以下过程虽然阻塞,但实际上并不能保证一旦解除阻塞,数据将在所有实例中可用: sp_wait_for_database_copy_sync.