Goo*_*SQL 2 sql-server availability-groups read-only-database sql-server-2016
我们有一个独特的情况,我们希望允许用户使用 SSMS 查询数据库的可读辅助副本以进行临时报告,但不允许他们从主副本中读取数据。我们设置了只读路由来完成此任务。这也是 SQL 2016 上的全部。
我最初的想法是在主副本和辅助副本上创建登录名,并授予对相关数据库的读取访问权限。然后我们将拒绝连接或禁用当前主副本上的登录。在 SSMS 中,用户可以使用 ApplicationIntent=ReadOnly 连接到侦听器,并路由到辅助副本,而无需接触主副本。
我们将使用基本逻辑在主副本服务器和辅助副本服务器上设置一个简单的作业:如果当前服务器=主服务器,则禁用登录;如果当前服务器 = 辅助服务器,则启用登录。
问题是,当在主服务器上禁用登录时,以只读意图连接到侦听器时,我会遇到登录失败。当我在主副本上重新启用登录时,它工作得很好,并且连接已正确路由到可读的辅助副本。
我在主服务器上设置了跟踪,果然,我可以看到登录连接并在主副本上的 master 和 msdb 中运行一些系统类型查询 - 即使我在 SSMS 中使用 ApplicationIntent=ReadOnly 进行连接。我不确定这是否是 SSMS 在幕后执行的操作,或者是否是登录通过只读路由过程的默认行为。
以下是我在主数据库上使用快速分析器跟踪捕获的查询:
--msdb query
select
case
when object_id('dbo.sysdac_instances') is not null then 1
else
0
end
--master query
SELECT
dtb.name AS [Name],
dtb.database_id AS [ID],
CAST(has_dbaccess(dtb.name) AS bit) AS [IsAccessible]
FROM
master.sys.databases AS dtb
ORDER BY
[Name] ASC
Run Code Online (Sandbox Code Playgroud)
以前有人处理过这种情况吗?看来我们基本上需要允许主副本上的登录连接权限,同时拒绝其对主副本上 AG 中的数据库的读取访问权限,但授予该登录权限以读取可读辅助副本上的数据库。
另一种选择是创建一个直接指向辅助副本的 DNS 条目,但我们不能保证该副本始终是辅助副本,因为可能会发生故障转移。
看来我们基本上需要允许主副本上的登录连接权限[...]
完全正确。用于连接的登录名必须能够连接到主数据库。
当您ApplicationIntent=ReadOnly
在指向 AG 侦听器的连接字符串中使用时,驱动程序最初会连接到主实例。这样 SQL Server 就可以查看副本列表并查看是否有任何可用的在线可读副本可供您发送。此处记录了这一点:
可用性组的主数据库处理传入的只读路由请求,并尝试查找已加入主副本并配置为只读路由的在线只读副本。客户端从主副本服务器接收返回连接信息并连接到所识别的只读副本。
微软顶级人士 Sean Gallardy 在 PFE 博客上也对流程进行了很好的总结:
- 我们通过驱动程序创建连接
- 驱动程序通过监听器连接SQL Server并传递相关信息
- SQL Server 注意到我们只读了路由设置并检查配置
- SQL Server 向驱动程序报告我们有一个可以使用的只读辅助数据库
- SQL Server 将新的辅助信息发送给驱动程序
- 驱动程序使用给定信息创建与辅助设备的新连接
关于您在问题中提到的其他事项:
[...] 同时拒绝其对主副本上 AG 中数据库的读取访问权限,但授予该登录权限以读取可读辅助副本上的数据库。
数据库级别权限将在 AG 之间复制 - 因此,如果您删除用户在主数据库上的读取访问权限,他们也将失去在辅助数据库上的读取访问权限。
我对这种努力的目标有点困惑,因为理论上数据应该是相同的(或接近相同的)。也许出于性能原因,您根本不希望某些登录在主数据库上运行查询。表达只读意图并连接到听众实际上是解决这个问题的最直接的方法。
其他选项将涉及单独的硬件,或应用程序中的自定义编码,用于处理直接连接到正确的副本(如果发生故障转移,则重试逻辑,并在每个副本上计划作业以在发生故障转移时禁用/启用登录, ETC)。