На прошлой неделе, преподавая курс IEPTO2, я объяснял, почему иногда поток невозможно завершить с помощью команды KILL, и подумал, что это отличная тема для статьи.
Некоторые из вас, вероятно, сталкивались с феноменом под названием неоткликающийся планировщик (non-yielding scheduler). Это происходит, когда поток использует процессор и не уступает его добровольно после исчерпания своего кванта времени (4 миллисекунды, это значение неизменно). В фоновом режиме работает задача — монитор планировщиков, которая проверяет, есть ли прогресс в работе различных планировщиков внутри SQL Server, и выдает предупреждение при обнаружении проблемы. В случае с неоткликающимся планировщиком вы увидите ошибку 17883, как показано ниже:
Process 56:0:0 (0xdee) Worker 0x041611F6 appears to be non-yielding on Scheduler 2.Thread creation time: 13884536031127. Approx Thread CPU Used: kernel 18 ms, user 263 ms.Process Utilization 0%. System Idle 98%. Interval: 331220558 ms.
Причин этому может быть множество, включая проблемы с подсистемой ввода-вывода, медленные вызовы Windows API или ошибки в самом SQL Server.
Если дело в ошибке SQL Server, то причина в том, что поток попадает в участок кода, где может циклически выполняться, не проверяя, истёк ли 4-миллисекундный квант времени (для проверки используется вызов функции SQLOS YieldAndCheckForAbort или одного из её вариантов). Если поток не проверяет, истёк ли квант, он об этом не узнает и не уступит выполнение — так и возникает неоткликающийся планировщик. Ошибка заключается именно в отсутствии вызова YieldAndCheckForAbort.
Первым порывом, скорее всего, будет завершить проблемный SPID командой KILL, но это невозможно. Вернее, команду выполнить можно, однако, вероятно, ничего не произойдёт. Дело в том, что в SQL Server нет способа принудительно завершить поток изнутри. Поток должен самостоятельно проверить, не поступал ли запрос на его завершение, и затем завершиться (а также завершить любые дочерние потоки, если это параллельная операция). И угадайте, где выполняется эта проверка? В функции YieldAndCheckForAbort! Таким образом, если поток никогда не проверяет, он не узнает о запросе и не завершится.
Вот почему иногда, если ситуация с неоткликающимся планировщиком не разрешается сама собой, приходится перезапускать SQL Server.

Комментариев нет:
Отправить комментарий