Estou procurando as melhores práticas para lidar com trabalhos agendados do SQL Server Agent em grupos de disponibilidade do SQL Server 2012. Talvez eu tenha perdido alguma coisa, mas no estado atual sinto que o SQL Server Agent não está realmente integrado a esse ótimo recurso do SQL2012.
Como posso tornar um trabalho de agente SQL agendado ciente de uma alternância de nó? Por exemplo, eu tenho um trabalho em execução no nó primário que carrega dados a cada hora. Agora, se o primário ficar inativo, como posso ativar o trabalho no secundário que agora se torna primário?
Se eu agendar o trabalho sempre no secundário, ele falha porque o secundário é somente leitura.
Em seu trabalho do SQL Server Agent, tenha alguma lógica condicional para testar se a instância atual está atendendo à função específica que você está procurando em seu grupo de disponibilidade:
Tudo o que isso faz é puxar a função atual da réplica local e, se estiver na
PRIMARY
função, você pode fazer o que seu trabalho precisa fazer se for a réplica primária. OELSE
bloco é opcional, mas é para lidar com a lógica possível se sua réplica local não for primária.Obviamente, altere
'YourAvailabilityGroupName'
a consulta acima para o nome real do seu grupo de disponibilidade.Não confunda grupos de disponibilidade com instâncias de cluster de failover. O fato de a instância ser a réplica primária ou secundária de um determinado grupo de disponibilidade não afeta os objetos no nível do servidor, como trabalhos do SQL Server Agent e assim por diante.
Em vez de fazer isso por trabalho (verificando cada trabalho quanto ao estado do servidor antes de decidir continuar), criei um trabalho em execução nos dois servidores para verificar em que estado o servidor está.
Esta abordagem fornece uma série de coisas
o script verifica o banco de dados no campo abaixo
Este proc é executado a cada 15 minutos em cada servidor. (tem o bônus adicional de anexar um comentário para informar às pessoas por que o trabalho foi desativado)
Não é infalível, mas para cargas noturnas e trabalhos por hora, ele faz o trabalho.
Ainda melhor do que ter esse procedimento executado em um agendamento, execute-o em resposta ao Alerta 1480 (alerta de alteração de função AG).
Estou ciente de dois conceitos para conseguir isso.
Pré-requisito: Com base na resposta de Thomas Stringer, criei duas funções no banco de dados mestre de nossos dois servidores:
Fazer um trabalho terminar se não for executado na réplica primária
Para este caso, cada trabalho em ambos os servidores precisa de um dos dois trechos de código a seguir como Etapa 1:
Verifique pelo nome do grupo:
Verifique pelo nome do banco de dados:
Se você usar este segundo, tenha cuidado com os bancos de dados do sistema - por definição, eles não podem fazer parte de nenhum grupo de disponibilidade, portanto, sempre falhará para eles.
Ambos funcionam fora da caixa para usuários administradores. Para usuários não administradores, você deve adicionar permissões extras, uma delas sugerida aqui :
Se você definir a ação de falha para Sair do relatório de trabalho com sucesso nesta primeira etapa, você não obterá o registro de trabalho cheio de sinais de cruz vermelhos feios, para o trabalho principal eles se transformarão em sinais de aviso amarelos.
De nossa experiência, isso não é o ideal. A princípio, adotamos essa abordagem, mas rapidamente perdemos a noção de encontrar trabalhos que realmente tinham um problema, porque todos os trabalhos de réplica secundárias enchiam o log de trabalhos com mensagens de aviso.
O que nós fomos então é:
Trabalhos de proxy
Se você adotar esse conceito, na verdade precisará criar dois trabalhos por tarefa que deseja executar. O primeiro é o "trabalho de proxy" que verifica se está sendo executado na réplica primária. Em caso afirmativo, ele inicia o "trabalho de trabalho", caso contrário, ele termina normalmente sem sobrecarregar o log com mensagens de aviso ou de erro.
Embora eu pessoalmente não goste da ideia de ter dois trabalhos por tarefa em cada servidor, acho que é definitivamente mais sustentável e você não precisa definir a ação de falha da etapa para Quit job reporting success , o que é um pouco desajeitado.
Para os trabalhos, adotamos um esquema de nomenclatura. O trabalho de proxy é apenas chamado
{put jobname here}
. O trabalho do trabalhador é chamado{put jobname here} worker
. Isso possibilita automatizar o início do trabalho do trabalhador a partir do proxy. Para fazer isso, adicionei o seguinte procedimento a ambos os dbs mestres:Isso utiliza a
svf_AgReplicaState
função mostrada acima, você pode facilmente alterar isso para verificar usando o nome do banco de dados chamando a outra função.De dentro da única etapa do trabalho de proxy, você o chama assim:
Isso utiliza Tokens conforme mostrado aqui e aqui para obter o id do trabalho atual. O procedimento então obtém o nome do trabalho atual do msdb, anexa
worker
a ele e inicia o trabalho do trabalhador usandosp_start_job
.Embora isso ainda não seja o ideal, mantém os logs de trabalho mais organizados e fáceis de manter do que a opção anterior. Além disso, você sempre pode executar o trabalho de proxy com um usuário sysadmin, portanto, não é necessário adicionar permissões extras.
Se o processo de carregamento de dados for uma consulta simples ou chamada de procedimento, você poderá criar o trabalho em ambos os nós e deixá-lo determinar se é o nó primário com base na propriedade Updateability do banco de dados, antes de executar o processo de carregamento de dados:
Outra forma é inserir um passo em cada job, que deve ser executado primeiro, com o seguinte código:
Defina esta etapa para continuar com a próxima etapa em caso de sucesso e para encerrar o trabalho relatando sucesso em caso de falha.
I find it cleaner to add an extra step instead of adding extra logic to an existing step.
It is always better to create a new Job Step which checks if it is a Primary Replica then everything is fine to continue with the job execution else if it is a Secondary Replica then Stop the job. Do not fail the job else it will keep sending unnecessary notifications. Instead stop the job so that it is cancelled and no notifications are sent out whenever these jobs are executed on the Secondary Replica.
Below is the script to add a first step for a specific job.
Note to execute the script:
If there are multiple Availability Groups, then set the AG name in the variable @AGNameToCheck_IfMoreThanSingleAG as to which AG should be checked for its replica state.
Also note that this script should work well even on those servers which do not have availability groups. Will execute only for SQL Server versions 2012 and beyond.
Another, newer option, is using master.sys.fn_hadr_is_primary_replica('DbName'). I have found this super helpful when using SQL Agent to do database maintenance (coupled with a cursor I've used for years) and also when executing an ETL or other database specific task. The benefit is that it singles out the database instead of looking at the whole Availability Group...if that's what you need. It also makes it much more improbable that a command will be executed against a database that "was" on the primary, but let's say an automatic failover happened during the job execution, and it is now on a secondary replica. The above methods that look at the primary replica take one look and don't update. Keep in mind, this is just a different way to achieve very similar results and give more granular control, if you need it. Also, the reason this method wasn't discussed when this question was asked is because Microsoft didn't release this function until after SQL 2014 was released. Below are some samples of how this function can be used:
Se você quiser usar isso para manutenção do banco de dados do usuário, é isso que eu uso:
Espero que seja uma dica útil!
Eu uso isso: