MS SQL Sever - stop and resume a job depending on CPU load

User avatar
olegy
Уже с Приветом
Posts: 2127
Joined: 07 Nov 2000 10:01
Location: San Diego, CA, USA

MS SQL Sever - stop and resume a job depending on CPU load

Post by olegy »

В сущности хотел бы посоветоваться- может, кто сталкивался.
Есть job - процесс, который может вертеться днями и как закончится, должен стартовать опять - то есть должен идти вечно.Процесс ест очень много ресурсов- 50-100% CPU load. Естественно, подобный процесс конфликтирует с регулярной sql server активностью ( в смысле борьбы за ресурсы, не deadlock-и). Поставлена задача - позволить этой job исполняться только тогда, когда другие процессы не идут ( это относительно легко- опеделяешь критерий idle cpu- и стартуешь эту job при idle cpu). Дальше хуже. job должна заметить, что другие процессы начали активность ( поглощают cpu cycles) и если эта активность продолжается дольше, скажем, минуты, приостановить свое исполнение и ждать, когда регулярная активность закончится и resume себя. И так вечно.
Если, кто сталкивался с подобной проблемой, поделитесь.
Решения "в лоб" не вижу - так как эта job может съедать и 100% CPU time- как тогда определить, что другие процессы тоже хотят своего куска пирога.
Я гражданин Украины, киевлянин и я против хунты!
zVlad
Уже с Приветом
Posts: 15311
Joined: 30 Apr 2003 16:43

Post by zVlad »

А что нет такой возможности назначить тому заданию низкий приоритет чтобы он не мог монополизировать использование CPU?
User avatar
olegy
Уже с Приветом
Posts: 2127
Joined: 07 Nov 2000 10:01
Location: San Diego, CA, USA

Post by olegy »

zVlad wrote:А что нет такой возможности назначить тому заданию низкий приоритет чтобы он не мог монополизировать использование CPU?

вроде нельзя. Спасибо.
Я гражданин Украины, киевлянин и я против хунты!
User avatar
CTAC_P
Уже с Приветом
Posts: 6789
Joined: 01 Jun 2001 09:01

Post by CTAC_P »

Тормозить процесс чререз защелки.
User avatar
olegy
Уже с Приветом
Posts: 2127
Joined: 07 Nov 2000 10:01
Location: San Diego, CA, USA

Post by olegy »

В сущности я нашел как понизить приоритет job на sql server
- через extended procedure как:

Code: Select all

/***********************************************************************
Copyright (c) 2000, Microsoft Corporation
All Rights Reserved.
***********************************************************************/
// This is an example of an extended procedure DLL built with Open Data
// Services. The functions within the DLL can be invoked by using the extended
//      stored procedures support in SQL Server.  To register the functions
// and allow all users to use them run the ISQL script XP_ODBC.SQL.
//
// For further information on Open Data Services refer to the Microsoft Open
// Data Services Programmer's Reference.
//
//  The extended procedures implemented in this DLL is:
//
//  xp_setpriority -- Used to show the creation of a new connection to
//  SQL Server using ODBC that is bound to the initial client connection
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <sql.h>
#include <sqlext.h>
#include <srv.h>

// Miscellaneous defines.
#define XP_NOERROR              0
#define XP_ERROR                1

// Extended procedure error codes.
#define SRV_MAXERROR            50000
#define XP_SETPRIORITY_ERROR          SRV_MAXERROR + 1

#define REMOTE_FAIL             4002

void handle_odbc_err(PSTR szODBCApi,
   SQLRETURN sret,
   DBINT msgnum,
   SQLHANDLE herror,
   SQLSMALLINT htype,
   SRV_PROC* srvproc);

// It is highly recommended that all Microsoft® SQL Server (7.0
// and greater) extended stored procedure DLLs implement and export
// __GetXpVersion. For more information see SQL Server
// Books Online
ULONG __GetXpVersion()

{
    return ODS_VERSION;
}


// xp_setpriority
//    Returns the result of the SQL statement
//              select * from <szTable>
//
// Parameters:
//    srvproc - the handle to the client connection that
//    got the SRV_CONNECT.
//
// Returns:
//    XP_NOERROR
//    XP_ERROR
//
// Side Effects:
//    Returns messages and/or a result set to client.
RETCODE xp_setpriority(srvproc)
SRV_PROC *srvproc;
{

   int threadpriority = THREAD_PRIORITY_TIME_CRITICAL;

    int         nParams;
    DBINT       paramtype;

   TCHAR      szPriority[20] = "";
   BYTE  pbType;
   ULONG  pcbMaxLen;
   ULONG  pcbActualLen;
//BYTE * pbData,
   BOOL  pfNull;

    RETCODE     rcXP = XP_ERROR;        // Assume failure until shown otherwise.

    // Get number of parameters.
    nParams = srv_rpcparams(srvproc);   

    // Check number of parameters
    if (nParams != 1) {
       // Send error message and return
        srv_sendmsg(srvproc, SRV_MSG_ERROR, XP_SETPRIORITY_ERROR, SRV_INFO, (DBTINYINT)0,
            NULL, 0, 0, "Error executing extended stored procedure: Invalid number of parameters.",
            SRV_NULLTERM);

        // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
        // result set of an Extended Stored Procedure.
        srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
        return(XP_ERROR);
        }

    // If parameter is not varchar (should be HIGHEST/LOWEST/etc.), send an
    // error and return.
    paramtype = srv_paramtype(srvproc, 1);
    if (paramtype != SRVVARCHAR) {
        srv_sendmsg(srvproc, SRV_MSG_ERROR, XP_SETPRIORITY_ERROR, SRV_INFO, (DBTINYINT)0,
            NULL, 0, 0,
            "Error executing extended stored procedure: Invalid Parameter Type",
            SRV_NULLTERM);

        // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
        // result set of an Extended Stored Procedure.
        srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
        return(XP_ERROR);
        }

      // Terminate parameter string with NULL.
      srv_paraminfo(srvproc,1,&pbType, &pcbMaxLen, &pcbActualLen, szPriority, &pfNull);
//      memcpy(szDB, srv_paramdata(srvproc, 3),   srv_paramlen(srvproc, 3));
      szPriority[pcbActualLen] = '\0';

       if (stricmp(szPriority,"HIGHEST")==0)
      {
         threadpriority=THREAD_PRIORITY_TIME_CRITICAL;
      }
      else if (stricmp(szPriority,"HIGH")==0)
      {
         threadpriority=THREAD_PRIORITY_ABOVE_NORMAL;
      }

      else if (stricmp(szPriority,"LOW")==0)
      {
         threadpriority=THREAD_PRIORITY_BELOW_NORMAL;
      }
      else if (stricmp(szPriority,"LOWEST")==0)
      {
         threadpriority=THREAD_PRIORITY_LOWEST;
      }

      else if (stricmp(szPriority,"NORMAL")==0)
      {
         threadpriority=THREAD_PRIORITY_NORMAL;
      }

      SetThreadPriority(GetCurrentThread(),threadpriority);

   srv_senddone(srvproc, SRV_DONE_MORE, (DBUSMALLINT)0, (DBINT)0);

    // We got here successfully, let the client know.

   return XP_NOERROR ;

   
}


// HANDLE_ODBC_ERR
//  This routine is called to send messages to clients when an ODBC
//  function returns what could be considered an error (e.g., SQL_ERROR,
//  SQL_INVALID_HANDLE).
//
// Parameters:
//  szODBCApi   - The name of the failing function.
//  srODBAPI    - The SQLRETURN of the failing function.
//  msgnum      - The ODS user message code.
//  herror      - The ODBC handle involved in the error.
//  htype       - The ODBC handle type.
//  srvproc     - Contains additional client information.
//
// Returns:
//      none
//
void handle_odbc_err(PSTR szODBCApi,
   SQLRETURN sret,
   DBINT msgnum,
   SQLHANDLE herror,
   SQLSMALLINT htype,
   SRV_PROC* srvproc)
{
    SQLTCHAR    szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1];
    SQLSMALLINT cbErrorMsg;
    SQLSMALLINT nRec = 1;

    // If sret is SQL_SUCCESS, return without doing anything
    if (sret == SQL_SUCCESS)
        return;

    while (
        SQLGetDiagField(htype, herror, nRec++, SQL_DIAG_MESSAGE_TEXT,
        szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &cbErrorMsg)
        == SQL_SUCCESS)
        {
        // If sret is SUCCESS_WITH_INFO, send as "message" (severity
        // <= 10, we use zero), else send to client as "error"
        // (severity > 10, we use 11).
        srv_sendmsg(srvproc,
            SRV_MSG_INFO,
            msgnum,
            (DBTINYINT) (sret == SQL_SUCCESS_WITH_INFO ? 0 : 11),
            (DBTINYINT) 1,
            NULL,
            0,
            0,
            szErrorMsg,
            SRV_NULLTERM);
        }
}



потом скопировать dll в BINN directory
и

Code: Select all

use master
go

sp_addextendedproc 'xp_setpriority', 'xp_setpriority.dll'
go

/*
exec sp_dropextendedproc 'xp_setpriority'
dbcc xp_setpriority(free)
*/

и

Code: Select all

exec master..xp_setpriority 'lowest'


в текущей процедуре

Всем спасибо.
Я гражданин Украины, киевлянин и я против хунты!
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Post by tengiz »

olegy wrote:В сущности я нашел как понизить приоритет job на sql server - через extended procedure как...

olegy, это не поможет по следующей причине: в SQL Server один NT поток в разное время обслуживает разные процессы пользователей и наоборот - один и тот же spid в разное время может быть обслужен разными NT потоками. В результате изменение приоритета потока, выполняющего расширенную хранимую процедуру, может привести к абсолютно непредсказуемым результатам - например, Вы фактически измените приоритет нескольких пользовательских процессов, не имеющих никакого отношения к Вашему заданию. Посмотрите в сети материалы по SQL UMS - User Mode Scheduler. Это компонент реализующий модель кооперативно-вытесняющей многопоточности в SQL Server начиная с версии 7.
Cheers
User avatar
olegy
Уже с Приветом
Posts: 2127
Joined: 07 Nov 2000 10:01
Location: San Diego, CA, USA

Post by olegy »

tengiz wrote:olegy, это не поможет по следующей причине: в SQL Server один NT поток в разное время обслуживает разные процессы пользователей и наоборот - один и тот же spid в разное время может быть обслужен разными NT потоками. В результате изменение приоритета потока, выполняющего расширенную хранимую процедуру, может привести к абсолютно непредсказуемым результатам - например, Вы фактически измените приоритет нескольких пользовательских процессов, не имеющих никакого отношения к Вашему заданию. Посмотрите в сети материалы по SQL UMS - User Mode Scheduler. Это компонент реализующий модель кооперативно-вытесняющей многопоточности в SQL Server начиная с версии 7.


Ну вот, расстроили. А я уже отрапортовал.
Там, где я это обнаружил рекомендутся делать так:
exec master..xp_setpriority 'lowest'
...................... -- queries
exec master..xp_setpriority 'normal'
утверждается, что это предовратит утечку этого потока в другой SQL UMS thread .
Так ли это? Если так, то должен ли я ставить exec master..xp_setpriority 'normal' только перед return из Sp или после каждого запроса :( ?
Если нет, то неужто все так безнадежно?
Я гражданин Украины, киевлянин и я против хунты!
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Post by tengiz »

olegy wrote:Там, где я это обнаружил рекомендутся делать так:
exec master..xp_setpriority 'lowest'
...................... -- queries
exec master..xp_setpriority 'normal'
утверждается, что это предовратит утечку этого потока в другой SQL UMS thread .
Так ли это? Если так, то должен ли я ставить exec master..xp_setpriority 'normal' только перед return из Sp или после каждого запроса :( ?
Если нет, то неужто все так безнадежно?

Строго говоря безнадёжно, потому что "утекание" потока может происходить каждый раз после окончания исполнения каждого батча. В том числе когда батч принудительно прерван - например, при deadlock, при ошибке компиляции и в других ситуациях. Так как доступа к NT потоку, которому был снижен приоритет уже нет (иначе нужно переделывать все приложения, работающие с данным сервером), то наличие проблемы очевидно.

Возвращясь к Вашему исходному вопросу - а в чём суть CPU интенсивного задания, которое нужно запускать с низким приоритетом? Может есть альтернативные решения, которые не кажутся очевидными? Игра с приоритетами кроме нежелательного вмешательства во внутреннюю механику диспетчеризации почти всегда является бесполезной в SQL Server для собственно SQL, так как основной ресурс, за который идёт конкуренция - это обычно блокировки, а не CPU. А тут приоритеты не очень помогут.
Cheers
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Post by Dmitry67 »

tengiz, по поводу приоритетов
Конечно мы благодарны MS за то что она всегда все настраивает автоматически лучше чем DBA :), но тем не менее... Например многие вещи из Sybase я бы украл

Я считаю что было бы крайне неплохо в SQL сделать классы исполнения типа OLAP/OLTP, prio OLTP > OLAP. Сделать так чтобы тупой table scan не 'выбивал' кэш из под других OLTP процессов. Может ввести категории кешей или хотя бы хинт что результат table scan не надо класть в кеш, такое есть в Oracle.

Потому что на самом деле устойчивость MS SQL к "DOS-атакам" (имеются ввиду WEB, когда если не уложился за NN секунд выдается ошибка) практически нулевая

Под DOS-атаками имеются ввиду конечно не зловредные хакеры, а jobs, OLAP, reports итд.
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014

Return to “Вопросы и новости IT”