web-dev-qa-db-ja.com

SQLエージェントジョブでのリソースガバナーの使用

SQLエージェントジョブを使用して実行されているプロセスのIOPSを制限するようにリソースガバナーをセットアップしようとしています。分類関数は、特定のログインを識別するように設定されています(そのログインを使用して実行されているすべてのspidは、割り当てられているリソースグループを使用する必要があります)。次に、ジョブ内にEXECUTE AS LOGIN = 'ResourceGovernerUser'を追加しましたが、機能させることができず、ジョブが'EXECUTED AS 'ServiceAccount''であるため、デフォルトのプールにフォールバックします。 sp_WhoisActiveを使用してアクティブなプロセスを見ると、ログイン名はサービスアカウントではなく'ResourceGovernerUser'と表示されます。そのため、サービスアカウントを使用するように分類関数を変更したところ、機能しました。これは、'Disk Read IO/Sec'オブジェクトの下のperfmonカウンター'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
4
Arun Gopinath

リソースガバナー分類関数は、ログインプロセス中にのみ実行されます。 EXECUTE ASによる偽装は、分類機能をトリガーしません。 EXECUTE ASは、SQL Serverエージェントが別のログインまたはユーザーのコンテキストでジョブを実行する方法です。

Run As ...ユーザーを指定したり、Job Ownerを変更したりしても、SQL ServerエージェントがSQL Serverにログインする方法は変わりません。ユーザー名のみを参照する分類関数を使用してSQL Serverエージェントジョブを特定のリソースグループで実行できる唯一の方法は、SQL ServerエージェントService Accountを独自のリソースグループに配置することです。

テストは実際に何が起こっているのかを理解するための優れた方法であるため、小さなテストベッドを作成しました。これはリソースグループの構成を変更するため、運用システムでは実行しないでください。

これにより、分類関数と、テストリソースプールに接続されたいくつかのリソースグループが作成されます。

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

ここではログインを作成し、それを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

これにより、「所有者」が先ほど作成したログインに設定された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

上記のジョブのmsdb履歴テーブルの結果:

ジョブ「TestResourceGovernorJob」が正常に開始されました。
 
ユーザーとして実行:ResourceGovernorTestLogin。 
-
 
(1行が影響を受けました)
 UserName SYSTEM_USER SESSION_USER ORIGINAL_LOGIN WorkloadGroup 
 ----------- ------------------- ------------------------------- ----------------------------- --------------------- --------- ------------------------------ 
 ResourceGovernorTestLogin ResourceGovernorTestLogin guest DOMAIN\USER AgentServiceAccountGroup 
(1行が影響を受けました)。ステップは成功しました。

次に、ログイン用のユーザーを作成し、SQL Serverジョブステップの詳細プロパティのRun Asオプションを使用して、ジョブの新しいバージョンを実行します。

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

ジョブのその実行からの出力:

ジョブ「TestResourceGovernorJob」が正常に開始されました。
 
ユーザーとして実行:ResourceGovernorTestLogin。 
-
 
(1行が影響を受けました)
 UserName 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

上記の両方の結果セットで、リソースガバナー分類関数が各ジョブをAgentServiceAccountGroupグループに入れていることがわかります。これは、SQL Serverエージェントの起動時に使用されるサービスアカウントを使用して、SQL Serverエージェントが最初にSQL Serverにログインするためです。

5
Max Vernon