Начнем с небольшого резюме: в предыдущих статьях мы описали три различных типа заданий (или операций) агента SQL Server Agent, которые необходимо выполнять при использовании групп доступности SQL Server AlwaysOn.

  • Задания уровня серверов или экземпляров. Это задания, выполняемые применительно к самому серверу, при решении таких задач, как усечение истории заданий SQL Server Agent, обслуживание индексов или проверки на целостность (обычно выполняемые во всех активных базах данных сервера) и т.д.
  • Задания уровня групп доступности. Это задания, касающиеся исключительно тех баз данных, которые входят в состав той или иной группы доступности — иными словами, задания, которые я в рамках настоящей серии именую «пакетными заданиями».
  • Операции по резервному копированию. В некоторых отношениях они напоминают задания уровня серверов или экземпляров. Но в чем-то они отличаются от последних, ибо операции резервного копирования отчасти подобны заданиям, относящимся к базам данных уровня AG.

В этой статье будут рассмотрены, прежде всего, задания уровня AG, пакетные задания, а также имеющиеся в нашем распоряжении варианты их выполнения.

Выполнение пакетных заданий

Если ставить вопрос в самом общем виде, то администратор, планирующий выполнение пакетных заданий в условиях использования групп доступности, может выбрать один из нескольких подходов.

Один из них состоит в том, чтобы просто ничего не делать — иначе говоря, не рассматривать возможные варианты, ничего не планировать и не готовиться к тому, что может произойти в случае сбоя. Так вот, хотя выдвигать такую стратегию в качестве варианта было бы с моей стороны просто смешно, реальность такова, что, по моим наблюдениям, кто-то, возможно, уже идет этим путем. Возможно, и нет — поскольку для развертывания групп доступности требуется чуть более высокая квалификация, чем для реализации топологий зеркального дублирования. Но мне доподлинно известно, что во многих организациях зеркальное дублирование баз данных используется как средство обеспечения высокой доступности, и местные специалисты практически повсеместно не делают ничего для страховки своих заданий в случаях, если эти задания будут при сбое переключены на вспомогательный сервер (ничего не предпринимается до тех пор, пока не станет слишком поздно, или до того, как аварийное переключение произойдет несколько раз).

Но не будем принимать в расчет этот абсолютно неприемлемый подход. У нас остается два варианта выполнения заданий SQL Server Agent применительно к базам данных, входящим в состав группы доступности.

— Таргетирование. Согласно этой логике — или в соответствии с данным подходом к реализации пакетных заданий — основная идея состоит в следующем. Если мы сумеем каким-то образом известить каждое задание о том, что в данном случае оно выполняется применительно к активной реплике, наша задача будет практически решена. Иными словами, требуется привнести некоторую логику в начало каждого задания SQL Server Agent (или в каждый шаг задания). А логика такая: если данный фрагмент кода выполняется сейчас на хосте, являющемся владельцем основной реплики для целевой базы данных или группы доступности, тогда пусть код выполняется, а если нет, тогда идем в обход — и процедура выполнения прерывается. Если бы такое «оповещение» было возможно, организация управления заданиями, размещенными на разных серверах, была бы делом совсем не сложным. Нужно было бы просто модифицировать существующие задания таким образом, чтобы в начале их выполнения осуществлялась проверка выполнения условия (if), а затем проследить за тем, чтобы данный код или данная логика синхронизировались или реплицировались по всем серверам (и чтобы синхронизация не нарушалась в ходе последующих изменений и модификаций заданий, графиков и т.д.).

— Динамическое подключение или отключение. Если привнесение в существующие задания логики таргетирования (или проверок на выполнение условия) невозможно, тогда, как ни прискорбно, нам придется обратиться к другому подходу: организовать динамическое подключение или отключение заданий в зависимости от того, размещены ли они на одном сервере и не являются ли активной репликой целевой базы данных. В этом смысле можно использовать логическую конструкцию или фрагмент кода, для того чтобы обеспечить отключение заданий, размещенных на серверах, которые не содержат основную реплику, — реализовать такую логику достаточно просто. С другой стороны, в соответствии с тем же принципом мы не можем исходить из того, что все задания, предусматривающие манипулирование входящей в состав группы доступности базой данных, которая установлена на сервере, содержащем основную реплику, должны быть активированы. Такой подход не сработает в ситуациях, когда то или иное задание было ранее отключено явным образом и должно по определению быть отключено на новом хосте, если произойдет аварийное переключение. Следовательно, единственный реальный путь обеспечения динамического подключения или отключения заданий предполагает формирование таблицы состояний или какого-либо другого механизма фиксации, определения и применения состояний подключения или отключения заданий (что осложняет дело и приводит, образно говоря, к появлению в вашем решении еще одной «подвижной детали», а мы всегда исходим из того, что чем проще решение, тем лучше).

Если учесть непроизводительные затраты на организацию управления состояниями заданий «Подключено» или «Отключено», становится вполне очевидным, что предпочтение следует отдать подходу, построенному на принципе таргетирования. Однако, к сожалению, реализация этого подхода (о чем свидетельствует и мой опыт, и мое понимание перспективы) связана с куда более серьезными трудностями из-за определенных обстоятельств, ограничивающих возможности системы SQL Server. Поэтому решение, на котором я в конце концов остановился, базируется на принципе активации или деактивации заданий. В следующих статьях цикла я подробно расскажу о некоторых «подводных камнях» и о причинах, объясняющих, почему таргетирование не работает.

Синхронизация в основе всего

В дополнение к сказанному стоит отметить важное обстоятельство: необходимость синхронизации деталей заданий не подлежит сомнению. Без выполнения этой процедуры все изменения, внесенные в детали заданий (такие, как планирование, состояния активации или деактивации, владельцы, шаги заданий и т.д.) фиксируются только на одном сервере (как правило, это основной сервер) и не реплицируются в соответствующем коде на других серверах. И тогда в случае аварийного сбоя задания не будут выполняться в соответствии с нашим замыслом (если вообще будут выполняться). А это значит, что мы окажемся практически в той же точке, откуда стартовали. Иначе говоря, мы будем пребывать в том же состоянии, как если бы не предприняли никаких действий по организации выполнения заданий после того, как в сетях появились группы доступности. Поэтому, закончив изложение причин, объясняющих, почему таргетирование не работает, в следующих статьях цикла я перейду к описанию механизмов и деталей осуществления синхронизации.