将资源调控器与 SQL 代理作业一起使用

Aru*_*ath 4 sql-server resource-governor sql-server-2014

我正在尝试设置资源调控器,以限制使用 SQL 代理作业运行的进程的 IOPS。分类器函数设置为标识特定登录(使用该登录运行的任何 spid 都应使用分配给它的资源组)。然后我EXECUTE AS LOGIN = 'ResourceGovernerUser'在作业中添加,但我无法让它工作并且它回退到默认池,因为作业是'EXECUTED AS 'ServiceAccount''. 尽管如果我使用 来查看活动进程sp_WhoisActive,登录名会显示为'ResourceGovernerUser'而不是服务帐户。所以我修改了分类器函数以使用服务帐户,然后它就可以工作了。我使用 perfmon 计数器'Disk Read IO/Sec'和对象'Disk Write IO/Sec'下验证了这一点'Resource Pool Stats'

问题是 - 如何让资源调控器使用服务帐户以外的登录名(与代理作业一起使用时)?我确实有一些未经测试的丑陋想法,例如 - 使用 CmdExec 或 PowerShell 代理运行作业。如果有人遇到过类似的情况或有更好的想法,我将不胜感激。谢谢你。

    --Example Setup:
    USE [master]
    GO

    CREATE RESOURCE POOL [SqlJobPool] WITH( 
            min_iops_per_volume=1, 
            max_iops_per_volume=5000); 
    GO

    CREATE WORKLOAD GROUP [IOGroup] 
        USING [SqlJobPool];
    GO

    CREATE FUNCTION [dbo].[fn_LimitedIO]()
    RETURNS SYSNAME WITH SCHEMABINDING
    AS
        BEGIN
            DECLARE @grp SYSNAME;

            IF SUSER_NAME() = N'ResourceGovernerUser' -- When this is set to the Service Account, it works
                BEGIN
                    SET @grp = N'IOGroup';
                END
            ELSE
                BEGIN
                    SET @grp = N'default';
                END
            RETURN @grp;
        END
    GO

    ALTER RESOURCE GOVERNOR with (CLASSIFIER_FUNCTION = dbo.fn_LimitedIO);
    ALTER RESOURCE GOVERNOR RECONFIGURE;
    GO 

    --Within the Agent job
    EXECUTE AS Login = 'ResourceGovernerUser'
    EXECUTE SomeSQLStuff
Run Code Online (Sandbox Code Playgroud)

Han*_*non 6

资源调控器分类器功能仅在登录过程中运行。模拟通过EXECUTE AS不会触发分类器功能。 EXECUTE AS是 SQL Server 代理在另一个登录名或用户的上下文中运行作业的方式。

指定Run As ...用户或修改Job Owner不会改变 SQL Server 代理登录到 SQL Server 的方式。让 SQL Server 代理作业在特定资源组中运行的唯一方法是将 SQL Server 代理服务帐户放入它自己的资源组中。

由于测试是了解实际情况的好方法,因此我创建了一个小型测试平台。不要在生产系统上运行它,因为它会修改资源组配置。

这将创建分类器函数,以及附加到测试资源池的几个资源组:

USE master;
SET NOCOUNT ON;
GO
CREATE FUNCTION dbo.fnDummyClassifier()
RETURNS sysname
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @GroupName sysname = NULL;
    IF SUSER_SNAME() = 'DOMAIN\USER'
        SET @GroupName = N'AgentServiceAccountGroup';

    IF SUSER_SNAME() = 'ResourceGovernorTestLogin'
        SET @GroupName = N'ResourceGovernorTestLoginGroup';

    IF SUSER_SNAME() = 'ResourceGovernorTestUser'
        SET @GroupName = N'ResourceGovernorTestUserGroup';

    IF @GroupName IS NULL
        SET @GroupName =  N'default';

    RETURN @GroupName;
END
GO
CREATE RESOURCE POOL TestPool
WITH (MAX_CPU_PERCENT = 10); 
CREATE WORKLOAD GROUP AgentServiceAccountGroup 
WITH (
      group_max_requests=0
    , importance=Medium
    , request_max_cpu_time_sec=0
    , request_max_memory_grant_percent=25
    , request_memory_grant_timeout_sec=0
    , max_dop=0
    )
USING TestPool;
CREATE WORKLOAD GROUP ResourceGovernorTestLoginGroup 
WITH (
      group_max_requests=0
    , importance=Medium
    , request_max_cpu_time_sec=0
    , request_max_memory_grant_percent=25
    , request_memory_grant_timeout_sec=0
    , max_dop=0
    )
USING TestPool;
CREATE WORKLOAD GROUP ResourceGovernorTestUserGroup 
WITH (
      group_max_requests=0
    , importance=Medium
    , request_max_cpu_time_sec=0
    , request_max_memory_grant_percent=25
    , request_memory_grant_timeout_sec=0
    , max_dop=0
    )
USING TestPool;
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = [dbo].[fnDummyClassifier]);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
Run Code Online (Sandbox Code Playgroud)

在这里,我们将创建一个登录名,并允许它登录,VIEW SERVER STATE这样我们就可以知道会话已分配给哪个资源组。

CREATE LOGIN ResourceGovernorTestLogin
WITH PASSWORD = '!NnrtiHummusPlenumPoodle2'
    , DEFAULT_LANGUAGE = us_english
    , CHECK_EXPIRATION = OFF
    , CHECK_POLICY = OFF;
GRANT VIEW SERVER STATE TO ResourceGovernorTestLogin;
GO
Run Code Online (Sandbox Code Playgroud)

这将创建一个 SQL Server 代理作业,其中“所有者”设置为我们刚刚创建的登录名。由于登录名不是 sysadmin 的成员,SQL Server 代理将在该登录名的上下文中运行此作业。

DECLARE @JobID uniqueidentifier;
EXEC msdb.dbo.sp_add_job @job_name = 'TestResourceGovernorJob'
    , @enabled = 1
    , @description = 'Tests resource governor classification'
    , @start_step_id = 1
    , @owner_login_name = 'ResourceGovernorTestLogin'
    , @job_id = @JobID OUTPUT;
EXEC msdb.dbo.sp_add_jobstep @job_id = @JobID, @step_id = 1, @step_name = 'Step1'
    , @subsystem = 'TSQL'
    , @command = 'SELECT '''';
SELECT UserName = CONVERT(nvarchar(30), SUSER_SNAME())
    , [SYSTEM_USER] = CONVERT(nvarchar(30), SYSTEM_USER)
    , [SESSION_USER] = CONVERT(nvarchar(30), SESSION_USER)
    , [ORIGINAL_LOGIN] = CONVERT(nvarchar(30), ORIGINAL_LOGIN())
    , WorkloadGroup = CONVERT(nvarchar(30), wg.name)
FROM sys.dm_exec_requests der
    INNER JOIN sys.dm_resource_governor_workload_groups wg ON der.group_id = wg.group_id
WHERE der.session_id = @@SPID;'
    , @flags = 4 --write step output into msdb.dbo.sysjobstephistory
    , @on_success_action = 1;
EXEC msdb.dbo.sp_add_jobserver @job_id = @JobID, @server_name = N'(LOCAL)';
/*
    Call SQL Server Agent via msdb.dbo.sp_notify_job 
    which in turn calls msdb.dbo.xp_notify_job.
    The SQL Server Agent executable logs into the
    SQL Server instance using the service account,
    then performs an "EXECUTE AS ..." to run
    job step(s).
*/
EXEC msdb.dbo.sp_start_job @job_id = @JobID;
GO

WAITFOR DELAY N'00:00:01';
DECLARE @msg nvarchar(max);
SELECT @msg = sjh.message
FROM msdb.dbo.sysjobhistory sjh
    INNER JOIN msdb.dbo.sysjobs sj ON sjh.job_id = sj.job_id
WHERE sj.name = 'TestResourceGovernorJob'
    AND sjh.step_id = 1;
PRINT (N'');
PRINT (@msg);
PRINT (N'');
EXEC msdb.dbo.sp_delete_job @job_name = 'TestResourceGovernorJob';
GO
Run Code Online (Sandbox Code Playgroud)

来自上述作业的 msdb 历史记录表的结果:

作业“TestResourceGovernorJob”成功启动。

以用户身份执行:ResourceGovernorTestLogin。 
——

(1 行受影响)
用户名 SYSTEM_USER SESSION_USER ORIGINAL_LOGIN WorkloadGroup
------------------------------ --------------------- ---------- ------------------------------ ---------- -------------------- ------------------------------
ResourceGovernorTestLogin ResourceGovernorTestLogin 来宾 DOMAIN\USER AgentServiceAccountGroup
(受影响的 1 行)。步骤成功了。

接下来,我们将为登录创建一个用户,并使用Run AsSQL Server 作业步骤的高级属性中的选项运行新版本的作业。

CREATE USER ResourceGovernorTestUser
FOR LOGIN ResourceGovernorTestLogin;

DECLARE @JobID uniqueidentifier;
EXEC msdb.dbo.sp_add_job @job_name = 'TestResourceGovernorJob'
    , @enabled = 1
    , @description = 'Tests resource governor classification'
    , @start_step_id = 1
    , @owner_login_name = 'ResourceGovernorTestLogin'
    , @job_id = @JobID OUTPUT;
EXEC msdb.dbo.sp_add_jobstep @job_id = @JobID, @step_id = 1, @step_name = 'Step1'
    , @subsystem = 'TSQL'
    , @database_name = 'master'
    , @database_user_name = 'ResourceGovernorTestUser'
    , @command = 'SELECT '''';
SELECT UserName = CONVERT(nvarchar(30), SUSER_SNAME())
    , [SYSTEM_USER] = CONVERT(nvarchar(30), SYSTEM_USER)
    , [SESSION_USER] = CONVERT(nvarchar(30), SESSION_USER)
    , [ORIGINAL_LOGIN] = CONVERT(nvarchar(30), ORIGINAL_LOGIN())
    , WorkloadGroup = CONVERT(nvarchar(30), wg.name)
FROM sys.dm_exec_requests der
    INNER JOIN sys.dm_resource_governor_workload_groups wg ON der.group_id = wg.group_id
WHERE der.session_id = @@SPID;'
    , @flags = 4 --write step output into msdb.dbo.sysjobstephistory
    , @on_success_action = 1;
EXEC msdb.dbo.sp_add_jobserver @job_id = @JobID, @server_name = N'(LOCAL)';
/*
    Call SQL Server Agent via msdb.dbo.sp_notify_job 
    which in turn calls msdb.dbo.xp_notify_job.
    The SQL Server Agent executable logs into the
    SQL Server instance using the service account,
    then performs an "EXECUTE AS ..." to run
    job step(s).
*/
EXEC msdb.dbo.sp_start_job @job_id = @JobID;
GO

WAITFOR DELAY N'00:00:01';
DECLARE @msg nvarchar(max);
SELECT @msg = sjh.message
FROM msdb.dbo.sysjobhistory sjh
    INNER JOIN msdb.dbo.sysjobs sj ON sjh.job_id = sj.job_id
WHERE sj.name = 'TestResourceGovernorJob'
    AND sjh.step_id = 1;
PRINT (N'');
PRINT (@msg);
PRINT (N'');
EXEC msdb.dbo.sp_delete_job @job_name = 'TestResourceGovernorJob';

DROP USER ResourceGovernorTestUser;
GO
Run Code Online (Sandbox Code Playgroud)

作业运行的输出:

作业“TestResourceGovernorJob”成功启动。

以用户身份执行:ResourceGovernorTestLogin。 
——

(1 行受影响)
用户名 SYSTEM_USER SESSION_USER ORIGINAL_LOGIN WorkloadGroup
------------------------------ --------------------- ---------- ------------------------------ ---------- -------------------- ------------------------------
ResourceGovernorTestLogin ResourceGovernorTestLogin ResourceGovernorTestUser DOMAIN\USER AgentServiceAccountGroup
(受影响的 1 行)。步骤成功了。

这会清理资源调控器配置,并删除分类器功能和登录。

ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL);
DROP WORKLOAD GROUP AgentServiceAccountGroup;
DROP WORKLOAD GROUP ResourceGovernorTestUserGroup;
DROP WORKLOAD GROUP ResourceGovernorTestLoginGroup;
DROP RESOURCE POOL TestPool;
ALTER RESOURCE GOVERNOR RECONFIGURE;
DROP FUNCTION dbo.fnDummyClassifier
DROP LOGIN ResourceGovernorTestLogin;
GO
Run Code Online (Sandbox Code Playgroud)

在上面的两个结果集中,您可以看到资源调控器分类器函数将每个作业放入AgentServiceAccountGroup组中;这是因为 SQL Server 代理最初使用 SQL Server 代理启动时使用的服务帐户登录到 SQL Server。