E aĂ, pessoal!
Nesse post eu trago para vocĂªs uma soluĂ§Ă£o simples, mas que eu gostei bastante, porque me ajudou a reduzir bastante o tempo de processamento de um pipeline do Azure Data Factory (ADF) ao alterar o Service Objective e redimensionar um Azure SQL Database utilizando comandos T-SQL antes do inĂcio do processamento, e voltando ao tier original ao final de todo o processamento.
Para alterar o tier do Azure SQL Database, vocĂª pode utilizar a interface do portal Azure, Powershell, Azure CLI, Azure DevOps e mais uma sĂ©rie de alternativas, alĂ©m do nosso querido Transact-SQL (T-SQL), que, na minha visĂ£o, Ă© a escolha mais fĂ¡cil e prĂ¡tica de todas.
Vejam como Ă© fĂ¡cil:
1 2 |
ALTER DATABASE [dirceuresende] MODIFY(SERVICE_OBJECTIVE = 'S3') |
O problema de todas essas soluções, especialmente no cenĂ¡rio que eu estou falando, Ă© que a alteraĂ§Ă£o do Service Objetive, vulgo Service Tier, nĂ£o Ă© feita imediatamente, ou seja, vocĂª executa o comando e o Azure SQL irĂ¡ efetivar a troca do tier no momento que o Azure achar melhor. Pode demorar 1 segundo, 10 segundos, 60 segundos, etc… E quando o tier do Azure SQL Database Ă© alterado, as sessões sĂ£o desconectadas.
No cenĂ¡rio que listei acima, onde altero o tier antes de iniciar o processamento dos dados, se eu simplesmente executar o comando T-SQL e continuar o processamento, no meio dele o Azure irĂ¡ alterar o tier, a conexĂ£o irĂ¡ cair por alguns segundos e o banco ficarĂ¡ indisponĂvel por alguns segundos.
VocĂª tambĂ©m pode utilizar o Retry em todos os componentes do seu pipeline e assim, evitar que isso seja um problema para vocĂª, pois quando a conexĂ£o cair, o retry serĂ¡ ativado e as operações serĂ£o feitas novamente, mas vocĂª teria que configurar o retry em todos os componentes ao invĂ©s de configurar apenas no componente do upsizing, pode ter sido cobrado por movimentaĂ§Ă£o de dados e uso de recursos do prĂ³prio ADF durante esse tempo que processou Ă toa. AlĂ©m disso, podem acontecer efeitos colaterais caso algum componente nĂ£o esteja preparado para ser interrompido no meio da execuĂ§Ă£o e executado novamente.
Outra possĂvel soluĂ§Ă£o Ă© colocar um operador de Wait no Azure Data Factory e especificar um tempo qualquer que vocĂª ache ser suficiente para o Azure alterar o tier. Pelos meus testes, o tempo necessĂ¡rio para o Azure SQL Database efetivar a troca do tier costuma ser algo entre 50 e 90 segundos.
Embora isso possa funcionar em alguns casos (e em outros nĂ£o), essa soluĂ§Ă£o nĂ£o me parece ser muito confiĂ¡vel. Se o tempo de alterar o tier ultrapassar o limite que eu defini, vou ter esperado um bom tempo e ainda vai falhar no meio do processamento. E se a alteraĂ§Ă£o terminar antes, terei esperado um bom tempo sem necessidade.
Procurei algumas soluções para resolver esse meu problema e acabei caindo na ideia do MVP de Data Platform Greg Low nesse post aqui, mas optei por criar a minha procedure visando ter uma soluĂ§Ă£o mais simples para tentar resolver esse problema.
CĂ³digo-fonte da Stored Procedure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
CREATE PROCEDURE dbo.stpAltera_Tier_DB ( @ServiceLevelObjective VARCHAR(50), @TimeoutEmSegundos INT = 60 ) AS BEGIN SET NOCOUNT ON DECLARE @Query NVARCHAR(MAX), @DataHoraLimite DATETIME2 = DATEADD(SECOND, @TimeoutEmSegundos, GETDATE()), @ServiceLevelObjectiveAtual VARCHAR(20) = CONVERT(VARCHAR(100), DATABASEPROPERTYEX( DB_NAME(), 'ServiceObjective' )) IF (@ServiceLevelObjectiveAtual <> @ServiceLevelObjective) BEGIN SET @Query = N'ALTER DATABASE [' + DB_NAME() + '] MODIFY (SERVICE_OBJECTIVE = ''' + @ServiceLevelObjective + ''');' EXEC sp_executesql @Query; WHILE ((DATABASEPROPERTYEX( DB_NAME(), 'ServiceObjective' ) <> @ServiceLevelObjective) AND GETDATE() <= @DataHoraLimite) BEGIN WAITFOR DELAY '00:00:00.500'; END END END |
O uso dessa procedure Ă© bem simples:
1 2 3 |
EXEC dbo.stpAltera_Tier_DB @ServiceLevelObjective = 'S3', @TimeoutEmSegundos = 60 |
ApĂ³s a execuĂ§Ă£o do comando, a procedure vai ficar aguardando atĂ© que a alteraĂ§Ă£o seja efetivada pelo Azure, reavaliando a cada 500 milissegundos se a alteraĂ§Ă£o jĂ¡ foi realizada, respeitando o limite de tempo definido. Caso o limite seja atingido, a procedure irĂ¡ terminar a execuĂ§Ă£o mesmo que a alteraĂ§Ă£o ainda nĂ£o esteja efetivada. Caso a efetivaĂ§Ă£o da alteraĂ§Ă£o seja menor que o tempo limite, a procedure irĂ¡ terminar a execuĂ§Ă£o assim que o tier for alterado, evitando desperdĂcio de tempo.
Para executar essa procedure pelo Azure Data Factory, vamos utilizar o “novo” componente de Script, disponibilizado em 6 de março de 2022:
Como o Azure SQL Database elimina todas as conexões e o banco fica indisponĂvel por uns segundos, mesmo com esse tratamento, a procedure irĂ¡ retornar um erro por causa que a prĂ³pria sessĂ£o dela foi eliminada:
No Azure Data Factory também vai dar erro ao executar essa procedure quando a troca for efetivada:
Para que essa soluĂ§Ă£o dĂª certo, vamos definir um Retry para esse bloco de Script, de modo que quando ele falhar (e vai falhar), ele entre no Retry, espere mais 10 segundos e execute a Procedure de novo.
Na segunda execuĂ§Ă£o da Stored Procedure, como a alteraĂ§Ă£o serĂ¡ pelo mesmo tier da execuĂ§Ă£o anterior, o comando serĂ¡ executado de forma instantĂ¢nea e o Azure vai apenas ignorar o comando e retornar sucesso na execuĂ§Ă£o, conforme demonstro abaixo:
E com isso, agora o seu banco jĂ¡ estĂ¡ com o novo tier e vocĂª pode iniciar o processamento dos dados. Ao final do processamento, eu faço o downscale para voltar o tier para o valor original, mas dessa vez, eu nĂ£o preciso ficar esperando o tĂ©rmino da alteraĂ§Ă£o, pois nĂ£o vou processar mais nada.
Sendo assim, eu posso usar a forma mais bĂ¡sica para voltar ao tier anterior:
Para ser bem sincero com vocĂªs, pensando na simplicidade em primeiro lugar, nem mesmo a Stored Procedure Ă© necessĂ¡ria no final das contas. Como a conexĂ£o Ă© sempre interrompida, posso apenas colocar um IF simples com um WAITFOR DELAY bem longo dentro do bloco do Script e ter o mesmo comportamento:
1 2 3 4 |
ALTER DATABASE [dirceuresende] MODIFY(SERVICE_OBJECTIVE = 'S6') IF (CONVERT(VARCHAR(100), DATABASEPROPERTYEX( DB_NAME(), 'ServiceObjective' )) <> 'S6') WAITFOR DELAY '00:10:00'; |
E assim como utilizando a Stored Procedure, a rotina deu erro na primeira execuĂ§Ă£o, aguardando atĂ© que a alteraĂ§Ă£o do tier seja efetivada no banco. Quando isso ocorre, a conexĂ£o Ă© interrompida e a execuĂ§Ă£o retorna falha.
O Azure Data Factory aguarda 10 segundos (tempo que eu defini) apĂ³s a falha e tenta novamente. Desta vez, a execuĂ§Ă£o Ă© bem rĂ¡pida, uma vez que o tier jĂ¡ foi alterado para o tier escolhido. Essa segunda execuĂ§Ă£o retorna sucesso e o ciclo do pipeline segue normalmente.
O comportamento acabou sendo igual ao da Procedure, mas muito mais simples. Coloquei um wait bem longo (10 minutos), que vai acabar sendo o limite de tempo que o Azure terĂ¡ para efetuar a mudança, o que Ă© bem mais que o suficiente. Acabando a alteraĂ§Ă£o antes, o ciclo jĂ¡ continua sem precisar esperar esses 10 minutos.
Acabou que a soluĂ§Ă£o ficou ainda mais simples do que eu pensava. Agora vocĂªs podem aumentar o tier do seu Azure SQL Database antes de iniciar o processamento do ETL usando o Azure Data Factory, para que o processamento seja mais rĂ¡pido, e ao final do processamento, vocĂª volta ao tier original, pagando a mais somente durante o tempo em que ficou processando dados. Uma forma inteligente de ter uma performance bem superior pagando muito menos đŸ™‚
Espero que vocĂªs tenham gostado dessa dica e atĂ© a prĂ³xima.