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

Определение процесса проверки синхронизации

В конечном счете, процесс проверки синхронизации реализуется достаточно просто. Все, что нам нужно сделать – это обеспечить согласованность зафиксированных на разных серверах деталей задания агента SQL Server, таких, как график, разрешения, оповещения, состояния «активировано или деактивировано» и выполняемые команды, ибо в случае аварийного переключения с одного хоста на другой любое рассогласование может обернуться настоящим бедствием. С учетом сказанного в процесс проверки синхронизации следует включить несколько пунктов.

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

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

Подобным же образом мы можем счесть целесообразным по тем или иным причинам иметь возможность воздерживаться от проверок. Это означает игнорировать определенные задания, данные по которым мы просто не хотим синхронизировать, да и вообще не хотим ими заниматься — вне зависимости от того, какова область охвата такого задания или каковы причины, побудившие нас отказаться от проверки.

Чтобы исследовать эти причины, в следующей статье мы создадим две хранимые процедуры — одну для проверки деталей заданий агента SQL Server на уровне сервера, а другую для проверки заданий, относящихся к отдельно взятой группе доступности AlwaysOn. Таким образом, если на наших серверах размещается, скажем, три различных группы доступности, мы в конечном итоге будем иметь задание, которое выполняет четыре вызова хранимых процедур: один для проверок уровня сервера и три различных вызова для каждой из групп доступности.

Обобщенный пример выполнения

Как я показал в одной из предыдущих статей, существует два основных подхода к работе с пакетными заданиями: во-первых, мы можем активировать или деактивировать на данном сервере все задание целиком (в зависимости от того, размещается ли в данный момент главная реплика на этом сервере) и, во-вторых, воспользоваться логикой «if или then», которая откладывает выполнение с использованием хранимой процедуры (во многих случаях именно такой подход будет предпочтительным). Но, как бы то ни было, в данной статье я буду исходить из того, что мы пойдем по первому пути (активация или деактивация), поскольку это более сложный подход к управлению заданиями, и он может понадобиться вам, если в качестве заданий вы выполняете пакеты SSIS и т.д. В соответствии с этим подходом мы будем исходить из следующей предпосылки: наши желания не ограничиваются тем, чтобы регулярные проверки синхронизации инспектировали состояние синхронизации на уровне группы доступности. Наряду с этим мы хотим, чтобы система переключала состояния «активировано или деактивировано», если мы обнаружим, что имело место аварийное переключение. Разумеется, как уже отмечалось выше, в дополнение к этому нам нужно будет принимать во внимание пакетные задания, которые, возможно, были на время деактивированы — и которые должны по-прежнему пребывать в этом состоянии даже в процессе (и по завершении) аварийного переключения.

Давайте предположим в контексте изложенных обстоятельств, что у нас имеется отдельная группа доступности с именем SSV, что мы составили и скоррелировали с этой группой доступности некое пакетное задание, используя для этой цели категорию задания агента SQL Server, также именуемую SSV, и что мы уже составили и заполнили данными соответствующую таблицу состояния заданий. Теперь предположим, что мы выполняем проверки синхронизации каждые три минуты и (раз уж мы придерживаемся подхода, предполагающего подключение или отключение заданий по критерию близости к основной реплике) реализовали логику для активации или деактивации заданий по факту аварийного переключения. Если бы ситуация полностью соответствовала приведенному описанию и весь код выполнялся на SERVER1, проверки проходили бы у нас, скажем, в 10:03, 10:06, 10:09 и т.д. Теперь предположим, что в 10:10 утра SERVER1 дает сбой (причина в данном случае не важна). Следующее допущение: мы выполнили аварийное переключение и возобновили работу к 10:12. В данный момент в соответствии с нашим замыслом код и логика, выполняемые в процессе нашей проверки синхронизации, должны решать на SERVER2 следующие задачи:

  • Зафиксировать факт аварийного переключения, то есть тот факт, что если ранее основная реплика группы доступности SSV размещалась на SERVER1, но теперь основным является SERVER2.
  • Удостовериться, что все задания уровня группы доступности, которые имеют в качестве целевой базу данных SSV и определены в таблице состояния заданий как «активированные» в данный момент активированы на SERVER2. Аналогичным образом теперь мы должны убедиться, что все задания уровня группы доступности, имеющие в качестве целевой базу данных или группу доступности SSV, отключены на наших серверах OTHER (SERVER1) в группе доступности. Для наших целей давайте предположим, что SERVER1 не вернулся в строй до 11:15, поскольку поломка оказалась серьезной.
  • Попытаться выполнять проверки синхронизации содержимого SERVER2 и SERVER1 уровня сервера, уровня резервного копирования и уровня группы доступности для поддержания согласованности всех данных. Понятно, что если в вашу группу доступности входит большее число серверов, их тоже нужно включать в число проверяемых.

Это задача не из легких, и часть процессов, которые, по нашим представлениям, должны были выполняться, просто не могли иметь место — скажем, изменение статуса размещенных на SERVER1 пакетных заданий уровня группы доступности на «деактивировано» или сопоставление деталей заданий на SERVER2 и SERVER1 — исключительно по той простой причине, что SERVER1 вышел из строя и не отвечает на запросы около часа. С другой стороны, наша логика синхронизации должна справиться с задачей активации единственного имеющего отношение к SSV задания на SERVER2, а это значит, что оно в соответствии с замыслом будет запущено на выполнение на своем новом месте. Конечно, если бы пакетное задание SSV выполнялось с высокой частотой, скажем, раз в минуту, тогда на протяжении нескольких минут (в 10:10, 10:11 и даже в 10:12) задание не выполнялось бы, поскольку состоялось аварийное переключение серверов и наша логика переключения состояний еще не включилась в работу, чтобы активировать это задание на SERVER2. В большинстве случаев здесь проблем не возникнет. С технической точки зрения, если вы запускаете пакетное задание примерно раз в минуту, то, скорее всего, делаете это неверно. Если это не так, вы, вероятно, сочтете целесообразным решать проблему по мере необходимости за счет увеличения частоты, с которой запускаются проверки синхронизации.

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