Você está na página 1de 571

BRINCARAlternar lista suspensaResumir

Capítulo 1: Apresentando os conceitos


básicos do Azure
Com todas as formalidades iniciais agora para trás, vamos começar nossa jornada
no Azure. Nossa jornada começa aqui: https://azure.microsoft.com.
O Azure é um dos provedores de plataforma de nuvem mais importantes do
mercado atualmente. Ele fornece vários serviços de nuvem, híbridos e locais,
como VMs, redes, computação, bancos de dados, mensagens, aprendizado de
máquina (ML), inteligência artificial, Internet das Coisas (IoT) e muitos outros
serviços, enquanto se concentra em segurança e conformidade. Você pode usar
esses serviços para criar qualquer coisa, de páginas da Web a aplicativos móveis,
de soluções de análise de dados a soluções de IoT e muito mais.
No Azure, os usuários têm a flexibilidade de escolher entre soluções sem código
completamente hospedadas para criar completamente suas próprias soluções
usando os blocos de construção básicos, como VMs e VNets, onde os usuários
têm controle total sobre cada aspecto do sistema. E a maioria dessas tecnologias
vem preparada com as vantagens da nuvem, como replicação geográfica, alta
disponibilidade, redundância de dados, escalabilidade e elasticidade.
Vamos revisar rapidamente os conceitos básicos do Azure. As seções a seguir se
concentrarão em aprimorar os fundamentos do Azure. Se você já tem um
conhecimento prático do Azure e sabe como criar recursos no Azure, então você
pode ignorar este capítulo com segurança e ir diretamente para o próximo.
Neste primeiro capítulo, forneceremos uma visão geral do Azure, incluindo a
introdução de alguns serviços comuns do Azure. Teremos uma boa base no
básico, como contas, máquinas virtuais (VMs), armazenamento, computação e
rede. Também explicaremos como criar serviços usando o portal do Azure e a CLI.
Neste capítulo, abordaremos os seguintes tópicos:

 Apresentando o portal do Azure


 Explorando contas, assinaturas e grupos de recursos do Azure
 Apresentando os serviços do Azure
 Explorando VMs do Azure
 Explorando o armazenamento do Azure
 Explorando a rede do Azure (VNet)
 Explorando a computação do Azure

Vamos começar!

Requisitos técnicos
Para acompanhar este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)


 A CLI do Azure instalada em sua estação de trabalho
Apresentando o portal do Azure
O portal do Azure é a página inicial para todos os desenvolvedores do Azure.
Você pode pensar nisso como uma página de índice que contém links para todos
os serviços fornecidos pelo Azure. A captura de tela a seguir mostra a aparência
do portal do Azure:

Figura 1.1 – A home page do portal do Azure


Você pode navegar por todos os serviços disponíveis no Azure ou pesquisá-los
rapidamente usando a caixa de pesquisa. Depois de clicar em um serviço, a
página da Web do serviço correspondente será exibida (também conhecida como
lâminas no Azure). O Azure mantém uma forte consistência em termos de design
de lâmina. Todas as lâminas de serviço serão muito semelhantes. Então, se você
está familiarizado com um, você deve ser capaz de navegar facilmente os outros.
Exploraremos algumas das lâminas de serviço neste capítulo.

Explorando contas, assinaturas e grupos


de recursos do Azure
Você pode explorar o Azure com ou sem uma conta. Se você estiver apenas
explorando o Azure e estiver planejando executar alguns experimentos de
Sandbox, não será necessário criar uma conta do Azure. Mas se você está
planejando investir mais tempo no Azure, é recomendável criar uma conta. O
Azure fornece US$ 200 em créditos gratuitos nos primeiros 30 dias para você
jogar. Este USD 200 deve dar-lhe uma quilometragem bastante boa para os
exercícios práticos para esta certificação. Você pode se inscrever para uma conta
gratuita aqui: https://azure.microsoft.com/free.
Nota
O Azure requer um número de cartão de crédito válido para criar a conta, mas não
cobra o cartão de crédito por contas gratuitas. Quando o crédito de USD 200
estiver esgotado, ele irá notificá-lo e, em seguida, excluir os recursos.
Vamos começar com as contas do Azure.
Conta do Azure
Uma conta do Azure refere-se à conta de Cobrança do Azure. Ele é mapeado
para a ID de email que você usou para se inscrever no Azure. Uma conta pode
conter várias assinaturas; Cada uma dessas assinaturas pode ter vários grupos de
recursos e os grupos de recursos, por sua vez, podem ter vários recursos. A
cobrança é feita no nível de assinaturas. Assim, uma conta pode ter várias faturas
geradas por assinatura.
Em seguida, vamos examinar a assinatura do Azure.
Assinatura do Azure
Cada recurso (VMs, redes virtuais, bancos de dados e assim por diante) que você
cria no Azure está vinculado a uma assinatura. Uma assinatura é um contêiner
para todos os recursos criados para aplicativos e soluções sob essa assinatura.
Uma assinatura contém os detalhes de todas as VMs, redes, armazenamento e
outros serviços que foram usados durante esse mês que serão usados para fins
de cobrança. O Azure cria uma assinatura padrão quando você cria uma conta.
Mas você pode optar por ter várias assinaturas com base em suas equipes
(desenvolvimento, teste, vendas, marketing, finanças e assim por diante), regiões
(América do Norte, EMEA, Ásia-Pacífico e assim por diante) ou outras divisões
lógicas que considere apropriadas para seu caso de uso.
Em seguida, vejamos os Grupos de recursos.
Grupos de recursos
Grupos de recursos são grupos lógicos de recursos pertencentes a um aplicativo
ou a uma equipe. Você pode pensá-los como marcas associadas aos recursos
para que você possa consultar, monitorar e gerenciar facilmente a coleção de
recursos como um só. Por exemplo, você pode criar um grupo de recursos
chamado Sandbox para as sessões de prática do Azure. No final do dia, você
pode excluir todos os recursos que foram criados nesse grupo de recursos de uma
só vez, em vez de passar por todos os recursos e excluí-los. Você pode ter vários
grupos de recursos em uma Assinatura.
Recursos
Recursos referem-se a todas as VMs, armazenamentos, bancos de dados,
funções e assim por diante que podem ser criados no Azure.
Antes de passarmos para o próximo tópico, vamos criar um exemplo de caso de
uso de uma empresa imaginária. Usaremos essa empresa imaginária como um
caso de uso do mundo real em todos os capítulos e tentaremos construir nossas
soluções de dados para isso.
Estabelecendo um caso de uso
Vamos fingir que existe uma empresa chamada Imaginary Airport Cabs (IAC). A
IAC quer construir um portal de reservas de táxis. Eles têm uma equipe de
engenharia e uma equipe de marketing que precisa que os aplicativos sejam
hospedados no Azure. A equipe de engenharia está planejando criar um servidor
Web escalonável com um back-end SQL do Azure. O frontend e o back-end são
segregados usando duas redes virtuais diferentes por motivos de isolamento e
segurança. A equipe de marketing, por outro lado, tem um requisito mais simples
de apenas um banco de dados SQL do Azure para armazenar suas informações
de clientes.
Se plotarmos esse requisito em relação às contas, assinaturas, grupos de
recursos e recursos, ele poderá ter a seguinte aparência:

Figura 1.2 – Relação entre contas, assinaturas, grupos de recursos e recursos


Voltaremos ao IAC e usaremos o Azure para resolver suas necessidades de TI ao
longo deste livro. Resolveremos casos de uso mais complicados para o IAC nos
capítulos a seguir para que você possa entender os conceitos do Azure com
exemplos reais para seu exame de certificação. O Azure oferece uma variedade
de serviços que podem ser úteis para o IAC. Veremos alguns deles na seção a
seguir.

Apresentando os Serviços do Azure


O Azure fornece uma ampla gama de serviços e tecnologias que podem atender
facilmente à maioria dos casos de uso do mundo real. Os serviços fornecidos pelo
Azure podem ser categorizados assim.
Infraestrutura como serviço (IaaS)
Na IaaS, você obtém a infraestrutura básica, como VMs, VNets e armazenamento,
e precisa criar o restante da pilha de aplicativos por conta própria. Essa opção
oferece a maior flexibilidade para os desenvolvedores em termos de versões do
sistema operacional, versões de biblioteca, patches personalizados e assim por
diante.
Plataforma como serviço (PaaS)
No PaaS, as plataformas de software são pré-instaladas e pré-configuradas.
Esses são serviços gerenciados no sentido de que o Azure gerencia o ciclo de
vida desse software para você. Os exemplos incluem o Azure SQL Server, o
Azure Databricks e o Serviço de Kubernetes do Azure. Você ainda será capaz de
ajustar o software para algum nível, mas você pode não ter a flexibilidade de
escolher versões específicas, patches e assim por diante.
Software como Serviço (SaaS), também
conhecido como Função como Serviço (FaaS)
O que outras plataformas chamam de Software como Serviço (SaaS), o Azure
se refere como Função como Serviço (FaaS). Em SaaS ou FaaS, você não
consegue ver nenhum dos detalhes de instalação do software. Você geralmente
tem uma interface de usuário semelhante a um notebook ou uma interface de API
para enviar diretamente seus trabalhos; O provedor de serviços de nuvem se
encarrega de instanciar o serviço, dimensionar o serviço e executar os trabalhos
para você. Esta é a maneira mais fácil e rápida de começar, mas a mais restritiva
em termos de configuração de software. Os exemplos incluem o Azure Functions,
o Azure Synapse, o SQL Serverless e assim por diante.
Para aqueles de vocês que não estão muito familiarizados com os serviços IaaS,
PaaS e SaaS, aqui está um diagrama que explica esses conceitos:

Figura 1.3 – Detalhamento dos serviços do Azure


Vamos examinar a seguir as VMs do Azure.

Explorando VMs do Azure


Máquinas virtuais (VMs) são abstrações de software do hardware físico. Eles
podem emular o hardware do computador para os aplicativos em execução nele.
Podemos ter várias VMs em execução em uma única máquina. Cada VM terá uma
parte da CPU, memória e armazenamento da máquina host alocada a ela.
As VMs do Azure são os recursos mais comuns que são girados no Azure. Você
pode usar VMs para configurar praticamente qualquer aplicativo desejado. Eles
são como servidores simples de baunilha que podem ser usados para instalar
qualquer software que você precisa, exceto as atualizações do sistema
operacional e os patches de segurança, que são cuidados pelo Azure. As VMs do
Azure oferecem a vantagem de implantações mais rápidas, escalabilidade,
isolamento de segurança e elasticidade. O Azure fornece VMs do Windows e do
Linux. Há uma enorme coleção de tipos e versões do sistema operacional
disponíveis no Azure Marketplace que podem ser usadas para girar as VMs. Aqui
estão alguns dos tipos de VM disponíveis no momento em que escrevo este livro.
Você pode procurar informações mais atualizadas em
https://docs.microsoft.com/en-us/azure/virtual-machines/sizes:

 Uso geral
 Otimizado para computação
 Memória otimizada
 Armazenamento otimizado
 GPU
 Alto desempenho

Nas subseções a seguir, explicaremos o processo de criação de uma VM.


Criando uma VM usando o portal do Azure
Primeiro, vamos aprender a criar uma máquina virtual usando o portal do Azure e,
em seguida, usando a CLI. A seguir está uma captura de tela da página Criar uma
máquina virtual:
Figura 1.4 – Criando VMs usando o portal do Azure
Aqui estão as etapas para criar a VM usando o portal:

1. No portal, escolha Máquinas Virtuais (usando a barra de pesquisa ou o


Explorer).
2. Clique no sinal de + Criar e selecione Máquinas Virtuais.
3. Insira um nome de máquina virtual, selecione um grupo de recursos,
selecione uma imagem de VM, selecione a propriedade Tamanho da VM e
um tipo de autenticação.
4. Clique em Revisar + Criar e, em seguida, em Enviar.
5. Você deve ver um pop-up com a opção Baixar chave privada e criar
recurso. Clique no botão Download e salve a chave privada em um local
seguro. Você precisará dessa chave para fazer login em sua VM.
6. Você também pode configurar opções avançadas, como Discos, Rede,
Gerenciamento e Tags, conforme mostrado na captura de tela anterior.

Agora, vamos aprender a criar uma VM usando a CLI do Azure.


Criando uma VM usando a CLI do Azure
Como esta é a primeira vez que estamos usando a CLI, aprenderemos como
começar.
Instalando a CLI
Há duas maneiras de usar a CLI. Primeiro, você pode usar a opção CLI do Azure
diretamente do portal do Azure, conforme mostrado aqui:

Figura 1.5 – Usando a CLI diretamente do portal do Azure


Como alternativa, você pode optar por instalar o cliente da CLI do Azure em sua
máquina local e executar os comandos a partir daí. Você pode aprender a baixar e
instalar o cliente da CLI do Azure aqui:
https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows.
Agora, vamos ver um exemplo de criação de uma VM usando a CLI do Azure.
Nota:
Todos esses comandos e scripts estão disponíveis no link do GitHub que é
fornecido junto com este livro, para que você possa facilmente copiar e tentar os
comandos.
Para criar uma VM usando a CLI, teremos que seguir uma sequência de etapas.
Para este exemplo, vamos criar uma VM do Ubuntu:
1. Primeiro, temos que encontrar todas as imagens do Ubuntu que estão
disponíveis usando a opção:vm image list

az vm image list --all --offer Ubuntu

2. Em seguida, precisamos encontrar as regiões do Azure onde queremos


implantar. Podemos usar para isso. Você pode escolher a região mais
próxima de você:account list-locations

az account list-locations --output table

3. Depois de fazer isso, podemos criar um novo grupo de recursos ou usar um


existente para associar essa VM. Vamos criar um novo grupo de recursos
chamado usando a opção, como mostrado aqui:IACRGgroup create

az group create --name 'IACRG' --location 'eastus'

4. Finalmente, vamos criar uma VM usando as informações dos comandos


anteriores. Neste exemplo, escolhi o local para implantar essa VM. Todos
os campos não obrigatórios terão como padrão os valores padrão do
Azure:eastus

az vm create --resource-group 'IACRG' --name 'sampleVM' --image 'UbuntuLTS' --admin-


username '<your username>' --admin-password '<your password>' --location 'eastus'

O comando anterior criará uma VM nomeada sob o grupo de recursos chamado .


sampleVMIACRG
Isso deve ter lhe dado uma boa ideia de como a CLI funciona no Azure. Você
pode saber mais sobre VMs do Azure aqui:
https://azure.microsoft.com/en-in/services/virtual-machines/.
Em seguida, vamos conferir as opções de armazenamento disponíveis no Azure.

Explorando o Armazenamento do Azure


O Azure tem várias opções de armazenamento que podem se adequar a uma
ampla variedade de aplicativos e domínios. Vamos explorar os mais comuns aqui.
Armazenamento de Blobs do Azure
O armazenamento de blobs é o tipo de armazenamento mais comum no Azure.
Ele pode ser usado para armazenar dados não estruturados, como vídeos, áudio,
metadados, arquivos de log, texto e binários. É uma solução de armazenamento
altamente dimensionável e muito econômica. Ele fornece suporte para
armazenamento hierárquico, para que os dados possam ser armazenados em
diferentes níveis com base em seu padrão de acesso e frequência de uso. Os
dados altamente utilizados podem ser mantidos em camadas quentes, os dados
não tão usados em camadas frias e os dados históricos podem ser arquivados. Os
dados no armazenamento de Blobs podem ser facilmente acessados por meio de
pontos de extremidade REST, bem como bibliotecas de cliente disponíveis em um
amplo conjunto de linguagens, como .NET, Java, Python, Ruby, PHP, Node.js e
muito mais.
Armazenamento de Blobs
Você pode acessar seu Armazenamento de Blobs em https://<storage-
account>.blob.core.windows.net.
A captura de tela a seguir mostra a criação de uma conta de armazenamento do
portal do Azure:

Figura 1.6 – Criando uma conta de armazenamento usando o portal do Azure


Vá em frente e crie uma conta de armazenamento agora, se você ainda não tiver
uma. Você precisará dessa conta de armazenamento ao longo deste livro para
armazenar todos os dados de exemplo, scripts e muito mais.
Agora, vamos examinar outra opção de armazenamento importante fornecida pelo
Azure que será usada extensivamente para data lakes: Azure Data Lake Gen2.
Azure Data Lake Gen 2 
O Azure Data Lake Gen2 ou Azure Data Lake Storage Gen 2 (ADLS Gen2) é um
superconjunto de armazenamento de Blobs otimizado para análise de big data. O
ADLS Gen2 é a opção preferencial para soluções de data lake no Azure. Ele
fornece suporte a namespace hierárquico sobre o armazenamento de Blobs. O
suporte a namespace hierárquico significa apenas que os diretórios são
suportados. Ao contrário do armazenamento de Blobs, que fornece operações de
pseudodiretório por meio de namespaces, o ADLS Gen2 fornece suporte real para
diretórios com conformidade POSIX e suporte à Lista de Controle de Acesso
(ACL). Isso torna operações como renomear e excluir diretórios atômicas e
rápidas. Por exemplo, se você tiver 100 arquivos em um diretório no
armazenamento de Blobs, renomear esse diretório exigiria centenas de operações
de metadados. Mas, no ADLS Gen2, apenas uma operação de metadados
precisará ser executada no nível do diretório. O ADLS Gen2 também oferece
suporte a RBACs (controles de acesso baseados em função), assim como o
armazenamento de Blobs.
Outra característica importante do ADL Gen2 é que ele é um sistema de
arquivos compatível com Hadoop. Portanto, criar qualquer pipeline de análise
de código aberto em cima do ADL Gen2 é muito fácil.
Já que estamos falando da ADL Gen2, você pode estar curioso para saber o que
aconteceu com a ADL Gen1.
O ADL Gen1, como o próprio nome sugere, foi a primeira geração de
armazenamento data lake altamente escalável e de alto desempenho que foi
criado para análise de dados. Ele ainda está disponível, mas será preterido em
fevereiro de 2024. O ADLS Gen1 é otimizado para arquivos grandes, por isso
funciona melhor para arquivos de 256 MB ou mais. Os recursos do Gen1 estão
disponíveis no Gen2 agora. O Gen2 também tem algumas vantagens adicionais,
como melhor disponibilidade regional, o que significa que ele está disponível em
todas as regiões do Azure, em comparação com algumas regiões selecionadas
onde o Gen1 está disponível. O Gen2 também oferece suporte a LRS (Locally
Redundant Storage, armazenamento com redundância local), ZRD (Zone
Redundant Storage, armazenamento redundante de zona) e GRS (Geo
Redundant Storage, armazenamento com redundância e recuperação de
dados), enquanto o Gen1 oferece suporte apenas a LRS.
ADLS Gen2
Você pode acessar o ADLS Gen2 em https://<storage-
account>.dfs.core.windows.net.
Para criar uma conta do ADLS Gen2, você precisa marcar a caixa de seleção
Habilitar namespace hierárquico na tela Criar uma conta de armazenamento:
Figura 1.7 – Selecionando o Data Lake Storage Gen2 (Habilitar namespace
hierárquico) ao criar uma instância de Armazenamento do Azure
Em seguida, vamos aprender sobre outra tecnologia de armazenamento do Azure
chamada Arquivos do Azure.
Arquivos do Azure
Os Arquivos do Azure fornecem compartilhamentos de arquivos remotos que
podem ser montados usando protocolos SMB (Server Message Block) ou NFS
(Network File Share). Essas são ótimas opções de armazenamento para quem
planeja migrar cargas de trabalho locais para a nuvem com um modelo lift and
shift, por exemplo, sem precisar investir em redesenvolvimento para o modelo
baseado em nuvem. Os arquivos do Azure podem ser facilmente montados tanto
de servidores em nuvem quanto de servidores locais. Os Arquivos do Azure são
particularmente úteis para casos que precisam de dados compartilhados,
configurações compartilhadas, aplicativos compartilhados e muito mais em vários
usuários, equipes ou regiões. Vejamos alguns comandos de exemplo sobre como
criar compartilhamentos de arquivos no Azure.
Criando compartilhamentos de arquivos do Azure com a CLI do Azure
Como já vimos alguns exemplos anteriores de uso do portal do Azure, vamos
explorar este usando a CLI do Azure para que nos familiarizemos com as opções
de linha de comando também. Continuaremos a usar o exemplo IAC aqui para que
você tenha uma boa compreensão de como usar a CLI com exemplos reais. Você
pode simplesmente examinar esses exemplos para ter uma ideia de como os
comandos do Arquivo do Azure são estruturados.
Para os exemplos a seguir, precisaremos que um grupo de recursos e uma conta
de armazenamento sejam criados. Podemos reutilizar o grupo de recursos , que
criamos na seção "Criando uma VM usando CLI". Para a conta de
armazenamento, podemos facilmente criar uma, como mostrado aqui.IACRG
az storage account create --resource-group IACRG --name iacstorage --location eastus --kind StorageV2
--sku Standard_LRS.
Isso criará uma conta de armazenamento chamada . Os nomes das contas de
armazenamento precisam ser exclusivos, portanto, talvez seja necessário
encontrar um nome que ainda não esteja sendo usado. Depois de criarmos a
conta de armazenamento, você poderá visitar a página da conta de
armazenamento no portal do Azure. Na guia Chaves de Acesso, você pode
copiar a Chave Primária (Chave1), que será necessária para executar qualquer
atividade nessa conta de armazenamento. Depois de copiadas, exporte as duas
variáveis a seguir da tela da CLI, conforme mostrado:iacstorage
export AZURE_STORAGE_ACCOUNT=<your storage account name> export
AZURE_STORAGE_KEY=<your storage primary key>
Se você estiver usando uma máquina Windows, consulte o link GitHub deste livro
para encontrar exemplos de exportação de variáveis no Windows.
Nota:
Usar a chave primária é uma maneira fácil de acessar o armazenamento, mas não
é uma opção recomendada para uso em sistemas de produção. O livro discutirá
opções mais seguras mais adiante nos capítulos.
Vamos começar:

1. Você pode criar um novo compartilhamento de arquivos do Azure para IAC


usando a opção. O comando a seguir criará um compartilhamento de
arquivos nomeado sob o .share-rm createiacfileshareiacstorage

az storage share-rm create --resource-group IACRG --storage-account iacstorage --name


iacfileshare

2. Você pode listar os compartilhamentos de arquivos usando a opção:share


list

az storage share list --account-name iacstorage

3. Você pode colocar um arquivo em nosso compartilhamento de arquivos


usando a opção:file upload

az storage file upload --share-name iacfileshare --source ./testfile.txt

4. Você pode exibir os arquivos em seu compartilhamento de arquivos usando


:file list

az storage file list --share-name iacfileshare

5. Finalmente, você pode baixar o arquivo que carregamos anteriormente


usando a opção:file download

az storage file download --share-name iacfileshare -p testfile.txt --dest ./testfile.txt

Como você pode ver, o Azure fornece um conjunto muito fácil e intuitivo de
comandos para interface com os vários serviços do Azure disponíveis.
Vamos examinar a seguir as Filas do Azure.
Filas do Azure
As filas do Azure são usadas para armazenar um grande número de mensagens
que podem ser acessadas de forma assíncrona entre a origem e o destino. Isso
ajuda no desacoplamento de aplicativos para que eles possam ser dimensionados
de forma independente. As filas do Azure podem ser usadas em aplicativos que
estão sendo executados na nuvem, no local, em dispositivos móveis e muito mais.
Há dois tipos de filas: filas de armazenamento e Barramento de Serviço.
As filas de armazenamento podem ser usadas para processamento de
mensagens assíncrono simples. Eles podem armazenar até 500 TB de dados (por
conta de armazenamento) e cada mensagem pode ter até 64 KB de tamanho. Se
seu aplicativo precisa de mais do que uma simples fila assíncrona e precisa de
recursos avançados, como modelos pub-sub, ordenação estrita de mensagens e
APIs de bloqueio e não bloqueio, o Service Bus é uma opção melhor. Com o
Service Bus, os tamanhos das mensagens podem ser de até 1 MB, mas o
tamanho geral é limitado a 80 GB.
Filas do Azure
URL das filas do Azure: .https://<storage
account>.queue.core.windows.net/<queue>
Agora, vamos ver alguns comandos de exemplo para criar filas no Azure.
Criando filas do Azure usando a CLI
Vejamos alguns exemplos de comandos da CLI para criar e usar uma Fila do
Azure. Novamente, assumiremos que as variáveis e ambiente já foram
definidas:AZURE_STORAGE_ACCOUNTAZURE_STORAGE_KEY

1. Você pode criar uma nova fila do Azure usando o comando. O comando a
seguir criará uma fila nomeada sob o .storage queue
createiacqueueiacstorage

az storage queue create --name iacqueue --account-name iacstorage

2. Você pode listar facilmente as filas em uma conta de armazenamento


usando o termo:storage queue list

az storage queue list --account-name iacstorage

3. Você pode adicionar uma nova mensagem à fila recém-criada usando a


opção:storage message put

az storage message put --queue-name iacqueue --content "test"

4. Finalmente, use o comando para exibir a mensagem. Este comando


recupera uma ou mais mensagens da frente da fila, mas não altera a
visibilidade da mensagem:storage message peek

az storage message peek --queue-name iacqueue


Agora que você entende os conceitos básicos das filas do Azure, vamos examinar
as tabelas do Azure.
Tabelas do Azure
As tabelas do Azure são armazenamentos de chave-valor fornecidos pelo Azure.
Eles são bons para armazenar dados estruturados não relacionais. Há duas
soluções disponíveis no Azure para repositórios de tabelas: Armazenamento de
Tabela do Azure e Cosmos DB.
Ambos os recursos fornecem o mesmo modelo de tabela e recursos Criar, Ler,
Atualizar e Excluir (CRUD), mas a diferença está em sua escala, SLAs e
disponibilidade. O Cosmos DB é a versão premium do Repositório de tabelas e
pode fornecer mais de 10 milhões de operações por segundo, enquanto o
armazenamento de tabelas do Azure tem um limite de dimensionamento de 20 mil
operações por segundo.
O Cosmos DB também oferece várias vantagens adicionais, como cinco níveis
flexíveis de consistência, até 99,999% de disponibilidade de leitura em bancos de
dados de várias regiões, modo sem servidor, presença global e muito mais. O
CosmosDB merece um capítulo completo por si só. Exploraremos o CosmosDB
com mais detalhes mais adiante neste livro.
Tabela do Azure
URL da tabela do Azure: .http://<storage
account>.table.core.windows.net/<table>
Como as outras opções de armazenamento que analisamos, vamos ver alguns
exemplos de comandos da CLI para se familiarizar com essa tecnologia. Você
pode apenas dar uma olhada nesses exemplos por enquanto. Forneceremos
etapas detalhadas para implementar os exemplos necessários para a certificação
mais adiante neste livro.
Criando tabelas do Azure usando a CLI
Vamos aprender a usar a CLI do Azure para criar e usar uma Tabela do Azure:

1. Podemos criar uma nova Tabela do Azure para nossa empresa de


exemplo, IAC, usando a opção. O comando a seguir criará uma tabela
nomeada sob a conta de armazenamento. Aqui, novamente, teremos que
exportar as duas variáveis env ( e ), antes de executar os seguintes
comandos..storage table
createiactableiacstorageAZURE_STORAGE_ACCOUNTAZURE_STORAGE_KE
Y

az storage table create --name iactable --account-name iacstorage

2. Podemos facilmente listar as tabelas em uma conta de armazenamento


usando a opção:storage table list

az storage table list --account-name iacstorage

3. Podemos inserir uma entidade na Tabela recém-criada usando a


opção:storage entity insert
az storage entity insert --table-name iactable --entity PartitionKey=testPartKey
RowKey=testRowKey Content=testContent

4. Finalmente, podemos usar o comando para visualizar a entrada:storage


entity show

az storage entity show --table-name iactable --partition-key testPartKey --row-key testRowKey

Com isso, abordamos as principais opções de armazenamento fornecidas pelo


Azure. Em seguida, examinaremos os Discos Gerenciados do Azure, que são
necessários para gerenciar o armazenamento em disco/SSD para VMs.
Discos gerenciados do Azure
Os discos gerenciados do Azure são os discos rígidos virtuais montados em
uma VM do Azure. Como o nome sugere, esses discos são completamente
gerenciados pelo Azure. Assim, você não precisa se preocupar com atualizações
do sistema operacional, patches de segurança e assim por diante. Ao contrário
dos discos físicos, os Managed Disks do Azure oferecem 99,999% de
disponibilidade. Eles alcançam uma pontuação de disponibilidade tão alta
armazenando três réplicas diferentes dos dados em servidores diferentes. As VMs
gerenciadas também podem ser alocadas a conjuntos de disponibilidade e zonas
de disponibilidade (distribuídas entre racks e data centers) para aumentar sua
capacidade de sobrevivência em casos de paralisação de servidor, rack (carimbo)
ou data center. Os discos gerenciados também fornecem opções para criptografia
de dados em repouso e criptografias em nível de disco. Existem diferentes tipos
de discos gerenciados disponíveis, como HDD padrão, SSD padrão, SSD
premium e discos ultra.
Criando e anexando discos gerenciados a uma VM usando a CLI
Vamos aprender a usar a CLI para criar e anexar Managed Disks ao , que criamos
anteriormente:sampleVM
az vm disk attach --resource-group IACRG --vm-name sampleVM --name IACmgdisk --size-gb 64 –
new
Este é um comando simples de uma linha para criar um novo disco e anexá-lo a
uma VM existente. Lembre-se de que você também tem a opção de especificar
parâmetros de configuração mais avançados como parte do próprio comando da
CLI que, quando não especificado, assumiria valores padrão.
Você pode saber mais sobre as tecnologias de armazenamento do Azure aqui:
https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction.
Agora, vamos explorar outra tecnologia principal do Azure, conhecida como Rede
do Azure.

Explorando a rede do Azure (VNet)


Como as VMs do Azure, a Rede Virtual do Azure é outro componente principal do
Azure que devemos estar cientes. Uma rede virtual vincula todos os recursos,
como VMs, armazenamentos e bancos de dados, de forma segura em uma rede
privada. Ele é usado para encapsular a nuvem ou os serviços locais juntos dentro
de um limite seguro, controlando quem pode acessar esses serviços e de quais
pontos de extremidade.
A Rede do Azure fornece os quatro serviços principais a seguir:

 Conectividade segura nos recursos do Azure usando a rede virtual básica,


o emparelhamento de rede virtual e os pontos de extremidade de serviço.
 Rede além da Nuvem do Azure e na Internet e nuvens híbridas usando
Roteadores Express, Pontos de Extremidade Privados e VPNs Ponto a Site
e Site a Site.
 Filtragem de rede ou, em outras palavras, Regras de Firewall que podem
ser implementadas por meio dos Grupos de Segurança de Rede ou de
Aplicativos. Há opções para implementar o mesmo usando dispositivos de
rede, que são servidores prontos disponíveis para cenários de rede
especializados.
 Capacidades de roteamento de rede que permitem configurar rotas de rede
usando Tabelas de Rotas e Protocolos de Gateway de Borda.

Agora, vamos aprender como criar uma rede virtual usando a CLI do Azure.
Criando uma rede virtual do Azure usando a CLI
Vejamos um exemplo simples de como criar uma rede virtual e atribuir uma VM a
ela. Vamos reutilizar o grupo de recursos do IACRG que usamos nos exemplos
anteriores deste capítulo:

1. Primeiro, precisamos criar uma VNET especificando os intervalos de IP e


prefixos de sub-rede necessários. O comando a seguir cria uma VNET
nomeada no grupo de recursos.iacvnetIACRG

az network vnet create --address-prefixes 10.20.0.0/16 --name iacvnet --resource-group IACRG


--subnet-name iacsubnet --subnet-prefixes 10.20.0.0/24

2. Então, precisamos criar um IP público para que possamos acessar nossa


VM da internet:

az network public-ip create --resource-group IACRG --name iacpubip --allocation-method


dynamic

3. Em seguida, devemos criar uma placa de interface de rede (NIC), que será
a interface de rede entre a VM e o mundo exterior, com a rede virtual e IP
público previamente criados:

az network nic create --resource-group IACRG --vnet-name iacvnet --subnet iacsubnet --name
iacnic --public-ip-address iacpubip

4. Agora temos todos os componentes necessários para criar uma VM em


nossa nova rede virtual, . Podemos reutilizar a imagem que usamos no
exemplo de criação de máquina virtual anterior para criar uma nova VM
dentro da nova VNet:iacvnetUbuntuLTS
az vm create --resource-group IACRG --name sampleVMwithinVNET --nics iacnic --image
UbuntuLTS --generate-ssh-keys

Esperamos que isso tenha lhe dado uma boa compreensão de como criar
componentes de rede, como VNets, IPs públicos e muito mais.
Você pode saber mais sobre a rede do Azure aqui: https://azure.microsoft.com/en-
in/product-categories/networking/.
Em seguida, veremos a Computação do Azure.

Explorando a computação do Azure


Computação do Azure é um termo genérico para todas as tecnologias focadas
em computação no Azure. Vamos explorar alguns dos Serviços de Computação
comuns fornecidos pelo Azure. Cada uma dessas tecnologias é digna de um livro,
então vamos nos concentrar apenas em introduzir essas tecnologias neste
capítulo. Vamos nos aprofundar em algumas das tecnologias que são necessárias
para a certificação mais adiante neste livro.
Conjuntos de dimensionamento de VM
Os Conjuntos de Dimensionamento de VM são uma coleção de VMs com
balanceamento de carga que podem ser usadas para criar serviços altamente
escalonáveis. Por exemplo, podemos ter um conjunto de servidores web que
podem ser dimensionados horizontalmente com base na carga. A vantagem de
usar Conjuntos de Dimensionamento de VM em vez de configurar manualmente
VMs é que os Conjuntos de Dimensionamento de VM podem ser iniciados e
gerenciados usando modelos centralizados. Ele vem com um balanceador de
carga por padrão, então não precisamos configurá-lo manualmente. Ele também
cuida do dimensionamento automático e dimensionamento com base na carga.
Além disso, os conjuntos de dimensionamento de VM têm maior confiabilidade,
pois a carga de trabalho é distribuída por vários servidores. Mesmo que alguns
nós falhem, os Conjuntos de Dimensionamento de VM podem abrir rapidamente
nós adicionais para substituir a capacidade. Os Conjuntos de Dimensionamento
de VM podem ser configurados em zonas de disponibilidade para melhorar ainda
mais a disponibilidade.
Você pode saber mais sobre Conjuntos de Dimensionamento de VM aqui:
https://azure.microsoft.com/en-in/services/virtual-machine-scale-sets/.
Serviço de Aplicativo do Azure
O Serviço de Aplicativo do Azure permite que você desenvolva e hospede
aplicativos Web, aplicativos móveis e APIs usando uma ampla seleção de
linguagens, como .NET, Java, Node.js, Python, ASP.NET e muito mais. Esses são
serviços totalmente gerenciados que fornecem suporte para todo o ciclo de vida
de aplicativos, como desenvolvimento, CI/CD, versões, manutenção, depuração e
dimensionamento. O Serviço de Aplicativo do Azure é apoiado por segurança e
conformidade de nível empresarial. Há exemplos, tutoriais e suporte muito
detalhados disponíveis no Azure para criar soluções móveis e Web completas
usando o Serviço de Aplicativo do Azure.
Você pode saber mais sobre o Serviço de Aplicativo do Azure aqui:
https://azure.microsoft.com/en-in/services/app-service/.
Serviço de Kubernetes do Azure
Kubernetes é um software de orquestração de contêineres de código aberto. O
Serviço de Kubernetes do Azure (AKS) é uma versão PaaS do Kubernetes
hospedada no Azure. O AKS fornece um gerenciamento completo do ciclo de vida
de aplicativos em contêineres, desde o desenvolvimento (usando Visual Studio,
código e outras ferramentas Kubernetes), até CI/CD (integração com o GitHub),
implantação, dimensionamento, telemetria, registro, monitoramento e muito mais.
O AKS também suporta imagens do Docker, que são amplamente utilizadas para
conteinerização.
Você pode saber mais sobre AKS aqui:
https://azure.microsoft.com/en-in/services/kubernetes-service/.
Azure Functions
O Azure Functions é um exemplo perfeito de uma tecnologia sem servidor e é
um SaaS. Sem servidor não significa que não há servidores, significa apenas que
você não precisa implantar, manter ou atualizar seus servidores (VMs); outra
pessoa está fazendo isso por você em segundo plano e abstraindo os detalhes de
você. Você pode usar funções para escrever sua lógica de processamento com
base em gatilhos de eventos e associações, como uma transação em um banco
de dados, um evento IoT e uma chamada REST. Os blocos de código que você
escreve são chamados de funções (sem pontos para adivinhar isso). Tudo o que
você precisa fazer é abrir a Interface do Bloco de Anotações do Azure Functions e
escrever sua lógica (código) diretamente nela. Há extensões de função
disponíveis em várias linguagens que oferecem suporte à integração com
ferramentas de desenvolvimento, CI/CD e DevOps.
Você pode saber mais sobre o Azure Functions aqui:
https://azure.microsoft.com/en-in/services/functions/.
Azure Service Fabric
O Service Fabric é uma tecnologia de cluster muito poderosa que cuida da
implantação, dimensionamento, atualizações e manutenção de aplicativos
baseados em microsserviços. Ele pode cuidar de todo o processo de
gerenciamento do ciclo de vida dos aplicativos. Isso é semelhante ao AKS, mas
para aplicações não conteinerizadas. Muitos dos principais serviços do Azure são
executados sobre o Service Fabric. O Service Fabric é um projeto de código
aberto e tem confiabilidade e disponibilidade muito altas.
O Lote do Azure é usado para executar grandes aplicativos de processamento
paralelo ou aplicativos de computação de alto desempenho. O Batch fornece o
suporte necessário para gerenciamento de recursos, agendamento e
dimensionamento para executar qualquer programa MPP tradicional. Ele gira as
VMs e implanta e executa seus programas de maneira paralela. Ele pode escalar
dinamicamente para cima e para baixo, conforme necessário, para otimizar o
custo. O Lote do Azure pode ser usado para processamento em lote de alto
volume, modelagem financeira, renderização de vídeo, geração de modelo de
previsão do tempo e assim por diante.
Você pode saber mais sobre o Lote do Azure aqui: https://azure.microsoft.com/en-
in/services/batch/.
Resumo
Com isso, concluímos nosso primeiro capítulo. Se foi muito esmagador para você,
não se preocupe – este capítulo foi feito apenas para fornecer uma visão geral do
Azure. Quando você concluir os próximos capítulos, sua confiança aumentará. Por
outro lado, se este capítulo foi fácil para você, então você provavelmente já está
ciente de algum nível de tecnologias de nuvem, e o próximo conjunto de capítulos
também deve ser fácil para você.
Agora que você concluiu este capítulo, você deve saber como navegar no portal
do Azure. Agora você entende a relação entre contas do Azure, assinaturas,
grupos de recursos e recursos. Você também sabe como criar novas VMs,
instâncias de armazenamento, redes virtuais e assim por diante usando o portal
do Azure e a CLI. Você também está ciente dos principais serviços de computação
que estão disponíveis no Azure. Com esse conhecimento fundamental, podemos
avançar para tópicos mais interessantes e voltados para a certificação.
Exploraremos as tecnologias de armazenamento do Azure no próximo capítulo.

Capítulo 2: Projetando uma estrutura de


armazenamento de dados
Bem-vindo ao Capítulo 2. Vamos nos concentrar nas tecnologias de
armazenamento de dados do Azure neste capítulo. O Azure fornece várias
tecnologias de armazenamento que podem atender a uma ampla variedade de
casos de uso híbridos e de nuvem. Algumas das tecnologias de armazenamento
importantes do Azure incluem: Blobs, Arquivos, Filas, Tabelas, Banco de Dados
SQL, Cosmos DB, Synapse SQL Warehouse e Azure Data Lake
Storage (ADLS). O Azure agrupa as quatro tecnologias de armazenamento
fundamentais, a saber: — Blobs, Arquivos, Filas e Tabelas — como
Armazenamento do Azure. Outros serviços avançados, como Cosmos DB, Banco
de Dados SQL, ADLS e assim por diante, são fornecidos como serviços
independentes do Azure.

A partir deste capítulo, seguiremos a sequência exata do conteúdo


programático do DP-203.

Neste capítulo, nos concentraremos principalmente nos aspectos de projeto das


estruturas de armazenamento. Os detalhes de implementação correspondentes
serão abordados nos capítulos posteriores.
Este capítulo abordará os seguintes tópicos:

 Criando um data lake do Azure

 Selecionando os tipos de arquivo corretos para armazenamento

 Escolhendo os tipos de arquivo certos para consultas analíticas

 Projetando o armazenamento para consultas eficientes

 Projetando armazenamento para remoção de dados

 Projetando estruturas de pastas para transformação de dados

 Desenhando uma estratégia de distribuição

 Projetando uma solução de arquivamento de dados

Vamos começar.

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 A interface de linha de comando do Azure (CLI do Azure) instalada em sua


estação de trabalho. Consulte a seção Criando uma VM usando a CLI do
Azure no Capítulo 1, Apresentando as Noções Básicas do Azure para obter
instruções sobre como instalar a CLI do Azure.

Criando um data lake do Azure


Se você tem acompanhado o domínio das tecnologias de big data, com certeza já
se deparou com o termo data lake. Data lakes são armazenamentos de dados
distribuídos que podem armazenar grandes volumes de dados diversos. Eles
podem ser usados para armazenar diferentes tipos de dados, como dados
estruturados, semiestruturados, não estruturados, streaming e assim por diante.
Uma solução de data lake geralmente compreende uma camada de
armazenamento, uma camada de computação e uma camada de serviço. As
camadas de computação podem incluir Extract, Transform,
Load (ETL); Batelada; ou Processamento de fluxo. Não há modelos fixos para
criar data lakes. Cada data lake pode ser exclusivo e otimizado de acordo com os
requisitos da organização proprietária. No entanto, há poucas diretrizes gerais
disponíveis para construir data lakes eficazes, e vamos aprender sobre eles neste
capítulo.

Qual é a diferença entre um data lake e um data


warehouse?
A principal diferença entre um data lake e um data warehouse é que um data
warehouse armazena dados estruturados, enquanto um data lake pode ser usado
para armazenar diferentes formatos e tipos de dados. Os data lakes são
geralmente as zonas de aterrissagem para diferentes fontes e tipos de dados.
Esses dados brutos são processados e os eventuais dados curados são
carregados em armazenamentos de dados estruturados, como data warehouses.
O outro principal fator diferenciador é a escala. Os data lakes podem armazenar
facilmente dados no intervalo de Petabytes (PB), Exabytes (EB) ou até superior,
enquanto os data warehouses podem começar a engasgar no intervalo PB.

Quando você deve usar um data lake?


Podemos considerar o uso de data lakes para os seguintes cenários:

 Se você tiver dados muito grandes para serem armazenados em sistemas de


armazenamento estruturados, como data warehouses ou bancos de dados
SQL

 Quando você tem dados brutos que precisam ser armazenados para
processamento posterior, como um sistema de ETL ou um sistema de
processamento em lote
 Armazenamento de dados contínuos, como dados da Internet das
Coisas (IoT), dados de sensores, tweets e assim por diante para cenários de
streaming de baixa latência e alta taxa de transferência
 Como a zona de preparo antes de carregar os dados processados em um
banco de dados SQL ou data warehouse

 Armazenamento de vídeos, áudios, arquivos de blob binários, arquivos de


log e outros dados semiestruturados, como arquivos JSON (JavaScript
Object Notation), XML (Extensible Markup Language) ou YAML Ain't
Markup Language (YAML) para armazenamento de curto ou longo prazo.
 Armazenamento de dados processados para tarefas avançadas, como
consultas ad hoc, aprendizado de máquina (ML), exploração de dados e
assim por diante.

Em seguida, veremos as diferentes zonas ou regiões em um data lake.

Zonas de data lake


Um data lake pode ser amplamente segregado em três zonas onde ocorrem
diferentes estágios do processamento, descritos a seguir:

1. Landing Zone ou Raw Zone: é onde os dados brutos são ingeridos de


diferentes fontes de entrada.
2. Zona de transformação: é onde acontece o processamento em lote ou fluxo.
Os dados brutos são convertidos em um formato mais estruturado e
amigável ao business intelligence (BI).
3. Zona de Serviço: é onde os dados selecionados que podem ser usados para
gerar insights e relatórios são armazenados e servidos para ferramentas de
BI. Os dados nessa zona geralmente aderem a esquemas bem definidos.

Ponta

Nas zonas de aterrissagem, os dados são acumulados de várias fontes de


entrada. Se a origem for uma entrada de streaming ou uma entrada de IoT, os
arquivos tendem a ser menores. Um grande número de arquivos pequenos é
conhecido por causar problemas de desempenho com data lakes. Por
exemplo, o ADLS Gen2 recomenda tamanhos de arquivo de
256 Megabytes (MB) a 100 Gigabytes (GB) para um desempenho ideal. Se
houver muitos arquivos pequenos, recomenda-se mesclá-los em arquivos
maiores.

Vamos agora explorar alguns modelos de data lake padrão.

Arquitetura de data lake


A imagem a seguir mostra uma arquitetura de data lake para processamento em
lote e em fluxo. O diagrama também inclui exemplos das tecnologias do Azure que
podem ser usadas para cada uma das zonas do data lake. Os nomes dos serviços
listados pelos ícones são apresentados na imagem após isso:

Figura 2.1 – Arquitetura de data lake usando serviços do Azure

Aqui estão os nomes dos serviços representados pelos ícones no diagrama


anterior:
Figura 2.2 – Legendas de ícones

Vamos aprender mais sobre essas tecnologias ao longo deste livro. Em seguida,
vamos examinar o processamento em lote.

Processamento em lote

Em uma estrutura de processamento em lote, os dados geralmente pousam na


Landing Zone (ou Raw Zone) de várias fontes de entrada. Uma vez que os dados
chegam à Landing Zone, a estrutura de orquestração aciona os pipelines de
processamento de dados. Os pipelines geralmente têm vários estágios que
levarão os dados por vários estágios de processamento, como limpeza de dados,
filtragem, agregação dos dados de várias tabelas e arquivos e, finalmente,
geração de dados curados para BI e exploração. As etapas do pipeline podem ser
executadas em paralelo ou de forma sequencial. O Azure fornece um serviço
chamado Data Factory que pode ser usado para criar esses pipelines. O Azure
Data Factory (ADF) é uma ferramenta muito versátil que também fornece a
capacidade de ingerir dados de várias fontes e executar atividades simples de
processamento de dados, como junções, filtragem e assim por diante.

O processamento em lote pode ser usado para trabalhos de ETL, trabalhos de


preparação de dados, geração de relatórios periódicos e muito mais. Do ponto de
vista da certificação, você deve estar ciente das tecnologias do Azure que podem
ser usadas para criar os componentes em lote de um data lake. A tabela a seguir
lista algumas das tecnologias do Azure comumente usadas para criar pipelines de
processamento em lote:
Figura 2.3 – Tecnologias do Azure disponíveis para criar um sistema de
processamento em lote

Vamos aprender a seguir sobre o processamento de fluxo.

Processamento de fluxo ou processamento em tempo real

O processamento de fluxo refere-se ao processamento de dados quase em tempo


real. Ao contrário do processamento em lote, que processa dados em repouso, o
processamento de fluxo lida com dados como e quando eles chegam. Como tal,
esses sistemas precisam ser sistemas de baixa latência e alta taxa de
transferência.

Por exemplo, considere nosso exemplo de Táxis de Aeroporto


Imaginários (IAC) que usamos no Capítulo 1, Noções básicas do Azure.
Podemos querer realizar o aumento de preços com base em uma demanda por
táxis, então o sistema precisa processar solicitações de táxis provenientes de uma
determinada área geográfica quase em tempo real. Esses dados podem então ser
agregados e usados para decidir o preço dinâmico.
Geralmente, em cenários de processamento de fluxo, os dados chegam em
pequenos arquivos em rápida sucessão. Nós nos referimos a esses pequenos
arquivos de dados como mensagens. O sistema de streaming geralmente faz
algumas verificações rápidas para o formato correto dos dados, processa os
dados e grava os dados em um armazenamento. Portanto, precisamos garantir
que os armazenamentos usados para processamento em tempo real ofereçam
suporte a gravações de alto volume com baixa latência.

A tabela a seguir lista algumas das tecnologias do Azure que podem ser usadas
para criar um pipeline de processamento de fluxo para um data lake:

Figura 2.4 – Tecnologias do Azure disponíveis para criar um sistema de


processamento de fluxo

Vamos aprender a seguir sobre duas das arquiteturas comuns usadas em data
lakes.

Arquitetura Lambda

Uma das deficiências dos sistemas de processamento em lote é o tempo que eles
levam para processar os dados. Normalmente, um pipeline em lote que processa
dados de um dia ou um mês pode ser executado por várias horas — ou às vezes
até dias — para gerar os resultados. Para superar essa falha, podemos usar uma
arquitetura híbrida chamada arquitetura Lambda que usa uma combinação de
pipelines rápidos e lentos. O caminho lento processa um volume maior de dados e
produz resultados precisos, mas leva mais tempo. O caminho rápido, por outro
lado, funciona em um conjunto de dados muito menor (geralmente dados
amostrados) e fornece um resultado aproximado muito mais rápido. O caminho
rápido também poderia usar diferentes tecnologias, como tecnologias de
streaming, para acelerar o processamento. Ambos os pipelines alimentam uma
camada de serviço que atualiza as atualizações incrementais do caminho rápido
para os dados da linha de base do caminho lento. Qualquer cliente de análise ou
ferramenta de relatório pode acessar os dados selecionados da camada de
serviço.

Você pode ver uma visão geral da arquitetura do Lambda no diagrama a seguir:

Figura 2.5 – Arquitetura do Lambda

Este modelo Lambda nos ajudará a tomar decisões informadas mais rapidamente,
em comparação com modelos somente em lote.

Arquitetura Kappa

O Kappa é uma arquitetura alternativa à arquitetura Lambda e se concentra


apenas no caminho rápido ou no caminho de streaming. Ele é construído com
base no pressuposto de que os dados em consideração podem ser representados
como um fluxo de dados imutável e que tais fluxos podem ser armazenados por
longos períodos de tempo em uma solução de armazenamento de dados com o
mesmo formato de streaming. Se precisarmos recalcular alguns dados históricos,
os dados de entrada correspondentes do armazenamento de dados podem ser
reproduzidos através da mesma camada de Streaming para recalcular os
resultados.

A principal vantagem da arquitetura Kappa é a complexidade reduzida, em


comparação com a arquitetura Lambda, onde implementamos dois pipelines.
Assim, evita-se o duplo processamento dos mesmos dados, como acontece na
arquitetura Lambda.

Na arquitetura Kappa, o componente de entrada é uma fila de mensagens, como


uma fila do Apache Kafka ou dos Hubs de Eventos do Azure, e todo o
processamento geralmente é feito por meio do Azure Stream Analytics,
do Spark ou do Apache Storm.

Você pode ver uma visão geral da arquitetura Kappa no diagrama a seguir:

Figura 2.6 – Arquitetura Kappa

A arquitetura Kappa pode ser usada para aplicativos como ML em tempo real e
aplicativos em que os dados de linha de base não mudam com muita frequência.

Explorando as tecnologias do Azure que podem


ser usadas para criar um data lake
Agora que entendemos algumas das maneiras recomendadas de criar um data
lake, vamos explorar as tecnologias do Azure que podem ser usadas para criar
data lakes.
Armazenamento de Blobs ou ADLS Gen2

O componente mais importante de um data lake é o componente de


armazenamento. Escolher o armazenamento certo pode ser a diferença entre o
sucesso ou o fracasso de um data lake. O Azure fornece uma tecnologia de
armazenamento especializada para criar data lakes, chamada ADLS Gen2. O
ADLS Gen2 geralmente é uma boa opção para a maioria dos requisitos de
armazenamento de data lake, mas também podemos optar por usar o
armazenamento de Blob regular para o data lake se nossos requisitos forem
principalmente para apenas armazenar dados não estruturados e se não
precisarmos de listas de controle de acesso (ACLs) nos arquivos e pastas. As
ACLs fornecem controle sobre quais usuários têm permissões de leitura, gravação
ou execução nos arquivos e pastas.

Azure Data Factory (ADF)

Uma vez que tenhamos a loja decidida, precisamos de uma maneira de mover
automaticamente os dados. Essa funcionalidade é cumprida pelo ADF. ADF é uma
ferramenta muito poderosa que pode ser usada para o seguinte:

 Ingestão de dados de uma ampla variedade de entradas,


como Armazenamento do Azure, Amazon Redshift, Google BigQuery, SAP
HANA, Sybase, Teradata, HTTP (HyperText Transfer Protocol)
genérico, FTP (File Transfer Protocol) e assim por diante
 Transformações de dados simples, como junções, agregações, filtragem e
limpeza

 Agendamento de pipelines para mover os dados de um estágio para outro

Componentes de computação e processamento de dados

Agora que descobrimos onde armazenar os dados, como obtê-los e como movê-


los, precisamos decidir como processar os dados para análises avançadas.
Isso pode ser alcançado usando uma variedade de tecnologias disponíveis no
Azure. Alguns deles estão listados aqui:
 Azure Synapse Analytics para seus pools SQL e Spark
 Azure Databricks for Spark
 Azure HDInsight para Hive, Spark e outras tecnologias de software de
software livre (OSS)
 Azure Stream Analytics para requisitos de streaming

Você deve estar se perguntando: por que o Azure tem tantas opções para o
Spark? Bem, o Spark vem ganhando muita força ultimamente como uma das
ferramentas analíticas mais populares para engenheiros de dados. O Spark
fornece algo para todos os desenvolvedores, seja processamento em lote,
streaming, ML, notebooks interativos e assim por diante, e o Spark facilita muito a
alternância entre os diferentes casos de uso, fornecendo interfaces de codificação
muito consistentes. Uma vez que você sabe como escrever um programa em lote,
escrever um programa de streaming é muito semelhante, com uma curva de
aprendizado muito rasa. É essa facilidade de uso e suporte para uma ampla
variedade de ferramentas analíticas que fazem do Spark a escolha preferida para
a última geração de engenheiros de dados. O Azure entende essa tendência e
fornece várias opções do Spark. Ele fornece a versão do Azure Databricks para
clientes que adoram os recursos do Databricks Spark. Ele fornece o HDInsight
Spark para clientes que preferem tecnologias OSS e também fornece o Synapse
Spark, que é uma versão aprimorada de desempenho do OSS Spark para os
clientes que preferem uma experiência integrada de painel único no Azure
Synapse Analytics.

Vamos explorar um pouco mais essas tecnologias de computação.

Azure Synapse Analytics

O Azure Synapse Analytics é o serviço de análise premium no qual o Azure está


investindo bastante. Quando ouvimos o Azure Synapse Analytics, geralmente
pensamos nele como um data warehouse SQL, mas, na realidade, o Synapse
Analytics é um conjunto completo de serviços analíticos integrados. O Synapse
Analytics integrou suporte para vários repositórios do Azure, tecnologias de
computação como SQL Data Warehouse e Synapse Spark, mecanismos de
orquestração como ADF, armazenamentos especializados como Cosmos DB,
serviços de gerenciamento de acesso e identidade (IAM) baseados em nuvem
como Azure Active Directory (Azure AD), suporte à governança
de dados via Azure Purview e muito mais.

O Azure Synapse Analytics também funciona como o repositório de análise para a


camada de Serviço, pois tem um armazenamento do SQL Warehouse altamente
escalonável em seu núcleo. Isso pode ser usado para armazenar os dados
processados que são reduzidos em tamanho para serem usados para consultas
analíticas, insights de dados, relatórios e assim por diante.

Azure Databricks

O Azure Databricks é a versão Databricks do Spark hospedada no Azure. O Azure


Databricks fornece uma experiência de Bloco de Anotações muito rica em
recursos e está bem conectado com os outros serviços do Azure, incluindo
Armazenamento, ADF, Power BI, Autenticação e outros recursos do Azure.
Podemos usar o Azure Databricks para escrever código ou scripts do Spark para
fazer o processamento de dados para nós. Por exemplo, podemos usar o Azure
Databricks Spark para limpar os dados de entrada, condensá-los por meio de
filtragem, agregação ou amostragem e adicionar uma estrutura aos dados para
que eles possam ser usados para análise por sistemas semelhantes a SQL.

Azure HDInsight

O Azure também fornece uma opção para usar versões de código aberto do


Apache Spark, Apache Hive, Apache HBase e muito mais por meio do
produto HDInsight. Semelhante ao Azure Databricks, podemos usar a versão de
código aberto do Spark ou do Hive para realizar o processamento de dados
para nosso data lake. A versão HDInsight do Spark usa Notebooks Jupyter. Este é
um dos Notebooks de código aberto comumente usados. A Hive, por outro lado,
tem sido a tecnologia de processamento de dados preferida até que a Spark
assumiu os holofotes. O Hive ainda é um dos serviços mais amplamente
implantados em plataformas de big data corporativas.

Azure Stream Analytics

O processamento de fluxo refere-se ao processamento rápido de dados à medida


que eles chegam. Portanto, precisamos de tecnologias que forneçam alta taxa de
transferência e recursos de processamento quase em tempo real. O Azure fornece
opções proprietárias e de software livre para esses requisitos de processamento
de fluxo. A tecnologia de streaming nativa do Azure é chamada de Azure Stream
Analytics (ASA). O ASA funciona nativamente com todos os serviços de
Armazenamento do Azure e pode se conectar diretamente a ferramentas de
relatório, como o Power BI, sem um armazenamento de dados intermediário. Mas,
se você preferir usar um serviço de código aberto para streaming, podemos usar
serviços como Apache Kafka e Apache Storm, disponíveis via HDInsight.

Relatórios e Power BI

Agora que conhecemos os componentes que podem ser usados para transformar
dados brutos do armazenamento de data lake em formulários mais organizados,
precisamos decidir como apresentar esses dados. A etapa final na análise de
dados é apresentar os dados de uma maneira que gere insights de negócios ou
gere relatórios para indicar o estado do negócio. Em ambos os casos, precisamos
de ferramentas como o Power BI para exibir relatórios interativos. O Power BI é
uma coleção de ferramentas que podem operar em big data e fornecer insights
visuais sobre os dados. O Power BI tem conectividade interna com o Azure para
se integrar perfeitamente a serviços como Cosmos DB, Synapse Analytics,
Armazenamento do Azure e muito mais.

Azure ML

O Azure também fornece alguns serviços avançados, como o Azure ML para


análises e previsões avançadas. O ML geralmente é a próxima etapa na
progressão de um pipeline de análise. Depois de começar a gerar insights a partir
dos dados, o próximo passo é prever tendências futuras. O Azure ML fornece
suporte para uma ampla variedade de algoritmos e modelos para análise de
dados. Como o ML não está no conteúdo programático deste livro, não vamos nos
aprofundar nele, mas se você quiser explorar o tema, pode conferir os detalhes no
link a seguir: https://azure.microsoft.com/en-in/services/machine-learning/.

Agora você deve ter uma compreensão bastante boa de como criar um data lake e
quais tecnologias usar do Azure. Foram muitas palavras-chave e tecnologias para
lembrar. Se você se sentir sobrecarregado com todas as tecnologias e palavras-
chave, não se preocupe, vamos revisitar essas tecnologias ao longo do livro.
Quando estivermos na metade do livro, você terá uma boa compreensão dessas
tecnologias.

Selecionando os tipos de arquivo


corretos para armazenamento
Agora que entendemos os componentes necessários para criar um data lake no
Azure, precisamos decidir sobre os formatos de arquivo que serão necessários
para armazenamento e recuperação eficientes de dados do data lake. Os dados
geralmente chegam em formatos como arquivos de texto, arquivos de log, valores
separados por vírgulas (CSV), JSON, XML e assim por diante. Embora esses
formatos de arquivo sejam mais fáceis para os humanos lerem e entenderem, eles
podem não ser os melhores formatos para análise de dados. Um formato de
arquivo que não pode ser compactado logo acabará preenchendo as capacidades
de armazenamento; um formato de arquivo não otimizado para operações de
leitura pode acabar retardando análises ou ETLs; Um arquivo que não pode ser
facilmente dividido eficientemente não pode ser processado em paralelo. Para
superar essas deficiências, a comunidade de big data recomenda três formatos de
dados importantes: Avro, Parquet e Optimized Row Columnar (ORC). Esses
formatos de arquivo também são importantes do ponto de vista da certificação, por
isso exploraremos esses três formatos de arquivo em profundidade neste capítulo.

Escolher o tipo de arquivo correto é fundamental, pois não será fácil alterar isso
mais tarde, uma vez que os dados comecem a chegar. Cada um dos formatos de
arquivo tem suas próprias vantagens e desvantagens, mas raramente há um
formato de arquivo que atenda a todos os requisitos. Assim, com base em nossos
requisitos, podemos até optar por ter mais de um formato de arquivo dentro do
data lake. O Azure chama essa persistência poliglota.

Ponta

Tente ficar com apenas um ou dois formatos de arquivo, idealmente um formato


de arquivo por zona do data lake. Muitos formatos de arquivo podem se tornar um
pesadelo de gerenciamento, com várias cópias duplicadas de dados sendo
geradas ao longo do tempo.

Há vários fatores a serem considerados ao escolher um formato de arquivo. Os


mais importantes estão listados aqui:

 Tipo de carga de trabalho: alguns formatos de arquivo têm melhor


desempenho com algumas ferramentas do que outros — por exemplo, o ORC
tem um desempenho melhor com o Hive, enquanto o ORC e o Parquet têm
um bom desempenho com o Spark. Assim, a tecnologia de processamento de
dados que planejamos adotar também terá uma palavra a dizer na decisão do
formato de arquivo.
 Custo: Essa será a principal preocupação de qualquer organização. Como
manter o custo baixo? Quanto mais armazenarmos no data lake, mais
acabaremos pagando por ele. Assim, os formatos de arquivo que suportam
melhores taxas de compactação tornam-se importantes aqui.
 Compressão: Se soubermos que nosso data lake nunca entrará em
intervalos PB ou EB, então podemos decidir sobre formatos de dados que
tenham um bom equilíbrio de compactação versus desempenho. E, da
mesma forma, se nosso tamanho de armazenamento for enorme,
definitivamente precisamos de um formato que suporte níveis de
compactação mais altos.
 Desempenho: Aspectos como velocidade de leitura, velocidade de gravação,
capacidade de dividir arquivos para processamento paralelo e acesso rápido
a dados relevantes afetarão o desempenho das ferramentas analíticas.
Assim, o requisito de desempenho é outro ponto fundamental ao decidir sobre
o formato de arquivo.

Ponta

Se você ainda precisar armazenar os dados em qualquer um dos formatos


semiestruturados, como CSV, JSON, XML e assim por diante, considere
compactá-los usando a compactação Snappy.

Vamos agora explorar os formatos de arquivo em detalhes.


Avro
Avro é um formato de armazenamento baseado em linha. Isso significa que ele
armazena cada linha completa, uma após a outra, em seu armazenamento de
arquivos. Por exemplo, imagine que temos uma tabela como esta:

Figura 2.7 – Uma tabela mostrando o formato Avro

Avro irá armazená-lo logicamente, como mostrado na captura de tela a seguir. Na


realidade, ele estaria adicionando os metadados necessários para decodificar o
arquivo juntos no mesmo arquivo:

Figura 2.8 – Um exemplo de linha Avro, incluindo metadados

Esse formato é bom para cargas de trabalho transacionais de gravação intensiva,


como trabalhos de ETL que precisam ler arquivos inteiros para processar dados.

Informação Avro

Mais informações sobre a Avro podem ser encontradas no seguinte


link: https://avro.apache.org.

Parquete
Parquet, por outro lado, é um formato baseado em colunas. Isso significa que ele
armazena dados de cada coluna relacionada juntos, um após o outro em seu
arquivo. Por exemplo, se considerarmos a mesma tabela no exemplo Avro, o
Parquet a armazenará logicamente conforme mostrado na captura de tela a
seguir. Assim como o Avro, o Parquet também armazenará alguns metadados
junto com os dados reais em seu arquivo:

Figura 2.9 – Um exemplo de linha de parquet

Esse armazenamento baseado em colunas torna o Parquet excepcionalmente


bom para trabalhos de leitura intensiva, como cargas de trabalho analíticas, pois
geralmente consultam apenas um subconjunto de colunas para processamento.
Isso garante que não tenhamos que ler linhas inteiras apenas para processar uma
pequena subseção dessas linhas, ao contrário dos formatos de dados orientados
a linhas. Projetos como Apache Spark e Apache Drill são mais compatíveis com o
Parquet e podem aproveitar os recursos de otimização de consulta,
como Predicate Pushdowns, ao trabalhar com o Parquet.

Informações sobre o parquet

Mais informações sobre o Parquet podem ser encontradas no seguinte


link: https://parquet.apache.org.

ORC
O ORC também é um formato baseado em colunas semelhante ao Parquet e
funciona muito bem com cargas de trabalho analíticas por esse motivo. Projetos
como o Apache Hive são mais compatíveis com o ORC, pois o ORC suporta
nativamente alguns dos tipos de dados do Hive e habilita recursos como
suporte a atomicidade, consistência, isolamento e durabilidade (ACID) e
pushdowns de predicados no Hive.

Informações sobre ORC


Mais informações sobre a ORC podem ser encontradas no seguinte
link: https://orc.apache.org.

Comparando Avro, Parquet e ORC


Vamos comparar os três formatos de arquivo da perspectiva dos principais
parâmetros de avaliação necessários para o armazenamento do data lake, da
seguinte maneira:

Figura 2.10 – Comparações de formatos de arquivo

Agora que entendemos os conceitos básicos dos formatos de arquivo, aqui estão
algumas dicas para escolher o formato de arquivo para cada uma das zonas
descritas na seção Zonas do Data Lake:

Zona de Pouso ou Zona Bruta

 Se o tamanho dos dados for enorme (em terabytes (TB), PB ou


superior), você precisará de uma boa compactação, então use Avro ou texto
compactado usando tecnologias como a compactação Snappy.
 Se você planeja ter muitos trabalhos de ETL, vá com Avro.

 Se você planeja ter apenas um formato de arquivo para facilitar a


manutenção, o Parquet seria um bom compromisso do ponto de vista de
compactação e desempenho.

Zona de transformação
 Se você for usar principalmente o Hive, vá com o ORC.

 Se você vai usar principalmente o Spark, vá com o Parquet.

Escolhendo os tipos de arquivo certos


para consultas analíticas
Na seção anterior, discutimos os três formatos de arquivo — Avro, Parquet e ORC
— em detalhes. Qualquer formato que ofereça suporte a leituras rápidas é melhor
para cargas de trabalho de análise. Então, naturalmente, formatos baseados em
colunas, como Parquet e ORC, se encaixam na conta.

Com base nas cinco áreas principais que comparamos antes (leitura, gravação,
compactação, evolução do esquema e a capacidade de dividir arquivos para
processamento paralelo) e sua escolha de tecnologias de processamento, como
Hive ou Spark, você pode selecionar ORC ou Parquet.

Por exemplo, considere o seguinte:

 Se você tiver cargas de trabalho baseadas em Hive ou Presto, use o ORC.

 Se você tiver cargas de trabalho baseadas em Spark ou Drill, use Parquet.

Agora que você entende os diferentes tipos de formatos de arquivo disponíveis e


os que devem ser usados para cargas de trabalho analíticas, vamos para o
próximo tópico: projetando para consultas eficientes.

Projetando o armazenamento para


consultas eficientes
Para projetar uma consulta eficiente, teremos que entender as diferentes
tecnologias de consulta disponíveis no Azure. Embora este capítulo seja focado
principalmente em tecnologias de armazenamento, um pequeno desvio para o
mundo das consultas nos ajudará a entender melhor o processo de design para
consultas eficientes. Há dois tipos de serviços de consulta disponíveis: os
baseados em SQL, como o Azure SQL, o Synapse Serverless/Dedicated
Pools (anteriormente conhecido como SQL Warehouse) e os mecanismos
analíticos de big data, como o Spark e o Hive. Vamos explorar as técnicas de
design importantes para esses dois grupos de mecanismos de consulta.

Podemos agrupar amplamente as técnicas disponíveis para consultas eficientes


nas três camadas a seguir:

 Camada de armazenamento —
usando técnicas como particionamento, remoção de dados e consistência
eventual
 Camada de aplicativo — usando técnicas como cache de dados e ajuste
de aplicativos (como variar os tamanhos dos contêineres, aumentar o
paralelismo)
 Camada de consulta — usando técnicas especializadas, como
indexação e exibições materializadas, disponíveis em alguns dos serviços

Não se preocupe com todas as novas palavras-chave nesta seção. Todos nós
exploraremos essas tecnologias em detalhes nas próximas seções. Vamos
começar com a camada de armazenamento.

Camada de armazenamento
Projetar uma estratégia de partição corretamente no início é importante porque,
uma vez que implementamos as partições, será difícil alterá-las em um ponto
posterior. Alterar partições em um estágio posterior exigirá transferências de
dados, modificações de consulta, alterações em aplicativos e assim por diante.
Uma estratégia de partição para um tipo de consulta pode não funcionar para
outra consulta, portanto, devemos nos concentrar em criar uma estratégia de
partição para nossas consultas mais críticas. Vejamos os pontos importantes a
serem considerados ao projetar partições.

Partições
Uma partição refere-se apenas à maneira como dividimos os dados e os
armazenamos. As melhores partições são aquelas que podem executar consultas
paralelas sem exigir muitas transferências de dados entre partições. Assim,
dividimos os dados de tal forma que os dados sejam distribuídos uniformemente e
os dados relacionados sejam agrupados dentro das mesmas partições. As
partições são um conceito muito importante do ponto de vista da certificação e,
como tal, há um capítulo inteiro dedicado às partições (Capítulo 3, Projetando uma
estratégia de partição). Então, vamos nos concentrar em uma visão geral de alto
nível aqui.

Alguns conceitos de partição importantes que podem ajudar a acelerar o


desempenho da consulta são discutidos a seguir.

Replicando dados

Dados estáticos menores e usados com mais frequência, como dados de pesquisa


ou dados de catálogo, podem ser replicados em partições. Isso ajudará a reduzir o
tempo de acesso aos dados e, por sua vez, acelerará consideravelmente as
consultas.

Reduzindo operações e junções entre partições

Minimizar as junções entre partições executando trabalhos em paralelo dentro de


cada partição e agregando apenas os resultados finais ajudará no acesso a dados
entre partições. Qualquer acesso entre partições é uma operação cara, portanto,
tentar executar o máximo de processamento de dados dentro da mesma partição
antes de exportar apenas os dados filtrados necessários ajudará a melhorar o
desempenho geral das consultas.

Poda de dados

A remoção ou exclusão de dados refere-se ao processo de ignorar dados


desnecessários durante a consulta e, assim, reduzir as operações
de entrada/saída (E/S). Este também é um tópico importante para a certificação,
por isso, temos uma seção completa dedicada à poda de dados mais adiante
neste capítulo.
Consistência eventual

Os sistemas de armazenamento oferecem suporte a diferentes níveis de


consistência. As lojas em nuvem geralmente mantêm cópias redundantes de seus
dados em vários servidores. Consistência refere-se a quanto tempo todas as
cópias internas de seus dados refletirão uma alteração feita na cópia principal. Os
armazenamentos de dados geralmente oferecem suporte a consistência forte ou
consistência eventual, mas alguns armazenamentos, como o Cosmos DB, até
oferecem suporte a vários níveis entre consistência forte e eventual. Se o sistema
de armazenamento for fortemente consistente, ele garantirá que todas as cópias
de dados sejam atualizadas antes que o usuário possa executar qualquer outra
operação. Por outro lado, se o sistema de armazenamento for eventualmente
consistente, o armazenamento permitirá que os dados em cada uma das cópias
sejam atualizados gradualmente ao longo do tempo. As consultas em execução
em armazenamentos de dados fortemente consistentes tendem a ser mais lentas,
pois o sistema de armazenamento garantirá que todas as gravações (em todas as
cópias) sejam concluídas antes que a consulta possa retornar. Mas em sistemas
eventualmente consistentes, a consulta retornará imediatamente após a primeira
cópia ser feita, e o restante das atualizações para todas as outras cópias
acontecerão de forma assíncrona. Portanto, se o seu sistema pode tolerar
consistência eventual, então ele tenderá a ser mais rápido.

Em seguida, vamos examinar os componentes da camada de aplicativo.

Camada de aplicação
As otimizações da camada de aplicativo lidam com a eficiência com que usamos
os componentes principais, como a unidade central de processamento (CPU),
memória, rede e assim por diante. Vejamos algumas das maneiras de melhorar o
desempenho na camada de aplicativo.

Aplicativos de ajuste

Os serviços analíticos de big data, como Spark e Hive, podem ser otimizados


configurando o número de execuções paralelas e outros atributos, como memória,
CPU, largura de banda de rede e o tamanho dos contêineres. Aqui estão alguns
pontos a serem considerados para ajustar esses serviços:

 Considere os tamanhos corretos de máquina virtual (VM). Selecione


VMs que tenham memória, CPU, disco e largura de banda de rede suficientes
para seus aplicativos.
 VMs maiores podem oferecer suporte a mais contêineres e, portanto,
aumentar a paralelização, mas isso está sujeito à capacidade do aplicativo de
dimensionar com a paralelização aumentada. Encontre o ponto ideal entre a
capacidade do aplicativo de dimensionar e os tamanhos de VM.

Por exemplo, vamos considerar o Spark. Cada um dos contêineres de trabalho do


Spark é chamado de executor. Você pode considerar experimentar as seguintes
configurações para executores:

 Num-executors—Quantos executores você deseja executar em cada


máquina.

 Memória do executor — quanta memória você deseja alocar a cada executor


para que eles não fiquem sem memória. Isso geralmente depende do
tamanho e da distorção dos dados. Com base na quantidade de dados que
serão processados por cada executor, você precisa configurar a memória.

 Núcleos de executor—Quantos núcleos de CPU você deseja alocar para cada


executor. Se o seu trabalho for mais intensivo em computação, adicionar mais
núcleos a cada executor pode acelerar o processamento.

Vamos ver a seguir como o armazenamento em cache de dados pode ajudar a


acelerar as consultas.

Cache

Cache refere-se ao armazenamento de dados intermediários em camadas de


armazenamento mais rápidas para acelerar consultas. Podemos usar
serviços externos, como o cache Redis, para armazenar dados acessados com
frequência por consultas para economizar nas latências de leitura. Também
podemos habilitar opções de cache incorporadas, como o
cache Resultset, disponíveis em tecnologias como Synapse SQL para acelerar o
desempenho da consulta.

Em seguida, vamos examinar um pouco mais de perto a camada de consulta.

Camada de consulta
A camada de consulta também é tecnicamente parte da camada de aplicativo,
mas a otimização de consulta é toda uma área de interesse em si mesma. Existem
milhares de trabalhos acadêmicos dedicados à área de otimização de consultas.
Portanto, examinamos as opções disponíveis para otimizações de consulta como
uma seção separada no Capítulo 14, Otimizando e solucionando problemas de
armazenamento e processamento de dados.

Indexação

Uma das técnicas importantes a serem usadas para consultas eficientes é a


indexação. Se você já usou alguma tecnologia SQL antes, talvez já tenha ouvido
falar sobre indexação de tabelas com base em determinadas colunas-chave. Os
índices são como as chaves em um HashMap que podem ser usados para
acessar diretamente uma linha específica sem ter que examinar a tabela inteira.

Em sistemas baseados em SQL, talvez seja necessário acessar linhas usando


valores diferentes da chave primária. Nesses casos, o mecanismo de consulta
precisa verificar todas as linhas para encontrar o valor que estamos procurando.
Em vez disso, se pudermos definir um índice secundário com base em valores de
coluna pesquisados com frequência, poderemos evitar as varreduras completas
da tabela e acelerar a consulta. As tabelas de índice secundárias são calculadas
separadamente dos índices primários da tabela, mas isso é feito pelo mesmo
mecanismo SQL.

No Azure, temos tecnologias que podem realizar a indexação em grandes


volumes de dados. Esses índices podem ser usados por mecanismos analíticos,
como o Spark, para acelerar as consultas. Uma dessas tecnologias que o Azure
oferece é chamada de Hiperespaço.
O Hyperspace nos permite criar índices em conjuntos de dados de entrada, como
Parquet, CSV e assim por diante, que podem ser usados para otimização de
consulta. A indexação do Hyperspace precisa ser executada separadamente para
criar um índice inicial. Depois disso, ele pode ser atualizado incrementalmente
para os novos dados. Uma vez que temos o índice Hyperspace, qualquer consulta
do Spark pode aproveitar o índice, semelhante a como usamos índices no SQL.

Visões materializadas

Exibições são projeções lógicas de dados de várias tabelas. Visões materializadas


são apenas versões pré-preenchidas de tais visões. Se uma consulta precisar
fazer mesclagens e uniões complexas de várias tabelas ou várias partições, pode
ser benéfico executar essas mesclagens e uniões com antecedência e manter os
dados prontos para o consumo da consulta. As exibições materializadas podem
ser geradas em intervalos regulares e mantidas prontas antes da execução da
consulta real.

Para todos os fins práticos, as exibições materializadas são apenas caches


especializados para as consultas. Os dados em exibições materializadas são
dados somente leitura e podem ser regenerados a qualquer momento. Ele não é
persistido permanentemente no armazenamento.

Agora que consideramos como as necessidades de consulta eficientes podem


influenciar nossos projetos, vamos estender essa consideração à remoção de
dados.

Projetando armazenamento para


remoção de dados
A remoção de dados, como o nome sugere, refere-se à remoção ou corte dos
dados desnecessários para que as consultas não precisem ler todo o conjunto de
dados de entrada. A E/S é um grande gargalo para qualquer mecanismo analítico,
então a ideia aqui é que, reduzindo a quantidade de dados lidos, podemos
melhorar o desempenho da consulta. A remoção de dados geralmente
requer algum tipo de entrada do usuário no mecanismo analítico para que ele
possa decidir sobre quais dados podem ser ignorados com segurança para uma
consulta específica.

Tecnologias como Synapse Dedicated Pools, Azure SQL, Spark e Hive fornecem
a capacidade de particionar dados com base em critérios definidos pelo usuário.
Se pudermos organizar os dados de entrada em pastas físicas que correspondem
às partições, podemos efetivamente ignorar a leitura de pastas inteiras de dados
que não são necessárias para tais consultas.

Vamos considerar os exemplos de Synapse Dedicated Pool e Spark, pois eles são
importantes do ponto de vista da certificação.

Exemplo de pool SQL dedicado com remoção


Vamos considerar um exemplo muito simples que qualquer pessoa com um
background SQL simples entenderá. Depois de entrarmos nos detalhes de
implementação nos capítulos posteriores, exploraremos muitos dos recursos
avançados fornecidos pelo Pool SQL Dedicado.

Aqui, criamos uma tabela de viagem para o nosso cenário IAC. Apenas para
refrescar sua memória, IAC é nosso exemplo de cenário de cliente que estamos
executando ao longo deste livro.

A tabela foi particionada usando a palavra-chave on , conforme ilustrado no trecho


de código a seguir:PARTITIONtripDate

CREATE TABLE dbo.TripTable

    [tripId] INT NOT NULL,

    [driverId] INT NOT NULL,

    [customerID] INT NOT NULL,

    [tripDate] INT,

    [startLocation] VARCHAR(40),

    [endLocation] VARCHAR(40)
)

WITH

    PARTITION ([tripDate] RANGE RIGHT FOR VALUES

        ( 20220101, 20220201, 20220301 )

    )

)
CopyExplain

A sintaxe especificada apenas garante que os valores especificados na


sintaxe pertençam ao lado direito do intervalo. Neste exemplo, as partições terão a
seguinte aparência:RANGE RIGHTPARTITION

Partition 1: All dates < 20220101

Partition 2: 20220101 to 20220231

Partition 3: 20220201 to 20220228

Partition 4: 20220301 to 20220331


CopyExplain

Se tivéssemos dado , teria acabado criando partições assim: RANGE LEFT

Partition 1:  All dates < 20220102

Partition 2: 20220102 to 20220201

Partition 3: 20220202 to 20220301

Partition 4: All dates > 20220301


CopyExplain

Agora, digamos que precisamos encontrar todos os clientes que viajaram com a
IAC no mês de janeiro. Tudo o que você precisa fazer é usar um filtro simples,
como no exemplo a seguir:

SELECT customerID FROM TripTable


WHERE tripDate BETWEEN '20220101' AND '20220131'
CopyExplain

Se não fosse a partição, a consulta teria que examinar todos os registros na tabela
para encontrar as datas dentro do intervalo de . Mas com a partição no lugar, a
consulta só verificará os registros na partição. Isso torna a consulta mais
eficiente.'20220101' AND '20220131''20220101'

Exemplo de faísca com poda


Vamos ver como podemos implementar a remoção de dados para o Spark. Neste
exemplo, vamos criar um Spark Data Frame simples e gravá-lo em partições de
data, como . Em seguida, veremos como ler apenas a partir de uma partição
necessária de dados. Procederemos da seguinte forma:"year/month/day"

1. Vamos criar alguns dados de exemplo usando uma matriz simples, da


seguinte maneira:
2. columnNames =

["tripID","driverID","customerID","cabID","date","startLocation","endLocation"]

3. tripData = [

4.   ('100', '200', '300', '400', '20220101', 'New York', 'New Jersey'),

  ('101', '201', '301', '401', '20220102', 'Tempe', 'Phoenix') ]


CopyExplain
5. Crie um DataFrame usando os dados anteriores, da seguinte forma:
df = spark.createDataFrame(data= tripData, schema = columnNames)
CopyExplain
6. Como o está em formato de data simples, vamos dividi-lo em ano, mês e dia,
da seguinte maneira:tripDate
7. dfDate = df.withColumn("date", to_timestamp(col("date"), 'yyyyMMdd')) \

8.            .withColumn("year", date_format(col("date"), "yyyy")) \

9.            .withColumn("month", date_format(col("date"), "MM")) \

           .withColumn("day", date_format(col("date"), "dd"))


CopyExplain
10. Agora, reparticione os dados na memória, da seguinte forma:
dfDate = dfDate.repartition("year", "month", "day")
CopyExplain
11. E, finalmente, gravá-lo em arquivos diferentes sob o diretório de saída. Aqui,
refere-se ao driver do Sistema de Arquivos de Blob do Azure. O código é
ilustrado no seguinte trecho:abfs://IAC/Trips/Outabfss
dfDate.write.partitionBy("year", "month", "day").parquet("abfss://IAC/Trips/Out"))
CopyExplain
12. Neste ponto, nosso diretório de saída será criado com a seguinte estrutura:
13. abfss://IAC/Trips/Out/

14.                   year=2022/

15.                             day=01/

                                   part*.parquet
CopyExplain
16. Agora, vamos ver como funciona a poda. Por exemplo, se executarmos a
seguinte consulta, o Spark lerá de forma inteligente apenas a pasta sem exigir
que examinemos todos os dados na
pasta:year="2022/month=01/day=03"IAC/Trips/Out
readDF = spark.read.parquet("abfss://IAC/Trips/Out/year=2022").filter("month=01", "day=03")
CopyExplain

Como você deve ter observado, particionar dados por meio de boas estruturas de
pastas pode ajudar a melhorar a eficiência das consultas. Este é um bom exemplo
em nosso próximo tópico, que explica como projetar estruturas de pastas para
data lakes.

Projetando estruturas de pastas para


transformação de dados
Considerando a variedade e o volume de dados que irão pousar em um data lake,
é muito importante projetar uma estrutura de pastas flexível, mas que possa ser
mantida. Estruturas de pastas mal projetadas ou ad hoc se tornarão um pesadelo
de gerenciamento e tornarão o data lake inutilizável. Alguns pontos a ter em mente
ao projetar a estrutura de pastas são dados aqui:

 Legibilidade humana — estruturas de pastas legíveis por humanos ajudarão


a melhorar a exploração e a navegação de dados.
 Representação da estrutura organizacional — alinhar a estrutura de pastas
de acordo com a estrutura organizacional ajuda a segregar os dados para
faturamento e controle de acesso. Essa estrutura de pastas ajudará a
restringir o acesso a dados entre equipes.
 Distinguir dados confidenciais — a estrutura de pastas deve ser tal que
possa separar dados confidenciais de dados gerais. Os dados confidenciais
exigirão níveis mais altos de políticas de auditoria, privacidade e segurança,
portanto, mantê-los separados facilita a aplicação das políticas necessárias.
 Capacidade de gerenciamento de ACLs — se você se lembrar do início do
capítulo, as ACLs são usadas para fornecer controle sobre quais usuários
têm permissões de leitura, gravação ou execução em arquivos e pastas.
Devemos projetar as pastas de tal forma que precisamos aplicar ACLs
apenas nos níveis superiores das pastas e não nas pastas folha. Não
devemos acabar em uma situação em que precisamos atualizar as ACLs toda
vez que uma subpasta é criada automaticamente, como novas pastas de
carimbo de data/hora para entradas de streaming.
 Otimize para leituras mais rápidas e uniformemente distribuídas — se
pudermos distribuir os dados uniformemente, as cargas de trabalho poderão
acessar os dados em paralelo. Isso melhorará o desempenho da consulta.
Além disso, pense no suporte para poda, que discutimos em uma seção
anterior.
 Considere os limites de assinatura: o Azure tem limites por assinatura sobre
o tamanho dos dados, a entrada/saída de rede, paralelismo e assim por
diante. Então, se os dados forem enormes, precisamos planejar dividi-los
em um nível de assinatura.

Com as diretrizes anteriores em mente, vamos explorar as estruturas de pastas


para três casos de uso diferentes.
Cenários de streaming e IoT
Os cenários de streaming e IoT são complicados, pois haverá milhares de
arquivos transmitidos de diferentes fontes, como tweets, sensores, dados de
telemetria e assim por diante. Precisamos de uma maneira eficiente de rastrear e
organizar os dados.

O modelo de layout recomendado pela Microsoft é fornecido aqui:

{Region}/{SubjectMatter(s)}/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Vamos considerar o exemplo do IAC. Se quisermos armazenar todas as viagens


feitas por um determinado táxi, a estrutura de pastas pode ser algo assim:

New York/cabs/cab1234/trips/2021/12/01
CopyExplain

Ou, se quisermos coletar os detalhes do cliente para cada um dos táxis todos os
dias, pode ser algo assim:

New York/cabs/cab1234/customers/2021/12/01
CopyExplain

Mas e se os detalhes do cliente forem considerados informações confidenciais que


precisam aderir a níveis mais altos de políticas de segurança e privacidade?
Nesses casos, a estrutura de pastas anterior se torna inconveniente porque
precisamos iterar cada cab e, em seguida, aplicar ACLs para cada uma das
pastas do cliente sob ela. Então, uma estrutura melhor ficaria assim:

New York/sensitive/customers/cab1234/2021/12/01
CopyExplain

Na estrutura de pastas anterior, podemos aplicar facilmente todas as diretivas de


segurança e ACLs na própria pasta. As restrições serão herdadas
automaticamente por todas as subpastas sob ele.sensitive
Então, se você tiver dados categorizados como confidenciais, então você pode
considerar os seguintes modelos:

{Region}/Sensitive/{SubjectMatter(s)}/{yyyy}/{mm}/{dd}/{hh}/

{Region}/General/{SubjectMatter(s)}/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Vejamos a seguir os cenários de lote.

Cenários em lote
Em sistemas de processamento em lote, lemos os dados de entrada e gravamos
os dados processados em diretórios de saída, por isso é intuitivo manter diretórios
de entrada e saída separados nos caminhos das pastas. Além dos diretórios de
E/S, também seria benéfico ter um diretório para todos os arquivos defeituosos,
como arquivos corrompidos, arquivos incompletos e assim por diante, para que
eles possam ser verificados em intervalos regulares pelos administradores de
dados.

O modelo de layout recomendado pela Microsoft é fornecido aqui:

{Region}/{SubjectMatter(s)}/In/{yyyy}/{mm}/{dd}/{hh}/

{Region}/{SubjectMatter(s)}/Out/{yyyy}/{mm}/{dd}/{hh}/

{Region}/{SubjectMatter(s)}/Bad/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Continuando nosso exemplo IAC, vamos supor que queremos gerar relatórios
diários para as viagens de táxi. Então, nosso diretório de entrada poderia ter esta
aparência:

New York/trips/In/cab1234/2021/12/01/*
CopyExplain

Nosso diretório de saída pode ter esta aparência:

New York/trips/Out/reports/cab1234/2021/12/01
CopyExplain

E, finalmente, o diretório de arquivos ruins poderia se parecer com isto:

New York/trips/Bad/cab1234/2021/12/01
CopyExplain

Aqui, novamente, se você tiver dados categorizados como confidenciais, poderá


considerar os seguintes modelos:

{Region}/General/{SubjectMatter(s)}/In/{yyyy}/{mm}/{dd}/{hh}/

{Region}/Sensitive/{/{SubjectMatter(s)}/Out/{yyyy}/{mm}/{dd}/{hh}/

{Region}/General/{/{SubjectMatter(s)}/Bad/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Ponta

Não coloque pastas de data no início, pois isso torna a aplicação de ACLs a cada
subpasta mais tediosa. Além disso, há limites no número de ACLs que podem ser
aplicadas, portanto, há chances de você ficar sem ACLs com o passar do tempo.

Agora que aprendemos algumas das práticas recomendadas para criar estruturas
de pastas em um data lake, vamos avançar para explorar algumas estratégias de
otimização envolvendo o Azure Synapse Analytics, conforme exigido pelo nosso
programa de certificação.

Desenhando uma estratégia de


distribuição
Estratégias de distribuição são técnicas que são usadas em Synapse Dedicated
SQL Pools. Synapse Dedicated SQL Pools são sistemas de processamento
paralelo (MPP) que dividem as consultas em 60 consultas paralelas e as
executam em paralelo. Cada uma dessas consultas menores é executada em algo
chamado distribuição. Uma distribuição é uma unidade básica de processamento
e armazenamento para um pool SQL dedicado.
O SQL dedicado usa o Armazenamento do Azure para armazenar os dados e
fornece três maneiras diferentes de distribuir (fragmentar) os dados entre as
distribuições. Eles estão listados da seguinte forma:

 Mesas redondas

 Tabelas de hash

 Tabelas replicadas

Com base em nossos requisitos, precisamos decidir sobre quais dessas técnicas
de distribuição devem ser usadas para criar nossas tabelas. Para escolher a
estratégia de distribuição correta, você deve entender seu aplicativo, o layout de
dados e os padrões de acesso a dados usando planos de consulta. Aprenderemos
como gerar e ler planos de consulta e padrões de dados nos próximos capítulos.
Agora, vamos tentar entender a diferença de alto nível em cada uma das técnicas
de distribuição e como escolher a opção certa.

Mesas redondas
Em uma tabela round-robin, os dados são distribuídos em série entre todas as
distribuições. É a mais simples das distribuições e é o padrão quando o tipo de
distribuição não é especificado. Essa opção é a mais rápida para carregar dados,
mas não é a melhor para consultas que incluem junções. Use tabelas round-robin
para dados de preparo ou dados temporários, onde os dados serão lidos em sua
maioria.

Aqui está um exemplo simples de criação de uma tabela distribuída round-robin no


Pool SQL Dedicado:

CREATE TABLE dbo.CabTable

(  

    [cabId] INT NOT NULL,  

    [driverName] VARCHAR(20),  

    [driverLicense] VARCHAR(20)  
)
CopyExplain

Não há necessidade de especificar nenhum atributo para tabelas round-robin; é a


distribuição padrão.

Tabelas de hash
Em uma tabela de hash, as linhas são distribuídas para
diferentes distribuições com base em uma função de hash. A chave de hash é
geralmente uma das colunas na tabela. As tabelas de hash são melhores para
consultas com junções e agregações. São ideais para mesas grandes.

Aqui está um exemplo simples de criação de uma tabela distribuída de hash no


Pool SQL Dedicado:

CREATE TABLE dbo.CabTable

(  

    [cabId] INT NOT NULL,  

    [driverName] VARCHAR(20),  

    [driverLicense] VARCHAR(20)  

)  

WITH  

(   

    DISTRIBUTION = HASH (cabId)

)
CopyExplain

Ponta

Escolha uma chave de coluna que seja distinta e estática, pois isso pode equilibrar
a distribuição de dados entre as partições.
Tabelas replicadas
Com tabelas replicadas, os dados da tabela são copiados para todas
as distribuições. Eles são ideais para tabelas pequenas, onde o custo de copiar os
dados para as junções de consulta supera os custos de armazenamento dessas
tabelas pequenas. Use tabelas replicadas para armazenar tabelas de
pesquisa rápida (LUTs).

Aqui está um exemplo simples de criação de uma tabela replicada no Pool SQL
Dedicado:

CREATE TABLE dbo.CabTable

(  

    [cabId] INT NOT NULL,  

    [driverName] VARCHAR(20),  

    [driverLicense] VARCHAR(20)  

)  

WITH  

(   

    DISTRIBUTION = REPLICATE

)
CopyExplain

Revisitaremos esses conceitos em detalhes quando aprendermos como


implementá-los para problemas práticos nos próximos capítulos. Vamos agora ao
último tópico do nosso capítulo, que trata apropriadamente do fim da vida útil dos
nossos dados.

Projetando uma solução de


arquivamento de dados
Agora que aprendemos como projetar um data lake e otimizar o armazenamento
para nossas consultas analíticas, ainda há um componente final a ser projetado.
Como arquivamos ou limpamos os dados antigos? Sem uma solução adequada
de arquivamento e/ou exclusão, os dados crescerão e preencherão o
armazenamento muito em breve.

O Azure fornece três camadas de armazenamento: Camada de Acesso Quente,


Camada de Acesso Frio e Camada de Acesso de Arquivamento.

Camada de Acesso Ativo


A Camada de Acesso Ativo é ideal para dados acessados com frequência. Ele
fornece o menor custo de acesso, mas a um custo de armazenamento mais alto.

Nível de acesso a frio


A camada de acesso frio é ideal para dados que são acessados ocasionalmente,
como dados um pouco mais antigos que provavelmente são usados para backups
ou relatórios mensais. Ele fornece custos de armazenamento mais baixos, mas
com custos de acesso mais altos. O Azure espera que os dados da camada de
acesso frio sejam armazenados por pelo menos 30 dias. A exclusão antecipada ou
a alteração de nível podem resultar em cobranças extras.

Camada de acesso ao arquivamento


A camada de acesso ao arquivamento é ideal para armazenar dados por longos
períodos. Pode ser por motivos de conformidade, backups de longo prazo,
arquivamento de dados e assim por diante. A Camada de Acesso ao Arquivo
Morto é uma solução de armazenamento offline, o que significa que você não
poderá acessar os dados a menos que reidrate-os do Arquivo Morto para uma
camada Online. Esta é a opção de armazenamento mais barata entre todos os
níveis. O Azure espera que os dados da Camada de Arquivo Morto sejam
armazenados por pelo menos 180 dias. A exclusão antecipada ou a alteração de
nível podem resultar em cobranças extras.
Gerenciamento do ciclo de vida dos dados
O armazenamento de Blobs do Azure fornece ferramentas para o gerenciamento
do ciclo de vida dos dados. Usando essas ferramentas, podemos definir políticas
como por quanto tempo um determinado dado precisa estar na Camada de
Acesso Ativo, quando mover os dados entre as diferentes camadas de acesso,
quando excluir blobs e assim por diante. O Azure executa essas políticas
diariamente.

Vamos ver um exemplo de como criar uma política de ciclo de vida de dados.

Portal do Azure

Vamos explorar como criar uma política de ciclo de vida de dados usando o portal
do Azure, da seguinte maneira:

1. No portal do Azure, selecione sua conta de armazenamento.


2. Vá para a guia Gerenciamento de Dados e selecione Gerenciamento do
Ciclo de Vida.
3. Clique no sinal + para adicionar uma nova regra.
4. Na página Detalhes, adicione um nome para sua regra e selecione quais
blobs de armazenamento essa regra precisa aplicar.
5. Clique em Avançar e, na página Blobs base, você pode especificar a regra
real. Um exemplo é mostrado na Figura 2.11.
6. Uma vez feito, clique no botão Adicionar.

Você pode ver uma visão geral disso na captura de tela a seguir:
Figura 2.11 – Como especificar regras de gerenciamento do ciclo de vida dos
dados no Armazenamento do Azure

Nota

O Azure executa políticas de ciclo de vida de dados apenas uma vez por dia,
portanto, pode levar até 24 horas para que suas políticas entrem em ação.

Resumo
Com isso, chegamos ao final do nosso segundo capítulo. Exploramos os vários
projetos de data lake em detalhes e aprendemos boas práticas para projetar um.
Agora você deve estar confortável para responder a perguntas relacionadas a
arquiteturas de data lake e às tecnologias de armazenamento, computação e
outras envolvidas na criação de um data lake. Você também deve estar
familiarizado com formatos de arquivo comuns, como Avro, Parquet e ORC e
saber quando escolher quais formatos de arquivo. Também exploramos diferentes
técnicas de otimização, como remoção de dados, particionamento, cache,
indexação e muito mais. Também aprendemos sobre estruturas de pastas,
distribuição de dados e, finalmente, como projetar um ciclo de vida de dados
usando políticas para arquivar ou excluir dados. Isso abrange o conteúdo
programático do exame DP-203, o capítulo Projetar uma estrutura de
armazenamento de dados. Reforçaremos os aprendizados deste capítulo por meio
de detalhes de implementação e dicas nos próximos capítulos.

Vamos explorar o conceito de particionamento com mais detalhes no próximo


capítulo.

Capítulo 3: Projetando uma estratégia de


partição
O particionamento de dados refere-se ao processo de dividir dados e armazená-
los em locais fisicamente diferentes. Particionamos dados principalmente por
motivos de desempenho, escalabilidade, capacidade de gerenciamento e
segurança. O particionamento em si é um termo genérico, mas os métodos e
técnicas de particionamento variam de serviço para serviço — por exemplo, as
técnicas de particionamento usadas para o armazenamento de Blobs do Azure
podem não ser as mesmas aplicadas para serviços de banco de dados, como o
SQL do Azure ou o pool SQL Dedicado do Azure Synapse. Da mesma forma,
bancos de dados de documentos, como o Cosmos DB, têm técnicas de
particionamento diferentes das Filas do Azure ou das Tabelas do Azure. Neste
capítulo, exploraremos algumas das técnicas importantes de particionamento e
quando usá-las.

Como no capítulo anterior, voltaremos a nos concentrar mais nos aspectos de


design, de acordo com o conteúdo programático. Os detalhes da implementação
serão abordados no Capítulo 5, Implementando estruturas de armazenamento de
dados físicos.

Este capítulo abordará os seguintes tópicos:


 Noções básicas sobre particionamento

 Criando uma estratégia de partição para arquivos

 Projetando uma estratégia de partição para cargas de trabalho analíticas

 Projetando uma estratégia de partição para eficiência/desempenho

 Criando uma estratégia de partição para o Azure Synapse Analytics

 Identificando quando o particionamento é necessário no Azure Data Lake


Storage Gen2 (ADLS Gen2)

Quase todos os principais serviços do Armazenamento do Azure e do Azure


Analytics oferecem suporte ao particionamento de uma forma ou de outra, mas, no
interesse da certificação, cobriremos apenas os serviços que são relevantes para
a certificação. Se você estiver interessado em aprender sobre particionamento nos
outros serviços do Azure, consulte o seguinte link: https://docs.microsoft.com/en-
us/azure/architecture/best-practices/data-partitioning-strategies.

Vamos mergulhar no mundo da partição!

Noções básicas sobre particionamento


No capítulo anterior, apresentamos brevemente o conceito de particionamento
como parte da seção Projetando armazenamento para consulta eficiente.
Exploramos conceitos de particionamento do lado do armazenamento, como
replicação de dados, redução de operações entre partições, como junções, e
consistência eventual para melhorar o desempenho da consulta. Neste capítulo,
aprofundaremos mais sistematicamente as técnicas de armazenamento e
particionamento analítico. Vamos começar com os benefícios do particionamento.

Benefícios do particionamento
O particionamento tem vários benefícios, além do desempenho da consulta.
Vamos dar uma olhada em alguns importantes.

Melhorando o desempenho
Como discutimos no capítulo anterior, o particionamento ajuda a melhorar a
paralelização de consultas dividindo dados monolíticos massivos em blocos
menores e facilmente consumíveis.

Além da paralelização, o particionamento também melhora o desempenho por


meio da remoção de dados, outro conceito que já discutimos no capítulo anterior.
O uso de consultas de remoção de dados pode ignorar partições não relevantes,
reduzindo assim a entrada/saída (E/S) necessária para consultas.

As partições também ajudam no arquivamento ou exclusão de dados mais


antigos. Por exemplo, vamos supor que precisamos excluir todos os dados com
mais de 12 meses. Se particionarmos os dados em unidades de dados mensais,
podemos excluir os dados de um mês inteiro com apenas um único comando, em
vez de excluir todos os arquivos um a um ou todas as entradas de uma tabela
linha por linha.DELETE

Vejamos a seguir como o particionamento ajuda na escalabilidade.

Melhorando a escalabilidade

No mundo do processamento de big data, existem dois tipos de escala: vertical e


horizontal.

O dimensionamento vertical refere-se à técnica de aumentar a capacidade de


máquinas individuais adicionando mais memória, CPU, armazenamento ou rede
para melhorar o desempenho. Isso geralmente ajuda no curto prazo, mas acaba
atingindo um limite além do qual não podemos escalar.

O segundo tipo de dimensionamento é chamado de dimensionamento


horizontal. Isso se refere à técnica de aumentar a capacidade de processamento
e armazenamento adicionando cada vez mais máquinas a um cluster, com
especificações de hardware regulares que estão facilmente disponíveis no
mercado (hardware commodity). À medida que os dados crescem, só precisamos
adicionar mais máquinas e redirecionar os novos dados para as novas máquinas.
Este método teoricamente não tem limites superiores e pode crescer para sempre.
Os data lakes são baseados no conceito de dimensionamento horizontal.
O particionamento de dados ajuda naturalmente no dimensionamento horizontal.
Por exemplo, vamos supor que armazenamos dados em um intervalo por dia em
partições, então teremos cerca de 30 partições por mês. Agora, se precisarmos
gerar um relatório mensal, podemos configurar o cluster para ter 30 nós para que
cada nó possa processar o valor de um dia de dados. Se o requisito aumentar
para processar relatórios trimestrais (ou seja, relatórios a cada 3 meses), podemos
simplesmente adicionar mais nós — digamos, mais 60 nós ao nosso tamanho de
cluster original de 30 para processar 90 dias de dados em paralelo. Portanto, se
pudermos projetar nossa estratégia de partição de dados de tal forma que
possamos dividir os dados facilmente em novas máquinas, isso nos ajudará a
escalar mais rapidamente.

Vejamos a seguir como o particionamento ajuda no gerenciamento de dados.

Melhorando a capacidade de gerenciamento

Em muitos sistemas analíticos, teremos que lidar com dados de uma ampla


variedade de fontes, e cada uma dessas fontes pode ter políticas de governança
de dados diferentes atribuídas a elas. Por exemplo, alguns dados podem ser
confidenciais, então precisamos restringir o acesso a eles; alguns podem ser
dados transitórios que podem ser regenerados à vontade; alguns podem estar
registrando dados que podem ser excluídos após alguns meses; alguns podem
ser dados de transações que precisam ser arquivados por anos; e assim por
diante. Da mesma forma, pode haver dados que precisam de acesso mais rápido,
então podemos optar por mantê-los em armazenamentos de unidade de estado
sólido (SSD) premium e outros dados em uma unidade de disco rígido (HDD)
para economizar no custo.

Se armazenarmos conjuntos de dados tão diferentes em suas próprias partições


de armazenamento, a aplicação de regras separadas — como restrições de
acesso ou a configuração de diferentes atividades de gerenciamento do ciclo de
vida dos dados, como exclusão ou arquivamento de dados e assim por diante —
para as partições individuais se tornará fácil. Portanto, o particionamento reduz a
sobrecarga de gerenciamento, especialmente ao lidar com vários tipos diferentes
de dados, como em um data lake.
Vejamos a seguir como o particionamento de dados ajuda na segurança.

Melhorar a segurança

Como vimos na seção anterior sobre como melhorar a capacidade de


gerenciamento, conjuntos de dados confidenciais podem ter diferentes níveis de
acesso e privacidade. Os dados dos clientes geralmente terão os mais altos níveis
de segurança e privacidade. Por outro lado, os catálogos de produtos podem não
precisar de níveis muito altos de segurança e privacidade.

Assim, ao particionar os dados com base em requisitos de segurança, podemos


isolar os dados seguros e aplicar regras independentes de controle de acesso e
auditoria a essas partições, permitindo assim que apenas usuários privilegiados
acessem esses dados.

Vamos ver a seguir como podemos melhorar a disponibilidade de dados usando o


particionamento.

Melhorando a disponibilidade

Se nossos dados forem divididos em várias partições armazenadas em máquinas


diferentes, os aplicativos poderão continuar a fornecer pelo menos dados parciais,
mesmo que algumas partições estejam inativas. Apenas um subconjunto de
clientes cujas partições ficaram inativas pode ser afetado, enquanto o restante dos
clientes não verá nenhum impacto. Isso é melhor do que todo o aplicativo caindo.
Assim, particionar fisicamente os dados ajuda a melhorar a disponibilidade dos
serviços.

Em geral, se planejarmos nossa estratégia de partição corretamente, os retornos


podem ser significativos. Espero que você já tenha entendido os benefícios do
particionamento de dados. Vamos ver a seguir algumas estratégias de partição de
uma perspectiva de armazenamento/arquivos.

Criando uma estratégia de partição para


arquivos
Nesta seção, examinaremos as técnicas de particionamento disponíveis para o
Armazenamento do Azure, que também devem abranger arquivos. Os serviços de
Armazenamento do Azure são genéricos e muito flexíveis quando se trata de
particionamento. Podemos implementar qualquer lógica de partição que
quisermos, usando as mesmas interfaces de programação de
aplicativos (APIs) Create, Read, Update, Delete (CRUD) que estão disponíveis
publicamente. Não há APIs ou recursos especiais disponíveis para
particionamento. Com esse plano de fundo, vamos agora explorar as opções de
particionamento disponíveis no armazenamento de Blobs do Azure e no ADLS
Gen2.

Armazenamento de Blobs do Azure


No armazenamento de Blobs do Azure, primeiro criamos contas do Azure; Então,
dentro das contas, criamos contêineres; e dentro de contêineres, criamos blobs de
armazenamento reais. Esses contêineres são entidades lógicas, portanto, mesmo
quando criamos blobs de dados dentro de contêineres, não há garantia de que os
dados irão parar na mesma partição. Mas há um truque para aumentar nossas
chances de armazenar os blobs na mesma partição.

O Azure usa algo chamado particionamento de intervalo para armazenar blobs.


Em uma partição de intervalo, os arquivos que estão em uma sequência
lexical acabam juntos em uma partição.

Por exemplo, se tivermos nomes de arquivos como , , e , esses arquivos acabarão


principalmente na mesma partição.Cab1-20211220Cab1-20211221Cab1-20211222Cab1-
20211223

Da mesma forma, nomes de arquivos como , , e na maioria das vezes terminarão


dentro da mesma partição.IAC-CabsIAC-RoutesIAC-CustomersIAC-Drivers

O Armazenamento do Azure usa <nome da conta + nome do contêiner + nome do


blob> como a chave de partição. Ele continua a armazenar blobs na mesma
partição até atingir o limite interno da partição. Nesse ponto, o Armazenamento do
Azure reparticiona e reequilibra os dados e os distribui uniformemente entre as
partições. Todo esse processo de reparticionamento e rebalanceamento será
tratado automaticamente pelo Armazenamento do Azure, sem intervenção do
usuário.

Se a quantidade de dados armazenados for grande e o Armazenamento do Azure


começar a reparticionar e rebalancear os dados, a latência das APIs CRUD será
afetada. Você pode evitar ou atrasar essas partições adicionando um valor de
hash de três dígitos (valor aleatório) aos seus nomes de arquivo. Isso fará com
que os dados sejam distribuídos em várias partições.

Por exemplo, seus nomes de arquivos podem usar o seguinte formato:

New York/cabs/cab1234/customers/{XYZYYYYMMDD}
CopyExplain

Aqui, pode ser o valor de hash aleatório. XYZ

ADLS Gen2
A solução para particionamento de arquivos em um data lake é a mesma
que projetar a estrutura de pastas, que já discutimos no capítulo anterior.
Podemos aplicar diferentes políticas de segurança ou diferentes configurações de
gerenciamento do ciclo de vida dos dados a pastas individuais no ADLS Gen2.
Como já exploramos o tópico de estrutura de pastas em detalhes, não o
abordaremos novamente aqui.

Além da estrutura de pastas, também podemos particionar dados para os


benefícios que discutimos anteriormente neste capítulo, como desempenho,
escalabilidade, capacidade de gerenciamento, segurança, disponibilidade e assim
por diante. O processo de segregação dos dados em partições pode ser feito
manualmente ou pode ser automatizado usando o Azure Data Factory (ADF).
Analisaremos mais profundamente a automação usando o ADF nos capítulos
posteriores orientados à implementação.

Agora que temos uma boa ideia sobre otimizações de particionamento baseadas
em armazenamento e arquivo, vamos explorar o particionamento do ponto de vista
da carga de trabalho analítica.
Projetando uma estratégia de partição
para cargas de trabalho analíticas
Existem três tipos principais de estratégias de partição para cargas de trabalho
analíticas. Estes estão listados aqui:

 Particionamento horizontal, que também é conhecido como fragmentação

 Particionamento vertical

 Particionamento funcional

Vamos explorar cada um deles em detalhes.

Particionamento horizontal
Em uma partição horizontal, dividimos os dados da tabela horizontalmente e
subconjuntos de linhas são armazenados em diferentes armazenamentos
de dados. Cada um desses subconjuntos de linhas (com o mesmo esquema da
tabela pai) são chamados de fragmentos. Essencialmente, cada um desses
fragmentos é armazenado em instâncias de banco de dados diferentes.

Você pode ver um exemplo de uma partição horizontal aqui:


Figura 3.1 – Exemplo de partição horizontal

No exemplo anterior, você pode ver que os dados na tabela superior são
distribuídos horizontalmente com base no intervalo ID de viagem.

Selecionando a chave de estilhaço correta

É muito importante selecionarmos a chave de estilhaço certa (também chamada


de chave de partição) para particionar os dados, pois alterá-la mais tarde será
uma operação muito cara. As seguintes diretrizes nos ajudarão com isso:

 Selecione uma chave que espalhe os dados de forma que o tráfego do


aplicativo para as partições de dados seja distribuído uniformemente.

 Selecione uma chave que não seja alterada com muita frequência. Boas
chaves são estáticas e são generalizadas — em outras palavras, o alcance
dessa chave não deve ser muito pequeno nem muito grande. Como regra
geral, uma chave que pode gerar centenas de partições é boa. Evite chaves
que geram poucas partições (dezenas de partições) ou muitas partições
(milhares de partições).

Nota
Não tente equilibrar os dados a serem distribuídos uniformemente entre
partições, a menos que especificamente exigido pelo seu caso de uso, porque
geralmente os dados mais recentes serão acessados mais do que os dados
mais antigos. Assim, as partições com dados recentes acabarão se tornando
gargalos devido ao alto acesso aos dados.

Abordaremos o padrão de fragmentação em profundidade na próxima seção,


quando falarmos sobre particionamento para eficiência e desempenho.

Particionamento vertical
Em uma partição vertical, dividimos os dados verticalmente, e cada subconjunto
das colunas é armazenado separadamente em um armazenamento de dados
diferente. No caso do particionamento vertical, normalizamos parcialmente a
tabela para dividi-la em tabelas menores (menos colunas). Esse tipo de
particionamento é ideal nos casos em que uma tabela pode ter um subconjunto de
dados que é acessado com mais frequência do que o resto. O particionamento
vertical pode ajudar a acelerar as consultas, pois apenas o subconjunto
necessário de dados pode ser recuperado seletivamente, em vez de ler linhas
inteiras. Isso é ideal para armazenamentos de dados orientados a colunas, como
HBase, Cosmos DB e assim por diante.

Você pode ver um exemplo de uma partição vertical aqui:


Figura 3.2 – Exemplo de partição vertical

No exemplo anterior, você pode ver que colunas como Classificação


de Viagem e Comentários do Cliente que podem não ser usadas com frequência
são divididas em partições separadas. Isso ajudará a reduzir a quantidade de
dados que estão sendo lidos para consultas.

Particionamento funcional
As partições funcionais são semelhantes às partições verticais, exceto que aqui,
armazenamos tabelas ou entidades inteiras em diferentes armazenamentos de
dados. Eles podem ser usados para segregar dados pertencentes a diferentes
organizações, tabelas usadas com frequência de tabelas usadas com pouca
frequência, tabelas de leitura-gravação de somente leitura, dados confidenciais de
dados gerais e assim por diante.

Você pode ver um exemplo de uma partição funcional aqui:


Figura 3.3 – Exemplo de uma partição funcional

Neste exemplo, você pode ver como os dados do cliente são movidos para sua
própria partição. Essa segregação nos ajudará a aplicar diferentes regras de
privacidade e segurança para as diferentes partições.

Os serviços do Azure, como o SQL do Azure e o pool dedicado do Azure Synapse,


dão suporte a todos os formatos de particionamento discutidos nesta seção.

Projetando uma estratégia de partição


para eficiência/desempenho
Nas últimas seções, exploramos as várias opções de armazenamento e
particionamento analítico e aprendemos sobre como o particionamento ajuda no
desempenho, escala, segurança, disponibilidade e assim por diante. Nesta seção,
vamos recapitular os pontos que aprendemos sobre desempenho e eficiência e
aprender sobre alguns padrões de desempenho adicionais.

Aqui estão algumas estratégias a ter em mente ao projetar para eficiência e


desempenho:
 Particione conjuntos de dados em blocos menores que podem ser executados
com paralelismo ideal para várias consultas.

 Particione os dados de forma que as consultas não acabem exigindo muitos


dados de outras partições. Minimize as transferências de dados entre
partições.

 Projete estruturas de pastas eficazes para melhorar a eficiência das leituras e


gravações de dados.

 Particione dados de forma que uma quantidade significativa de dados possa


ser removida durante a execução de consultas.

 Particione em unidades de dados que podem ser facilmente adicionadas,


excluídas, trocadas ou arquivadas. Isso ajuda a melhorar a eficiência do
gerenciamento do ciclo de vida dos dados.

 Tamanhos de arquivo no intervalo de 256 megabytes (MB) a


100 gigabytes (GB) funcionam muito bem com mecanismos analíticos como
HDInsight e Azure Synapse. Portanto, agregue os arquivos a esses intervalos
antes de executar os mecanismos analíticos neles.
 Para trabalhos com uso intensivo de E/S, tente manter os tamanhos ideais de
buffer de E/S na faixa de 4 a 16 MB; qualquer coisa muito grande ou muito
pequena se tornará ineficiente.

 Execute mais contêineres ou executores por máquina virtual (VM) (como


executores do Apache Spark ou contêineres Apache Yet Another Resource
Negotiator (YARN).

Tente lembrar as boas práticas anteriores ao projetar sua próxima estratégia de


partição. Vamos tentar entender como realmente encontrar os dados certos para
particionar e quantos dados particionar.

Processo iterativo de melhoria do desempenho da


consulta
Aqui está um processo iterativo de alto nível para melhorar o desempenho da
consulta:

1. Liste as consultas críticas para os negócios, as consultas executadas com


mais frequência e as consultas mais lentas.
2. Verifique os planos de consulta para cada uma dessas consultas usando a
palavra-chave e veja a quantidade de dados que estão sendo usados em
cada estágio (aprenderemos sobre como exibir planos de consulta nos
capítulos posteriores).EXPLAIN
3. Identifique as junções ou filtros que estão demorando mais tempo. Identifique
as partições de dados correspondentes.
4. Tente dividir as partições de dados de entrada correspondentes em partições
menores ou altere a lógica do aplicativo para executar o processamento
isolado na parte superior de cada partição e, posteriormente, mesclar apenas
os dados filtrados.
5. Você também pode tentar ver se outras chaves de particionamento
funcionariam melhor e se você precisa reparticionar os dados para obter
melhor desempenho de trabalho para cada partição.
6. Se qualquer tecnologia de particionamento específica não funcionar, você
pode explorar ter mais de uma parte da lógica de particionamento — por
exemplo, você pode aplicar o particionamento horizontal dentro do
particionamento funcional e assim por diante.
7. Monitore o particionamento regularmente para verificar se os padrões de
acesso ao aplicativo estão equilibrados e bem distribuídos. Tente identificar
pontos quentes logo no início.
8. Itere esse processo até atingir o tempo de execução da consulta preferencial.

Também utilizaremos estas orientações nos nossos exemplos nos próximos


capítulos. Vamos explorar as especificidades do particionamento no Azure
Synapse Analytics.

Criando uma estratégia de partição para


o Azure Synapse Analytics
Aprendemos sobre o Azure Synapse Analytics no Capítulo 2, Projetando uma
estrutura de armazenamento de dados. O Synapse Analytics contém dois
mecanismos de computação, descritos aqui:

 Um pool de SQL (Structured Query Language) que consiste em pools SQL


dedicados e sem servidor (anteriormente conhecido como SQL Data
Warehouse)
 Uma piscina Spark que consiste em piscinas Synapse Spark

Mas quando as pessoas se referem ao Azure Synapse Analytics, geralmente se


referem à opção Pool SQL dedicado. Nesta seção, examinaremos a estratégia de
partição disponível para o pool SQL dedicado do Synapse.

Nota

Já abordamos brevemente o particionamento no Spark como parte da


seção Remoção de dados no capítulo anterior. Os mesmos conceitos também se
aplicam ao Synapse Spark.

Antes de explorarmos as opções de particionamento, vamos recapitular as


técnicas de distribuição de dados de um pool dedicado do Synapse do capítulo
anterior, pois isso desempenhará um papel importante em nossa estratégia de
partição, da seguinte maneira:

Um pool SQL dedicado é um sistema de processamento paralelo massivo (MPP)


que divide as consultas em 60 consultas paralelas e as executa em paralelo. Cada
uma dessas consultas menores é executada em algo chamado distribuição. Uma
distribuição é uma unidade básica de processamento e armazenamento para um
pool SQL dedicado. Há três maneiras diferentes de distribuir dados (fragmentos)
entre distribuições, conforme listado aqui:

 Mesas redondas
 Tabelas de hash
 Tabelas replicadas

O particionamento é suportado em todos os tipos de distribuição na lista anterior.


Além dos tipos de distribuição, o pool SQL dedicado também oferece suporte a
três tipos de tabelas: columnstore clusterizado, índice clusterizado e tabelas de
heap. Exploraremos essas opções de tabela em detalhes nos próximos capítulos.
O particionamento também é suportado em todos esses tipos de tabelas.

Em um pool SQL dedicado, os dados já estão distribuídos em suas 60


distribuições, portanto, precisamos ter cuidado ao decidir se precisamos
particionar ainda mais os dados. As tabelas columnstore clusterizadas funcionam
de forma ideal quando o número de linhas por tabela em uma distribuição é de
cerca de 1 milhão.

Por exemplo, se planejamos particionar ainda mais os dados pelos meses de um


ano, estamos falando de 12 partições x 60 distribuições = 720 subdivisões. Cada
uma dessas divisões precisa ter pelo menos 1 milhão de linhas; Em outras
palavras, a tabela (geralmente uma tabela de fatos) precisará ter mais de 720
milhões de linhas. Portanto, teremos que ter cuidado para não particionar
excessivamente os dados quando se trata de pools SQL dedicados.

Dito isso, o particionamento em pools dedicados do Synapse tem duas vantagens


distintas, como veremos agora.

Melhoria de desempenho ao carregar dados


O particionamento ajuda ao carregar dados para consultas em pools SQL
dedicados. Essa é uma técnica que já discutimos na seção Benefícios do
particionamento deste capítulo. Se pudermos agrupar os dados pertencentes a um
determinado período de tempo em uma partição, adicionar ou remover esses
dados se tornará tão simples quanto executar um comando ou simples. Por
exemplo, vamos supor que precisamos gerar um relatório contínuo de 12 meses.
No final de cada mês, removemos o mês mais antigo e adicionamos um novo mês
ao relatório. Se particionamos os dados com a granularidade de meses, podemos
facilmente excluir os dados antigos e adicionar os novos dados usando uma
técnica de troca de partição em um pool SQL dedicado. ADDDELETE

Melhoria de desempenho para filtrar consultas


O particionamento também pode ajudar a melhorar o desempenho da consulta,
sendo capaz de filtrar os dados com base em partições. Em particular, as
partições ajudam com a cláusula em consultas. Por exemplo, se particionamos os
dados com base nos meses de um ano, podemos especificar qual mês exato
procurar em nossas consultas, ignorando assim o restante dos meses. WHERE

Espero que você tenha entendido os recursos e restrições para particionamento


em pools dedicados do Azure Synapse. Vamos para nossa próxima seção, que
fala sobre quando começar a particionar dados no ADLS Gen2.

Identificando quando o particionamento é


necessário no ADLS Gen2
Como aprendemos no capítulo anterior, podemos particionar dados de acordo
com nossos requisitos, como desempenho, escalabilidade, segurança, sobrecarga
operacional e assim por diante, mas há outra razão pela qual podemos acabar
particionando nossos dados, que são os vários limites de largura de banda de E/S
que são impostos em níveis de assinatura pelo Azure. Esses limites se aplicam ao
armazenamento de Blobs e ao ADLS Gen2.

A taxa na qual ingerimos dados em um sistema de Armazenamento do Azure é


chamada de taxa de entrada, e a taxa na qual movemos os dados para fora do
sistema de Armazenamento do Azure é chamada de taxa de saída.

A tabela a seguir mostra um instantâneo de alguns dos limites impostos pelo


armazenamento de Blobs do Azure. Esta tabela é apenas para lhe dar uma ideia
dos limites que o Armazenamento do Azure impõe. Quando projetamos nossos
aplicativos de data lake, precisamos cuidar de tais restrições como parte de nosso
próprio design:
Figura 3.4 – Alguns dos limites para o armazenamento de Blobs do Azure no
momento em que este livro foi publicado

Assim, por exemplo, se sua taxa de saída for superior a 50 gigabits por
segundo (Gbps) para seu data lake, você terá que criar várias contas e
particionar seus dados entre essas contas.

Ponta

Se você estiver usando uma configuração híbrida de sistemas locais e na nuvem e


se transferir dados entre esses sistemas com frequência, verifique se as máquinas
de origem/destino e a rede pública real podem oferecer suporte ao nível de taxas
de transferência de dados de entrada e saída fornecidas pelo Armazenamento do
Azure. Se você estiver movendo dados de fontes locais, considere usar o Azure
ExpressRoute.
Para obter limites de Armazenamento do Azure completos e atualizados, consulte
a seguinte
documentação: https://docs.microsoft.com/en-us/azure/storage/common/
scalability-targets-standard-account.

Observe que alguns dos limites na tabela (como taxas de entrada e limites de
capacidade de armazenamento) são limites flexíveis, o que significa que você
pode entrar em contato com o Suporte do Azure para aumentar esses limites até
certo ponto; no entanto, você acabará atingindo os limites rígidos para cada
opção. Outros recursos, como IP (Internet Protocol), endereços, redes
virtuais (VNets) e assim por diante são limites rígidos, então você precisa
planejar as partições com esses números em mente.

Nota

Os requisitos de entrada/saída mais altos também podem vir dos aplicativos em


execução sobre o Armazenamento do Azure e não apenas por meio de
carregamentos e downloads diretos de dados na loja do Azure. Por exemplo, se
tivermos um pool dedicado do SQL do Azure ou do Azure Synapse (data
warehouse) que tenha um fragmento muito ocupado, ele poderá exceder os limites
de leitura (saída) dessa conta de armazenamento. Nesses casos, teremos que
reparticionar esse fragmento para dividir os dados entre várias contas.

Em geral, para qualquer serviço do Azure, fique de olho nos limites de recursos
para que não seja uma surpresa quando seu produto for implantado na produção.

Resumo
Com isso, chegamos ao final do nosso terceiro capítulo. Espero que você tenha
gostado de aprender sobre as diferentes técnicas de particionamento disponíveis
no Azure! Começamos com o básico de particionamento, onde você aprendeu
sobre os benefícios do particionamento; Em seguida, passamos para técnicas de
particionamento para cargas de trabalho analíticas e de armazenamento.
Exploramos as melhores práticas para melhorar a eficiência e o desempenho do
particionamento. Entendemos o conceito de tabelas de distribuição e como elas
afetam o particionamento do Azure Synapse Analytics e, finalmente, aprendemos
sobre as limitações de armazenamento, que desempenham um papel importante
na decisão de quando particionar para o ADLS Gen2. Isso abrange o conteúdo
programático do exame DP-203, Designing a Partition Strategy. Reforçaremos os
aprendizados deste capítulo por meio de detalhes de implementação e dicas nos
próximos capítulos.

Vamos explorar a camada de serviço no próximo capítulo.

Capítulo 4: Projetando a camada de


serviço
Neste capítulo, aprenderemos sobre as técnicas e tecnologias envolvidas no
design de uma camada de serviço de dados. Como vimos anteriormente no design
do data lake, os dados passam por várias zonas. Ele começa a partir de uma
Zona de Pouso, de onde é processado em formatos mais úteis na Zona
de Transformação e, finalmente, os insights de dados derivados aterrissam
na Zona de Serviço (também chamada de camada de Serviço). A Zona de
Atendimento fornece os dados e insights processados para os usuários finais. A
Zona de Pouso e a Zona de Transformação de um data lake se concentram em
aspectos como armazenamento eficiente de dados, processamento de grandes
volumes de dados, otimização de consultas e assim por diante. A camada de
Servir, por outro lado, foca principalmente em como atender os dados de forma
rápida e eficiente às ferramentas de business intelligence (BI).

As camadas de serviço geralmente são criadas usando armazenamentos de


dados relacionais (repositórios baseados em SQL (Structured Query Language).
Isso é feito por dois motivos: armazenamentos de dados relacionais podem
armazenar dados em tabelas normalizadas eficientes e executar consultas mais
rapidamente do que os serviços analíticos de big data. Isso funciona bem porque a
quantidade de dados na Zona de Serviço geralmente é menor do que na Zona de
Transformação; Além disso, o SQL é a linguagem preferida para a maioria dos
analistas de dados e é universalmente suportada pelas ferramentas de BI.

O Azure nos fornece uma variedade de serviços que podem ser usados para criar
a camada de Serviço, como Azure Synapse Analytics, Azure SQL, Cosmos DB,
Apache Hive, Apache HBase e assim por diante. Exploraremos os importantes
para a certificação neste capítulo.

Neste capítulo, vamos nos concentrar nos seguintes tópicos:

 Aprendendo os conceitos básicos de modelagem de dados e esquemas

 Projetando esquemas de estrelas e flocos de neve

 Projetando dimensões que mudam lentamente (SCDs))


 Projetando uma solução para dados temporais

 Projetando uma hierarquia dimensional

 Projetando para carregamento incremental

 Projetando lojas analíticas

 Criando metastores no Azure Synapse Analytics e no Azure Databricks

Este é o último dos capítulos focados no design. Os próximos três capítulos serão
dedicados aos detalhes de implementação do que aprendemos até agora.

Vamos começar!

Requisitos técnicos
Para este capítulo, você precisará de uma conta do Azure (gratuita ou paga).

Aprendendo os conceitos básicos de


modelagem de dados e esquemas
A modelagem de dados é um processo de projetar como os dados serão
representados em armazenamentos de dados. Muitas técnicas de modelagem de
dados foram originalmente projetadas para bancos de dados e armazéns. Como
as camadas de serviço geralmente são criadas com armazenamentos de dados
relacionais, como data warehouses, algumas das técnicas de modelagem de
dados também podem ser aplicadas ao design da camada de serviço.
Mas lembre-se de que a camada de serviço pode ser criada usando outras
tecnologias de armazenamento, como bancos de dados de documentos,
armazenamentos de chave-valor e assim por diante, com base nos requisitos do
cliente.

Ao contrário dos data lakes, em bancos de dados ou data warehouses não temos
o luxo de armazenar grandes volumes de dados no formato que gostamos.
Bancos de dados e data warehouses podem executar consultas excepcionalmente
rápidas, desde que os dados sejam armazenados em formatos predeterminados e
sejam limitados em tamanho. Portanto, ao projetar a camada de serviço,
precisamos identificar as especificidades de quais dados precisam ser
armazenados, em qual formato armazená-los e quantos dados armazenar. Para
ser específico, precisamos decidir quais tabelas SQL são necessárias, qual seria a
relação entre essas tabelas e quais restrições precisam ser impostas a essas
tabelas.

Existem diferentes métodos de modelagem de dados, como modelagem


entidade-relacionamento (ER), modelagem hierárquica, modelagem de dados
dimensionais, modelagem de dados relacionais, modelagem de dados orientada
a objeto (OO) e assim por diante. Dentre estas, a modelagem dimensional é a
mais relevante para data warehousing, por isso nos concentraremos apenas nas
técnicas de modelagem dimensional neste capítulo.

Modelos dimensionais
A modelagem dimensional se concentra na recuperação de informações mais fácil
e rápida, enquanto outros modelos geralmente se concentram na otimização do
armazenamento. Os modelos de dados dimensionais mais comumente usados
são os esquemas Star e Snowflake. Vamos nos concentrar nesses dois
esquemas nas seções a seguir.

Projetando esquemas de estrelas e


flocos de neve
Os esquemas são diretrizes para organizar entidades de dados, como tabelas
SQL em um armazenamento de dados. Projetar um esquema refere-se ao
processo de projetar as várias tabelas e as relações entre elas. Os esquemas Star
e Snowflake são dois dos esquemas mais usados no mundo da análise de dados
e BI. Na verdade, os esquemas Star são usados com mais frequência do que os
esquemas Snowflake. Ambos têm suas próprias vantagens e desvantagens, então
vamos explorá-los em detalhes.

Esquemas em estrela
Um esquema Star é o mais simples dos esquemas de data warehouse. Ele tem
dois conjuntos de tabelas: uma que armazena informações quantitativas, como
transações que acontecem em um ponto de venda ou viagens que acontecem em
uma empresa de táxi, e outra que armazena o contexto ou descrições de eventos
que são armazenados na tabela quantitativa.

As tabelas quantitativas são chamadas de tabelas de fatos e as tabelas descritivas


ou de contexto são chamadas de tabelas de dimensão.

O diagrama a seguir mostra um exemplo de um esquema Star:


Figura 4.1 – Exemplo de um esquema Star

Como pode ser óbvio pelos nomes das tabelas, é a nossa tabela de fatos, e todas
as outras — como , , e — são tabelas de
dimensão.FactTripsDimDriverDimCustomerDimDateDimCab

Uma vez que o diagrama de relacionamento do esquema Estrela tem a forma de


uma estrela, ele é chamado de esquema Estrela. A tabela de fatos no meio é o
centro da estrela, e as tabelas de dimensões são os braços da estrela.

Vejamos alguns pontos importantes sobre os esquemas Star, como segue:

 As tabelas de fatos são geralmente de volume muito maior do que as tabelas


de dimensão.
 As tabelas de dimensão não estão conectadas; eles são independentes uns
dos outros.

 Os dados não são normalizados em um esquema Star. É muito comum


encontrar dados replicados em várias tabelas. As mesas são projetadas para
velocidade e facilidade de uso.

 Eles são otimizados para consultas de BI. As consultas geralmente são muito
simples, pois tem apenas um nível de junções.
 As consultas também costumam ser muito mais rápidas devido ao menor
número de junções.

Agora, vamos ver como os esquemas de Flocos de Neve são diferentes.

Esquemas de flocos de neve


Um esquema de floco de neve é uma extensão do esquema Star. Nesse modelo,
a tabela de fatos permanece a mesma, mas as tabelas de dimensão são divididas
em suas formas normalizadas, que são referenciadas usando chaves
estrangeiras. Pode haver vários níveis de hierarquia entre as tabelas de
dimensão.

O diagrama a seguir mostra como o mesmo exemplo usado para um esquema


Star pode ser estendido para um esquema Snowflake:
Figura 4.2 – Exemplo de um esquema de floco de neve

Como você notará no diagrama anterior, a tabela foi normalizada para ter os
detalhes da licença separadamente. Da mesma forma, normalizamos os detalhes
do endereço longe da tabela.DimDriverDimCustomer

Você pode escolher um esquema do Snowflake se tiver aplicativos de BI e não-BI


compartilhando o mesmo data warehouse. Nesses casos, de uma perspectiva
geral, talvez seja melhor ter dados normalizados.

Vejamos alguns pontos importantes sobre os esquemas de Flocos de Neve, como


segue:

 As tabelas de fatos, aqui novamente, são semelhantes aos esquemas Star e


são de volume muito maior do que as tabelas de dimensão.

 Os dados de dimensão são normalizados, evitando assim quaisquer dados


redundantes.

 As dimensões poderiam ser conectadas entre si.

 Os dados são otimizados para armazenamento e integridade, mas não


velocidade.
 O esquema é mais complexo do que um esquema Star, portanto, essa pode
não ser a opção preferida para casos de uso de BI e relatórios.

 As consultas são geralmente mais lentas em comparação com os esquemas


Star devido às junções de vários níveis necessárias.

Espero que agora você tenha uma boa ideia sobre os esquemas Star e Snowflake.
Há mais um tipo de esquema chamado esquema de Constelação de
Fatos ou esquema de Galáxia. Com esse tipo de esquema, pode haver mais de
uma tabela de fatos e as tabelas de dimensão são compartilhadas. Esse esquema
não é tão importante quanto os esquemas Star e Snowflake de uma perspectiva
de certificação, mas se você quiser saber mais sobre esse esquema, você pode
começar a partir daqui: https://www.javatpoint.com/data-warehouse-what-is-fact-
constellation-schema.

Vamos ver a seguir como lidar com dados que mudam lentamente em tabelas de
dimensão.

Projetando SCDs
SCDs referem-se a dados em tabelas de dimensão que mudam lentamente ao
longo do tempo e não em uma cadência regular. Um exemplo comum para SCDs
são os perfis de clientes — por exemplo, um endereço de e-mail ou o número de
telefone de um cliente não muda com tanta frequência, e esses são candidatos
perfeitos para SCD. Nesta seção, veremos como projetar essas mudanças.

Serviços como o Azure SQL fornecem suporte embutido para SCD, mas em data
warehouses como pools dedicados do Synapse, teremos que implementá-los nós
mesmos.

Aqui estão alguns dos principais aspectos que precisaremos considerar ao


projetar um SCD:

 Devemos acompanhar as mudanças? Se sim, quanto da história devemos


manter?

 Ou devemos simplesmente substituir as mudanças e ignorar o histórico?


Com base em nossos requisitos para manter o histórico, há cerca de sete
maneiras pelas quais podemos realizar o controle das mudanças. Eles são
chamados de SCD1, SCD2, SCD3 e assim por diante, até SCD7.

Dentre estes, SCD1, SCD2, SCD3, SCD4 e SCD6 são os mais importantes, e
vamos nos concentrar apenas naqueles deste capítulo. Estes são também os mais
importantes do ponto de vista da certificação.

Projetando SCD1
No SCD tipo 1, os valores são substituídos e nenhum histórico é mantido,
portanto, uma vez que os dados são atualizados, não há como descobrir qual era
o valor anterior. As novas consultas sempre retornarão o valor mais recente. Aqui
está um exemplo de uma tabela SCD1:

Figura 4.3 – Exemplo de SCD tipo 1

Neste exemplo, o valor da coluna Cidade está mudando de Nova York para Nova


Jersey. O valor apenas é substituído.

Projetando SCD2
No SCD2, mantemos um histórico completo de alterações. Toda vez que há uma
alteração, adicionamos uma nova linha com todos os detalhes sem excluir os
valores anteriores. Há várias maneiras pelas quais podemos fazer isso. Vamos dar
uma olhada nas abordagens mais comuns.

Usando um sinalizador
Nessa abordagem, usamos um sinalizador para indicar se um determinado valor
está ativo ou se é atual. Aqui está um exemplo disso:

Figura 4.4 – Exemplo de SCD tipo 2: sinalizador

Na segunda tabela, sempre que há uma alteração, adicionamos uma nova linha e
atualizamos a coluna das linhas anteriores para False. Dessa forma, podemos
facilmente consultar os valores ativos filtrando os critérios. isActiveisActive=True

Nota

As chaves substitutas são chaves de identificação de linha secundárias. Eles são


adicionados em todos os casos SCD2 porque a chave de identificação
primária não será mais exclusiva com linhas recém-adicionadas.

Usando números de versão

Nessa abordagem, usamos números de versão para acompanhar as alterações. A


linha com a versão mais alta é o valor mais atual. Aqui está um exemplo disso:
Figura 4.5 – Exemplo de SCD tipo 2: números de versão

No exemplo anterior, precisamos filtrar na coluna MAX(Version) para obter os


valores atuais.

Usando intervalos de datas

Nessa abordagem, usamos intervalos de datas para mostrar o período em que um


determinado registro (linha) estava ativo, conforme ilustrado no exemplo a seguir:

Figura 4.6 – Exemplo de SCD tipo 2: intervalos de datas

No exemplo anterior, sempre que alteramos um campo, adicionamos um novo


registro à tabela. Junto com isso, atualizamos a coluna EndDate do registro
anterior e a coluna StartDate para o novo registro com a data de hoje. Para
buscar o registro atual, temos que filtrar os critérios, ou, em vez disso, poderíamos
apenas preencher uma data muito futurista em vez de —algo
como .EndDate=NULL NULL31-Dec-2100
Como uma variação da abordagem de intervalo de datas, também podemos
adicionar uma coluna de sinalizador para identificar facilmente registros ativos ou
atuais. O exemplo a seguir mostra essa abordagem:

Figura 4.7 – Exemplo de SCD tipo 2: intervalos de datas e sinalizador

Vejamos agora o design do SCD3.

Projetando SCD3
Na SCD3, mantemos apenas uma história parcial e não uma história completa.
Em vez de adicionar linhas adicionais, adicionamos uma coluna extra que
armazena o valor anterior, para que apenas uma versão dos dados históricos seja
preservada. Tal como acontece com a opção SCD2, aqui novamente, podemos
optar por adicionar colunas de data para acompanhar as datas modificadas, mas
não precisamos de chaves substitutas neste caso, pois a chave de identificação
do registro não muda. Aqui está um exemplo disso:

Figura 4.8 – Exemplo de SCD tipo 3

No exemplo anterior, adicionamos uma nova coluna chamada PrevCity. Toda vez


que o valor de Cidade muda, adicionamos o valor anterior ao PrevCity e
atualizamos a coluna Cidade com a cidade atual.
Projetando SCD4
SCD4 foi introduzido para atributos de dimensão que mudam com relativa
frequência. No tipo 4, dividimos os atributos de mudança rápida da tabela de
dimensões em outra tabela de dimensões menores e também referenciamos a
nova tabela de dimensões diretamente da tabela de fatos.

Por exemplo, no diagrama a seguir, se assumirmos que o passe de carona


(também conhecido como veículos de alta ocupação) precisa ser comprado todos
os meses, podemos mover esse campo para uma minidimensão menor e
referenciá-lo diretamente da tabela de fatos:

Figura 4.9 – Exemplo de SCD4: antes da divisão

Podemos dividir a tabela em uma mini dimensão DimCarPool, como no diagrama


a seguir:
Figura 4.10 – Exemplo de SCD tipo 4: após divisão

Essa subdivisão ajuda a modificar apenas uma quantidade menor de dados com
frequência em vez da linha completa.

Projetando SCD5, SCD6 e SCD7


O restante dos SCDs — SCD5, SCD6 e SCD7 — são derivados dos quatro SCDs
anteriores. Dentre essas derivadas, a SCD6 é relativamente importante, então
vamos explorar isso como parte da próxima subseção.

Projetando SCD6
O tipo 6 é uma combinação de 1, 2 e 3. Nesse tipo, juntamente com a adição de
novas linhas, também atualizamos o valor mais recente em todas as linhas,
conforme ilustrado na captura de tela a seguir:

Figure 4.11 – Example of SCD type 6

In the previous example, you would have noticed that the value for all the records
belonging to customer has been updated. This is just another benefit of extracting
the latest values.CurrCityAdam

That explains SCD type 6. If you are interested in learning about SCDs 5 and 7,
you can find more information at the following links:

SCD5: https://www.kimballgroup.com/data-warehouse-business-intelligence-
resources/kimball-techniques/dimensional-modeling-techniques/type-5/

SCD7: https://www.kimballgroup.com/data-warehouse-business-intelligence-
resources/kimball-techniques/dimensional-modeling-techniques/type-7

Agora que você tem uma boa ideia sobre SCDs, vamos explorar como lidar com o


temporal.

Projetando uma solução para dados


temporais
Dados temporais referem-se a dados em pontos específicos no tempo. O
armazenamento de dados temporais é necessário em situações como auditoria de
dados, investigações forenses, manutenção de SCDs, recuperações point-in-time
e assim por diante. O SQL do Azure e o SQL Server fornecem um mecanismo
chamado tabelas temporais para armazenar dados temporais.
As tabelas temporais são tabelas especializadas que controlam as alterações de
dados ao longo do tempo. Eles rastreiam o histórico de alterações de dados como
o que já tínhamos visto em tabelas SCD, mas neste caso o sistema se encarrega
de gerenciar o período de validade de tempo de cada linha, em vez de termos que
fazê-lo manualmente. Por isso, essas tabelas também são chamadas de tabelas
temporais com versão do sistema.

Nota

A tabela temporal é um conceito de banco de dados SQL do Azure e SQL Server.


Ele não estava disponível nos pools do Azure Synapse no momento em que este
livro foi escrito.

Vejamos um exemplo de como criar tabelas temporais no SQL do Azure:

CREATE TABLE Customer

  [customerId] INT NOT NULL PRIMARY KEY CLUSTERED,

  [name] VARCHAR(100) NOT NULL,

  [address] VARCHAR(100) NOT NULL,

  [email] VARCHAR (100) NOT NULL,

  [phone] VARCHAR(12) NOT NULL,

  [validFrom] DATETIME2 GENERATED ALWAYS AS ROW START,

  [validTo] DATETIME2 GENERATED ALWAYS AS ROW END,

  PERIOD FOR SYSTEM_TIME (validFrom, validTo),

WITH (SYSTEM_VERSIONING = ON);


CopyExplain

Se você notar, há três afirmações que se destacariam:

[validFrom] DATETIME2 GENERATED ALWAYS AS ROW START,


[validTo] DATETIME2 GENERATED ALWAYS AS ROW END,

PERIOD FOR SYSTEM_TIME (validFrom, validTo),

Para uma tabela temporal, precisamos definir a Coluna Início do Período e a


Coluna Término do Período. Em nosso exemplo, a Coluna Início do Período é e a
Coluna Término do Período é o . E dizemos ao mecanismo de banco de dados
que esses são nossos indicadores de hora de início e término usando a
linha.validFromvalidToPERIOD FOR SYSTEM_TIME (validFrom, validTo)

Nota

Deve haver apenas uma definida com duas colunas datetime2. Essas duas
colunas datetime2 devem ser declaradas como . PERIOD FOR SYSTEM_TIMEGENERATED
ALWAYS AS ROW START / END

Agora, vamos atualizar uma das entradas da tabela e ver como a tabela temporal
acompanha as alterações.

UPDATE [dbo].[Customer] SET [address] = '111 Updated Lane, LA' WHERE [customerId] = 101;
CopyExplain

Vamos consultar a tabela com base nos dois limites de tempo e ver todas as
alterações que aconteceram com o cliente com customerId=101.
Figura 4.12 – Resultado de amostra de uma consulta temporal

Como você pode ver, a tabela Temporal acompanhou a alteração junto com os
carimbos de data/hora. Derivamos o com base no valor da coluna. IsActualvalidTo

Quando criamos uma tabela Temporal, nos bastidores duas tabelas são criadas.
Uma é chamada de tabela temporal (aquela que definimos) e outra tabela com o
esquema exato chamada de tabela de histórico. Sempre que os dados são
alterados, os valores atuais persistem na tabela Temporal e os valores antigos são
movidos para a tabela de histórico com a hora de término atualizada para o
carimbo de data/hora atual, indicando que essa linha não está mais ativa.
Também há opções para definir nossas próprias tabelas de Histórico com
indexação adicional, distribuições e assim por diante e fornecer isso ao SQL do
Azure para usar como a tabela de histórico.

Tudo o que você precisa fazer é definir a tabela Histórico e fornecer o nome
conforme mostrado durante a criação da tabela Temporal.

WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.CustomerHistory));


CopyExplain

Agora você sabe como aproveitar o suporte a tabelas temporais no SQL do Azure
para criar aplicativos que precisam registrar alterações ao longo do tempo.

Você pode saber mais sobre as tabelas temporais


aqui: https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-
tables?view=sql-server-ver15

Vejamos a seguir como projetar uma hierarquia dimensional.

Projetando uma hierarquia dimensional


A hierarquia dimensional refere-se à maneira como agrupamos e organizamos os
dados dimensionais em vários níveis. Em uma estrutura hierárquica, geralmente
há uma relação um-para-muitos ou muitos-para-muitos pais-filhos. Exemplos de
estruturas hierárquicas podem ser estruturas organizacionais, categorias de
produtos em uma loja online, um sistema de arquivos e assim por diante. A
principal característica da estrutura hierárquica é que todos os nós são idênticos e
incluem ponteiros para os nós de seus pais ou filhos.

A fim de alcançar uma hierarquia dimensional, podemos usar uma técnica


chamada de relação de autorreferência ou auto-junções dentro da tabela de
dimensões. Tomemos um exemplo de uma dimensão Funcionário.

CREATE TABLE DimEmployee (

[employeeId] VARCHAR(20) NOT NULL,

[name] VARCHAR(100),

[department] VARCHAR(50),

[title] VARCHAR(50),

[parentEmployeeId] VARCHAR(20)

)
CopyExplain

Aqui, temos uma coluna chamada referenciando a coluna. Se o Banco de Dados


oferecer suporte à restrição de chave estrangeira, o será definido como a Chave
Estrangeira para . O Synapse SQL ainda não oferece suporte a Chaves
Estrangeiras, portanto, precisamos garantir a correção no nível do
aplicativo.parentEmployeeIDemployeeIDparentEmployeeIDemployeeID

Nota

A chave pai deve permitir entradas, pois os elementos raiz da hierarquia não terão
um pai.NULL

Uma tabela hierárquica de exemplo com entradas teria a seguinte aparência:


Figura 4.13 – Tabela de dimensões hierárquicas de amostra

Podemos ver que David se reporta a Brenda e Brenda se reporta a Alan. Nós
efetivamente criamos uma hierarquia usando a mesma tabela.

Ponta

Se você estiver usando a Hierarquia Dimensional como parte de um SCD, sempre


adicione a chave pai apontando para a chave substituta em vez da chave primária
comercial. Porque as chaves substitutas serão exclusivas e garantirão que a
hierarquia dimensional não seja quebrada quando ocorrerem alterações na chave
de negócios.

Espero que você tenha uma ideia clara sobre hierarquias dimensionais. Vamos
examinar a seguir o design de uma solução de carregamento incremental para a
camada de serviço.

Projetando para carregamento


incremental
O carregamento incremental ou carregamento delta refere-se ao processo de
carregar incrementos menores de dados em uma solução de armazenamento —
por exemplo, podemos ter dados diários que estão sendo carregados em um
data lake ou dados por hora fluindo para um pipeline de extração,
transformação, carregamento (ETL) e assim por diante. Durante cenários de
ingestão de dados, é muito comum fazer um upload em massa seguido de cargas
incrementais agendadas.

O Azure tem um serviço muito versátil chamado Azure Data Factory (ADF), que


pode ajudar com o carregamento incremental. Como esta é a primeira vez que
estamos usando o ADF neste livro, vamos aprender um pouco mais sobre ele
agora, pois as informações serão úteis nos próximos capítulos.

O ADF é um serviço de nuvem gerenciado que pode ser usado para coordenar e
orquestrar pipelines complexos baseados em nuvem ou híbridos (locais). O ADF
fornece a capacidade de construir pipelines ETL e extrair, carregar,
transformar (ELT). Com o ADF, você pode fazer o seguinte:

 Ingerir dados de uma ampla variedade de fontes, como bancos de dados,


compartilhamentos de arquivos, hubs de Internet das Coisas (IoT), Amazon
Web Services (AWS), Google Cloud Platform (GCP) e muito mais.
 Crie pipelines complexos usando variáveis, parâmetros, ramificações e assim
por diante.

 Transforme dados usando serviços de computação como Synapse,


HDInsight, Cosmos DB e assim por diante.

 Programe e monitore ingestões, controle de fluxo e operações de fluxo de


dados.

Veja como é a aparência do espaço de trabalho do ADF:


Figura 4.14 – Tela inicial do Data Factory Workspace

O ADF é construído a partir de um conjunto básico de componentes. Os


importantes estão listados aqui:

 Pipelines — um pipeline é um conjunto de atividades que são vinculadas


para executar algum fluxo de controle ou transformação de dados.
 Atividades — as atividades no ADF referem-se às etapas no pipeline, como
copiar dados, executar um trabalho do Spark e assim por diante.
 Conjuntos de dados — são os dados nos quais seus pipelines ou atividades
operam.
 Serviços Vinculados: os Serviços Vinculados são conexões que o ADF usa
para se conectar a uma variedade de armazenamentos de dados e cálculos
no Azure. Eles são como cadeias de conexão que permitem acessar dados
de fontes externas.
 Gatilhos — Gatilhos são eventos usados para iniciar pipelines ou iniciar uma
atividade.
Usaremos muitas das terminologias anteriores ao usar o ADF, então é bom
entendê-las.

Agora que sabemos o que é ADF, vamos explorar as diferentes maneiras pelas
quais podemos projetar o carregamento incremental usando o ADF. Com base no
tipo de fonte de dados, podemos ter diferentes técnicas para implementar o
carregamento incremental. Alguns deles estão listados aqui:

 Usando marcas d'água — se a fonte de dados for um banco de dados ou


um sistema baseado em tabela relacional
 Usando carimbos de data/hora de arquivo — se a origem for um sistema
de arquivos ou armazenamento de blob
 Usando dados de partição — Se a origem for particionada com base no
tempo
 Usando a estrutura de pastas — se a origem for dividida com base no
tempo

Vamos explorar cada uma dessas técnicas em detalhes.

Marcas d' água


A marca d'água é uma técnica muito simples pela qual apenas acompanhamos o
último registro carregado (nossa marca d'água) e carregamos todos os novos
registros além da marca d'água na próxima corrida incremental.

Em tecnologias de armazenamento relacional, como bancos de dados SQL,


podemos armazenar os detalhes da marca d'água como apenas mais uma tabela
simples e atualizar automaticamente a marca d'água com procedimentos
armazenados. Toda vez que um novo registro é carregado, o procedimento
armazenado deve ser acionado, o que atualizará nossa tabela de marca d'água. O
próximo pipeline de cópia incremental pode usar essas informações de marca
d'água para identificar o novo conjunto de registros que precisam ser copiados.
Vejamos como podemos implementar um design de marca d'água com o ADF
usando o SQL do Azure como origem. Vamos supor que tenhamos uma tabela
simples chamada que precisa ser carregada incrementalmente em uma tabela
SQL do Azure. Proceda da seguinte forma:FactTrips
1. Selecione o serviço SQL do Azure no painel do Azure e crie uma nova
instância SQL do Azure, se você ainda não tiver uma. Crie uma tabela
simples, conforme mostrado na captura de tela a seguir, e insira alguns
valores fictícios nela usando a opção Editor de consultas
(visualização):FactTrips

Figura 4.15 – Criando uma tabela simples no SQL do Azure

2. Crie uma tabela de marca d'água, assim:


3. CREATE TABLE WatermarkTable

4. (

5.   [TableName] VARCHAR(100),

6.   [WatermarkValue] DATETIME,

);
CopyExplain
7. Crie um procedimento armazenado para atualizar automaticamente a tabela
de marca d'água sempre que houver novos dados.
8. CREATE PROCEDURE [dbo].uspUpdateWatermark @LastModifiedtime DATETIME,

@TableName VARCHAR(100)
9. AS

10. BEGIN

11. UPDATE [dbo].[WatermarkTable] SET [WatermarkValue] = @LastModifiedtime WHERE

[TableName] = @TableName

END
CopyExplain
12. Agora, do lado do ADF, precisamos criar um novo pipeline para encontrar o
delta entre as marcas d'água antigas e novas e, em seguida, iniciar uma
cópia incremental.
13. Na página Pipeline no ADF, crie duas atividades de Pesquisa. Eles podem
ser encontrados em Atividades -> Geral -> Lookup. Aqui está um exemplo
de tela do ADF:

Figura 4.16 – Página de criação do ADF

6. Configure o primeiro para procurar a entrada da tabela de marca d'água


anterior, conforme mostrado na captura de tela a seguir. O conjunto de
dados Marca d'água foi configurado para apontar para o
Azure .WatermarkTable
Figura 4.17 – Configuração de pesquisa usando a tabela de marca d'água

7. Configure a próxima atividade de Pesquisa para examinar a


hora de modificação do arquivo mais recente na tabela de origem, que no
nosso caso seria a tabela:FactTrips
SELECT MAX(LastModifiedTime) AS NewWatermarkValue FROM FactTrips;
CopyExplain

Você terá que inserir a seguinte consulta na caixa de texto Consulta na


guia Configurações:
Figura 4.18 – Nova configuração de pesquisa de marca d'água usando
LastModifiedTime

8. Finalmente, adicione uma nova atividade Copiar de Atividades -> Mover


e Transformar -> Copiar Dados e configure-a da seguinte maneira:
9. SELECT * FROM FactTrips WHERE

10. LastModifiedTime > '@{activity('PreviousWatermark').output.firstRow.WatermarkValue}'

11. AND

LastModifiedTime <= '@{activity('NewWatermark').output.firstRow.WatermarkValue}';


CopyExplain

Na seção Consulta, na guia Origem, insira a seguinte consulta:


Figura 4.19 – Atividade de cópia do ADF com geração delta baseada em marca
d'água

9. Salve (publique) o pipeline anterior e configure um gatilho agendado usando


o botão Adicionar gatilho na tela Pipeline. Agora, sempre que houver
alterações na tabela, ela será copiada para nossa tabela de destino em
intervalos regulares.FactTrips

Vamos aprender a seguir como fazer cópia incremental usando carimbos de


data/hora de arquivo.

Carimbos de data/hora do arquivo


Há outra técnica disponível para carregar incrementalmente apenas os novos
arquivos de uma origem para um destino: a funcionalidade da ferramenta Copiar
Dados do ADF. Essa ferramenta fornece uma opção para verificar os arquivos na
origem com base no atributo. Portanto, tudo o que precisamos fazer é especificar
as pastas de origem e destino e selecionar a opção Carga incremental:
LastModifiedDate para o campo Comportamento de carregamento de
arquivo.LastModifiedDate

Você pode iniciar a funcionalidade da ferramenta Copiar Dados na tela principal


do ADF, conforme mostrado na captura de tela a seguir:

Figura 4.20 – Tela de inicialização da ferramenta ADF Copy Data

Depois de clicar na ferramenta Copiar Dados, ela inicia uma tela do assistente
onde você pode especificar os detalhes da carga incremental, conforme ilustrado
na captura de tela a seguir:

-
Figura 4.21 – Selecionando a janela Tumbling para carga incremental com base
no tempo de modificação do arquivo

Nota

Na guia Propriedades mostrada na captura de tela anterior, você precisa


selecionar a janela Tumbling para a configuração Cadência da tarefa ou
agendamento de tarefas; caso contrário, a opção de carga incremental não
aparecerá.

Na janela Origem, selecione a opção Carga incremental: Data da Última


Modificação, conforme mostrado na captura de tela a seguir:
Figura 4.22 – Opção de carga incremental do ADF com carimbos de data/hora
LastModifiedDate

Preencha o restante dos campos e selecione Avançar na tela Resumo para criar


um pipeline de cópia incremental usando datas de modificação de arquivo.

Vamos aprender a seguir como fazer cópia incremental usando estruturas de


pastas.

Partições de arquivos e estruturas de pastas


Para as opções de particionamento de arquivos e dados organizados em
estruturas de pastas baseadas em data, podemos usar a funcionalidade da
ferramenta ADF Copy Data para executar o carregamento incremental. Os
arquivos e pastas em ambas as abordagens terão uma hierarquia de
pastas semelhante com base na data/hora. Se você se lembrar da seção sobre
estrutura de pastas no Capítulo 2, Projetando uma estrutura de armazenamento
de dados, criamos uma estrutura de pastas usando uma hierarquia de datas.
Vamos supor que nossos dados de entrada estejam chegando em uma pasta
estruturada por data, conforme mostrado aqui:

New York/Trips/In/2022/01/01
CopyExplain

Let's try to incrementally upload this data to another location in the blob storage on
a regular basis. ADF's Copy Data tool has support for incremental copying for files
and folders that are partitioned using date/time. Similar to how we instantiated
a Copy activity in the previous section for the incremental copy based on file
modified date timestamps, we need to instantiate the Copy Data tool functionality
with the File Loading behavior field set to Incremental load: time-partitioned
folder/file names. In this screen, once you start typing the input format using date
variables such as , the Options section expands to show the year format, month
format, and day format fields. You can select your preferred folder structure format
using the dropdowns and complete the rest of the flow. The following screenshot
shows an example of this:{year}/{month}/{day}
Figure 4.23 – ADF incremental load option with time-partitioned folders

Once you review the details and click Next on the Summary screen, the


incremental pipeline for partitioned data/folder structures will get deployed.

Agora aprendemos três métodos diferentes para realizar a cópia incremental.


Vamos explorar a seguir como selecionar o armazenamento de dados analíticos
correto para nossa camada de Serviço.

Projetando lojas analíticas


Os armazenamentos analíticos podem ser armazenamentos de dados SQL ou
NoSQL implantados na Zona de Servidão do data lake. O principal trabalho de um
armazenamento de dados analíticos é servir os dados gerados pelos pipelines de
transformação de dados para as ferramentas de BI de forma rápida e simples. Os
repositórios analíticos geralmente estão sujeitos a consultas ad hoc de analistas
de negócios e outros usuários finais. Como tal, essas lojas precisam ter um
desempenho muito bom com leituras aleatórias. O Azure fornece uma variedade
de tecnologias de armazenamento que podem atender a esses requisitos. Aqui
estão alguns dos mais importantes:

 Azure Synapse Analytics (pools SQL sem servidor/dedicados e pools Spark)


— o Synapse Analytics fornece pools SQL e pools Spark. Entre estes, os
pools dedicados SQL são data warehouses de processamento paralelo
massivo (MPP) e geralmente são ideais para a maioria das situações de
armazenamento analítico. Os pools SQL sem servidor podem ser usados
para consultas ad hoc. Os pools do Spark, por outro lado, podem oferecer
suporte a cargas de trabalho analíticas por meio de seu armazenamento na
memória e amplo suporte a columnstore. Ambos oferecem suporte a
interfaces do tipo SQL/SQL.
 Azure Databricks — o Azure Databricks é outra distribuição do Spark que
pode fornecer recursos limitados de armazenamento analítico por meio de
seus armazenamentos na memória e amplo suporte a columnstore. Ele
também suporta interfaces do tipo SQL.
 Azure Cosmos DB — o Cosmos DB fornece suporte para bancos de dados
de documentos, armazenamentos de chave-valor, repositórios de gráficos,
armazenamentos de colunas amplas e muito mais. Ele também suporta
interfaces SQL/SQL-like.
 Banco de Dados SQL do Azure/Banco de Dados SQL em máquinas
virtuais (VMs) personalizadas — o SQL do Azure fornece suporte a banco
de dados relacional e, é claro, dá suporte à interface SQL.
 HBase/Phoenix no HDInsight — fornece suporte a armazenamento analítico
por meio do armazenamento na memória e do amplo suporte a columnstore.
Ele também suporta interfaces SQL/SQL-like.
 Hive LLAP no HDInsight—Fornece suporte ao armazenamento analítico por
meio do armazenamento na memória. Ele também suporta interfaces
SQL/SQL-like.
 Azure Data Explorer—Fornece suporte a armazenamento relacional e séries
temporais. Ele também suporta interfaces SQL/SQL-like.
Há outros critérios, como segurança e escalabilidade, que você pode querer
considerar.

Considerações de segurança
Aqui está uma tabela de comparação de segurança de alto nível reproduzida da
documentação do Azure que pode ajudá-lo a decidir sobre o armazenamento
analítico certo para você:

Figura 4.24 – Comparação de segurança dos diferentes repositórios analíticos do


Azure

Vejamos a comparação de escalabilidade a seguir.


Considerações sobre escalabilidade
Aqui está outra tabela de comparação que pode ajudá-lo a decidir sobre um
armazenamento analítico com base em suas considerações de tamanho e
velocidade de dados:

Figure 4.25 – Scalability comparison of the different Azure analytical stores

You can learn more about analytical store selection criteria


here: https://docs.microsoft.com/en-us/azure/architecture/data-guide/technology-
choices/analytical-data-stores
Estamos quase no final deste capítulo. Na última seção, vamos explorar o que são
metastores e como configurá-los no Azure Synapse Analytics e no Azure
Databricks.

Criando metastores no Azure Synapse


Analytics e no Azure Databricks
Os metastores armazenam os metadados dos dados em serviços como o Spark
ou o Hive. Pense em um metastore como um catálogo de dados que pode dizer
quais tabelas você tem, quais são os esquemas de tabela, quais são as relações
entre as tabelas, onde elas são armazenadas e assim por diante. O Spark oferece
suporte a duas opções de metastore: uma versão na memória e uma versão
externa.

As metalojas na memória são limitadas em acessibilidade e escala. Eles


podem ajudar trabalhos em execução na mesma JVM (Java Virtual Machine),
mas não muito além disso. Além disso, os metadados são perdidos quando o
cluster é desligado.

Para todos os fins práticos, o Spark usa um metastore externo, e o único
metastore externo suportado no momento em que este livro foi o Hive Metastore.
O metastore do Hive é maduro e fornece interfaces de programação de
aplicativos (APIs) genéricas para acessá-lo. Assim, em vez de reconstruir um
novo metastore, o Spark usa apenas o metastore Hive maduro e bem projetado
para sua própria catalogação.

Vamos explorar os recursos de metastore disponíveis no Azure Synapse Analytics


e no Azure Databricks.

Azure Synapse Analytics


O Synapse Analytics oferece suporte ao compartilhamento de metadados entre
seus pools computacionais, como Spark e SQL. Os bancos de dados do Spark
e as tabelas externas criadas usando o formato Parquet podem ser facilmente
acessados a partir dos pools SQL.
Dois componentes principais de metadados podem ser compartilhados na versão
atual do Synapse: bancos de dados e tabelas. Vamos examiná-los em detalhes.

Bancos

Qualquer banco de dados criado usando o Spark SQL pode ser acessado
diretamente pelos pools SQL dedicados ou sem servidor no Synapse, desde que
ambos os pools tenham acesso em nível de armazenamento ao banco de dados
recém-criado.

Por exemplo, crie uma tabela no Spark executando o seguinte código: FactTrips

spark.Sql("CREATE DATABASE FactTrips")


CopyExplain

Em seguida, leia-o a partir do SQL, assim:

SELECT * FROM sys.databases;


CopyExplain

Você não precisa fazer nenhuma configuração; O Synapse torna automaticamente


os bancos de dados visíveis em seus pools de computação. Agora, vamos
examinar o outro componente de metadados que pode ser compartilhado na
versão atual do Synapse: tabelas.

Tabelas

Qualquer tabela baseada em Parquet que o Spark armazena no diretório é


compartilhada automaticamente com os pools SQL. warehouse

Qualquer tabela externa baseada em Parquet criada pelo Spark também pode ser
compartilhada com os pools SQL, fornecendo o local da tabela.

Azure Databricks (e Azure Synapse Spark)


Como vimos brevemente no Capítulo 2, Projetando uma estrutura de
armazenamento de dados, o Azure Databricks é a versão Databricks do Spark
hospedada no Azure. Ele está disponível como um serviço independente do Azure
e está bem conectado à maioria dos serviços do Azure. O Azure Databricks e o
Azure Synapse Spark usam o Hive Metastore como seu metastore externo.
Esses metastores externos permitem o acesso a dados entre diferentes clusters
do Spark e também entre outros computadores, como o Hive. Teoricamente,
qualquer serviço que possa conversar com o metastore do Hive e tenha os níveis
de acesso corretos pode ler os catálogos do Spark persistidos no metastore. O
metastore do Hive em si geralmente é implantado sobre um banco de dados SQL,
como o SQL do Azure. A configuração de um metastore externo do Hive é um
procedimento manual para Databricks e Synapse Spark. Há dois conjuntos de
configurações que você terá que configurar, um para o Spark e outro para o Hive.

No lado do Spark, ao criar um cluster, você só precisa adicionar os seguintes


parâmetros no campo Opções de configuração do Spark. Aqui, presumimos que
você já tenha um cluster do Hive e um banco de dados SQL do Azure (a ser
usado como o metastore) em funcionamento. Você pode optar por usar qualquer
banco de dados SQL, não necessariamente o SQL do Azure para o metastore.
Proceda da seguinte forma:

1. Especifique a cadeia de conexão JDBC (Java Database Connectivity) para


um metastore JDBC, da seguinte maneira:
spark.hadoop.javax.jdo.option.ConnectionURL <mssql-connection-string>
CopyExplain
2. Especifique o nome de usuário a ser usado para o metastore, da seguinte
maneira:
spark.hadoop.javax.jdo.option.ConnectionUserName <mssql-username>
CopyExplain
3. Especifique a senha a ser usada para o metastore, da seguinte maneira:
spark.hadoop.javax.jdo.option.ConnectionPassword <mssql-password>
CopyExplain
4. Especifique o nome da classe de driver para um metastore JDBC, da seguinte
maneira:
spark.hadoop.javax.jdo.option.ConnectionDriverName

com.microsoft.sqlserver.jdbc.SQLServerDriver
CopyExplain
5. Specify the Hive metastore version, as follows:
spark.sql.hive.metastore.version <hive-version>
CopyExplain
6. Specify the location of the metastore jars, Java ARchive (JAR) files, as
follows:
spark.sql.hive.metastore.jars <hive-jar-source>
CopyExplain

Note

A prefix is added to make sure these Hive-specific options propagate to the


metastore client.spark.hadoop

E no servidor Hive, atualize as seguintes configurações com os valores corretos:

1. Especifique a cadeia de conexão JDBC para um metastore JDBC, da


seguinte maneira:
javax.jdo.option.ConnectionURL <mssql-connection-string>
CopyExplain
2. Especifique o nome de usuário para o banco de dados metastore, da seguinte
maneira:
javax.jdo.option.ConnectionUserName <mssql-username>
CopyExplain
3. Especifique o banco de dados metastore de senha, da seguinte maneira:
javax.jdo.option.ConnectionPassword <mssql-password>
CopyExplain
4. Especifique o nome da classe do driver de conexão para o metastore JDBC,
da seguinte maneira:
javax.jdo.option.ConnectionDriverName com.microsoft.sqlserver.jdbc.SQLServerDriver
CopyExplain

Se suas versões do Spark/Hive não corresponderem às versões padrão


fornecidas pelo Azure, você precisará baixar a versão correta dos arquivos JAR e
carregá-los no espaço de trabalho. O link a seguir tem mais detalhes sobre
isso: https://docs.microsoft.com/en-us/azure/databricks/data/metastores/external-
hive-metastore.
Resumo
Isso encerra o nosso quarto capítulo. Parabéns por chegar até aqui.

Só para recapitular, começamos com o básico de modelagem de dados e


aprendemos sobre esquemas Star e Snowflake. Em seguida, aprendemos sobre
como projetar para SCDs, os diferentes subtipos de SCDs, hierarquias
dimensionais, lidar com dados temporais usando dimensões de tempo, carregar
dados incrementalmente usando ADF e selecionar o armazenamento analítico
correto com base nos requisitos do cliente. Finalmente, aprendemos sobre a
criação de metastores para Synapse e Azure Databricks. Todos esses tópicos
completam o conteúdo programático do DP203 – Design the Serving Layer. Agora
você aprendeu a criar sua própria camada de serviço no Azure.

Chegamos agora ao fim dos nossos capítulos de design. Vamos nos concentrar
nos detalhes da implementação a partir do próximo capítulo. Yay!

Capítulo 5: Implementando estruturas de


armazenamento de dados físicos
Espero que você tenha tido uma boa experiência de aprendizado até agora.
Vamos continuar nossa jornada em direção à certificação com tópicos mais
interessantes neste capítulo. Até o capítulo anterior, estávamos nos concentrando
nos aspectos de design, mas a partir de agora, estaremos nos concentrando nos
detalhes de implementação. Aprenderemos como implementar os conceitos de
nível de armazenamento que aprendemos nos capítulos anteriores. Depois de
concluir este capítulo, você deve ser capaz de decidir e implementar o seguinte:
que tipo de fragmentação de dados é necessária, quando compactar seus dados,
quantas partições criar, que tipo de redundância de dados manter e assim por
diante.

Abordaremos os seguintes tópicos neste capítulo:

 Introdução ao Azure Synapse Analytics


 Implementando a compactação

 Implementando o particionamento

 Implementando particionamento horizontal ou fragmentação

 Implementando distribuições

 Implementando diferentes geometrias de tabela com pools do Azure Synapse


Analytics

 Implementando redundância de dados

 Implementando o arquivamento de dados

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 Um espaço de trabalho Synapse ativo

Vamos começar a implementar!

Introdução ao Azure Synapse Analytics


A maioria dos exemplos neste capítulo será executada em um espaço de trabalho
do Azure Synapse Analytics, portanto, vamos ver como criar um. Proceda da
seguinte forma:

1. No portal do Azure, procure . Nos resultados, selecione Azure Synapse


Analytics.Synapse
2. Uma vez dentro, clique em + Criar e insira os detalhes para um novo espaço
de trabalho. A tela Criar espaço de trabalho Synapse é mostrada na
seguinte captura de tela:
Figura 5.1 – Criação do espaço de trabalho do Azure Synapse

3. Uma vez feito, clique no botão Revisar + criar e, finalmente, no


botão Criar nessa tela para criar um novo espaço de trabalho Synapse.

Esse espaço de trabalho nos fornecerá pools SQL (Structured Query


Language) e Spark, necessários para experimentar os vários conceitos que
aprendemos nos capítulos anteriores. Vamos começar implementando a
compactação na próxima seção.

Implementando a compactação
Nos capítulos anteriores, aprendemos sobre a importância da compactação de
dados em data lakes. À medida que o tamanho dos dados em data lakes aumenta,
torna-se importante que armazenemos os dados em um formato compactado para
economizar no custo. Há várias maneiras de implementar a compactação no
Azure. Existem muitas bibliotecas de compactação disponíveis no mercado e,
tecnicamente, tudo o que precisamos fazer é escrever alguns scripts para chamar
essas bibliotecas para compactar dados. Mas escrever scripts ad hoc traz sua
própria complexidade de manutenção, então vamos examinar algumas maneiras
fáceis de manter de implementar a compactação no Azure usando o Azure
Synapse Pipelines. O mesmo pode ser alcançado usando o Azure Data
Factory também. O Azure Synapse Pipelines é apenas a mesma implementação
do Azure Data Factory no Synapse Analytics.

Compactando arquivos usando Synapse Pipelines


ou ADF
No capítulo anterior, aprendemos sobre a ADF. Como o ADF, o Synapse Pipelines
pode ser usado para criar pipelines para fazer uma ampla gama de atividades,
como extrair, transformar, carregar (ETL), extrair, carregar,
transformar (ELT), copiar dados e assim por diante. O ADF e o Synapse
Pipelines oferecem suporte a várias dezenas de serviços como fontes de dados e
coletores, dentro e fora do Azure. Entre eles, serviços como o Armazenamento de
Blobs do Azure ou o Azure Data Lake Storage Gen2 (ADLS Gen2) oferecem
suporte à opção de compactar os dados antes de copiar. Vamos ver um exemplo
de leitura de arquivos descompactados e compactá-los antes de gravá-los de volta
no ADLS Gen2 usando Synapse Pipelines.

Proceda da seguinte forma:

1. Crie uma instância da ferramenta Copiar dados clicando no sinal +,


conforme mostrado na captura de tela a seguir:
Figura 5.2 – Selecionando a ferramenta Copiar dados no Synapse Pipelines

2. Na instância da ferramenta Copiar Dados, insira as


pastas Origem e Destino no armazenamento de dados do Azure.
3. Na página Configuração, você pode especificar uma opção Tipo de
compactação, conforme mostrado na captura de tela a seguir:
Figura 5.3 – Opções de tipo de compactação na página de armazenamento de
dados de destino da ferramenta Copiar Dados

4. Selecione uma das opções Tipo de compactação, preencha os outros


campos obrigatórios nas outras guias e, finalmente, clique em Publicar na
página Revisar e concluir para salvar essa instância da ferramenta Copiar
dados.
5. Em seguida, você pode acionar essa instância da ferramenta Copiar
Dados sob demanda ou configurar um gatilho recorrente para executar a
compactação em intervalos regulares a partir da tela de pipeline do ADF.

Isso é tão simples de configurar um trabalho de compactação regular usando


Synapse Pipelines (da mesma forma no ADF). Em seguida, vamos explorar como
compactar arquivos usando o Spark, que é um dos pools de computação
disponíveis no Synapse. Você também pode optar por usar o Azure Databricks
Spark. Os exemplos fornecidos aqui funcionarão bem com qualquer sabor de
Spark.

Compactando arquivos usando o Spark


O Spark fornece bibliotecas que podem gravar diretamente as saídas em formatos
compactados, como Parquet, ORC e assim por diante. Além disso, podemos
especificar os algoritmos de compressão a serem usados. Por exemplo, o
seguinte script Python armazena os dados no formato Parquet usando
compactação:gzip

columnNames = ["name","license","gender","salary"]

driverData = [

  ('Alice', 'A224455', 'Female', 3000),

  ('Bryan','B992244','Male',4000),

  ('Catherine','C887733','Female',4000)

df = spark.createDataFrame(data= driverData, schema = columnNames)

df.write.option("compression", "gzip"). parquet("abfss://path/to/output")


CopyExplain

Nota

O Spark oferece suporte a estas opções de compactação: , , , , e . Você pode


saber mais sobre as opções de compactação do Spark em
https://spark.apache.org/docs/latest/configuration.html. snappygziplzobrotlilz4zstd

Agora que aprendemos como compactar dados usando o ADF e o Spark, vamos
examinar as diferentes maneiras de particionar dados no Azure Synapse.

Implementando o particionamento
No Capítulo 3, Projetando uma estratégia de partição, abordamos os conceitos
básicos de particionamento. Nesta seção, vamos aprender como implementar os
diferentes tipos de particionamento. Começaremos com o particionamento em
armazenamentos de dados do Azure e, em seguida, examinaremos o
particionamento para cargas de trabalho analíticas.

Para particionamento baseado em armazenamento, a técnica principal é


particionar os dados na estrutura de pastas correta. Nos capítulos anteriores,
aprendemos sobre como armazenar os dados em um formato baseado em data. A
recomendação do Azure é usar o seguinte padrão:

{Region}/{SubjectMatter(s)}/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Vamos aprender a implementar a criação de pastas de forma automatizada


usando o ADF.

Usando pipelines ADF/Synapse para criar


partições de dados
Você pode usar ADF ou Synapse Pipelines, pois ambos usam a mesma tecnologia
ADF. Neste exemplo, estou usando Synapse Pipelines. Vejamos as etapas para
particionar dados de forma automatizada:

1. No espaço de trabalho Sinapse, selecione a guia Pipelines e selecione uma


atividade de fluxo de dados, conforme ilustrado na captura de tela a seguir:
Figura 5.4 – Selecionando a atividade de fluxo de dados em Synapse Pipelines

2. Clique duas vezes na atividade Fluxo de dados para revelar os


nós Origem e Destino.
3. Configure os detalhes de origem. Na guia Opções de origem, preencha o
campo Caminhos curinga, semelhante ao exemplo mostrado na captura de
tela a seguir:

Figura 5.5 – Inserindo informações de origem na atividade de fluxo de dados


4. Agora, clique no nó Destino e preencha os detalhes da pasta de destino,
conforme ilustrado na captura de tela a seguir:

Figura 5.6 – Inserindo informações de destino na atividade de fluxo de dados

5. O campo importante aqui é Caminho da pasta. Este campo aceita


expressões dinâmicas. Se você clicar na caixa de texto do caminho da pasta,
aparecerá uma ferramenta do Construtor de Expressões que pode ser
usada para criar expressões complexas que denotam o formato de arquivo
necessário.
6. Aqui está uma expressão de exemplo que pode ser usada para criar diretórios
de data:
"staging/driver/out/" + toString(year(currentDate()))  + "/" + toString(month(currentDate())) +

"/" + toString(dayOfMonth(currentDate()))
CopyExplain
7. Se a data atual for 1º de janeiro de 2022, a expressão anterior geraria uma
pasta como esta:
staging/driver/out/2022/01/01
CopyExplain
8. E no dia seguinte, uma nova pasta com a data seria criada, e assim por
diante.02
9. Quando terminar de adicionar o caminho da pasta, publique o pipeline e
acione-o.
É assim que podemos particionar e armazenar automaticamente os dados
recebidos. Vejamos a seguir as opções de particionamento disponíveis para
cargas de trabalho analíticas.

Particionamento para cargas de trabalho analíticas


No Capítulo 3, Projetando uma estratégia de partição, aprendemos sobre os três
tipos de particionamento para cargas de trabalho analíticas, que estão listados
novamente aqui:

 Particionamento ou fragmentação horizontal

 Particionamento vertical

 Particionamento funcional

Entre estas, as técnicas de particionamento horizontal ou fragmentação são de


natureza dinâmica e são feitas após a criação de esquemas. Eles geralmente são
executados regularmente durante o carregamento de dados ou durante a fase de
transformação de dados. As piscinas dedicadas Synapse e as piscinas Spark
oferecem várias opções para realizar o sharding. Dedicaremos uma seção
completa ao sharding em seguida.

O particionamento vertical ou funcional, por outro lado, é feito no momento da


construção do esquema. Esses tipos de particionamento envolvem descobrir o
conjunto correto de tabelas com base nas consultas e na distribuição de dados.
Depois de descobrirmos as tabelas necessárias com base em nossas
necessidades de negócios, a implementação envolve apenas a criação de várias
tabelas usando o comando e vinculando as tabelas usando uma restrição, como
uma restrição.CREATE TABLEFOREIGN KEY

Nota

No momento em que escrevo este livro, a restrição ainda não tem suporte em
pools SQL dedicados.FOREIGN KEY

Do ponto de vista da certificação, o sharding é mais importante, então vamos nos


concentrar nisso a seguir.
Implementando particionamento
horizontal ou fragmentação
Vamos explorar o sharding de duas perspectivas diferentes: um pool SQL
dedicado e o Spark. Basta notar que usaremos as terminologias particionamento
horizontal e fragmentação de forma intercambiável ao longo do livro, mas elas
significam a mesma coisa.

Compartilhamento em piscinas dedicadas


Synapse
Os pools dedicados do Synapse SQL têm três tipos diferentes de tabelas com
base em como os dados são armazenados, descritos a seguir:

 Armazenamento de colunas clusterizado

 Índice agrupado

 Heap

Aprenderemos mais sobre esses tipos de tabela mais adiante neste capítulo. Os


pools dedicados da Synapse suportam fragmentação para todos esses tipos de
tabela. Eles fornecem três maneiras diferentes de fragmentar os dados, da
seguinte maneira:

 Hash

 Rodízio

 Replicada

Esses métodos por meio dos quais um pool dedicado SQL distribui dados entre
suas tabelas também são chamados de técnicas de distribuição. As técnicas de
compartilhamento e distribuição são tecnologias sobrepostas que são sempre
especificadas juntas em instruções SQL.CREATE TABLE
Nota

O pool SQL dedicado por padrão particiona os dados em 60 distribuições. As


partições que especificamos adicionam explicitamente às partições que o pool
dedicado SQL já cria. Portanto, certifique-se de não acabar particionando demais
os dados, pois isso pode afetar negativamente o desempenho da consulta.

Vamos agora dar uma olhada em exemplos de como fragmentar dados em um


pool SQL dedicado.

Usando pools SQL dedicados para criar fragmentação

Os pools SQL dedicados têm uma opção chamada que pode ser usada durante o
processo de criação da tabela para definir como os dados devem ser
particionados. Vamos usar o mesmo exemplo base que usamos no Capítulo
2, Projetando uma estrutura de armazenamento de dados, para tentar o
particionamento. Procederemos da seguinte forma:PARTITION

1. Vamos criar uma tabela simples que particiona no campo, da seguinte


maneira:tripDate
2. CREATE TABLE dbo.TripTable

3. (

4.     [tripId] INT NOT NULL,

5.     [driverId] INT NOT NULL,

6.     [customerId] INT NOT NULL,

7.     [tripDate] INT,

8.     [startLocation] VARCHAR(40),

9.     [endLocation] VARCHAR (40)

10. )

11. WITH

12. (

13.     CLUSTERED COLUMNSTORE INDEX,


14.     DISTRIBUTION = HASH ([tripId]),

15.     PARTITION ([tripDate] RANGE RIGHT FOR VALUES

16.         ( 20220101, 20220201, 20220301 )

17.     )

)
CopyExplain
18. Insira alguns dados de exemplo na tabela, conforme mostrado no bloco de
código a seguir:
19. INSERT INTO dbo.TripTable VALUES (100, 200, 300, 20220101, 'New York', 'New

Jersey');

20. INSERT INTO dbo.TripTable VALUES (101, 201, 301, 20220101, 'Miami', 'Dallas');

21. INSERT INTO dbo.TripTable VALUES (102, 202, 302, 20220102, 'Phoenix', 'Tempe');

...
CopyExplain
22. Agora, vamos executar a consulta conforme mostrado na captura de tela a
seguir. Não se preocupe se você não entender os detalhes da consulta - ele
está apenas tentando obter os detalhes da partição em um formato fácil de
ler. Esta consulta pode ser encontrada na documentação do Synapse:
Figura 5.7 – Saída do comando partition

4. Como você pode ver na seção Resultados, quatro partições foram criadas.

Dois dos atributos usados ao definir a partição são e . Aprendemos sobre essas
palavras-chave no Capítulo 2, Projetando uma estrutura de armazenamento de
dados, enquanto aprendemos sobre a remoção de dados. Apenas para
recapitular, garante que o valor especificado na sintaxe pertencerá à partição do
lado direito e vice-versa para a palavra-chave. RANGE RIGHTRANGE LEFTRANGE
RIGHTPARTITIONRANGE LEFT

A seguir, vejamos as opções que o Spark oferece para fragmentação.

Compartilhamento usando o Spark


Por padrão, o Spark particiona dados com base no número de núcleos disponíveis
ou no número de blocos HDFS (Hadoop Distributed File System) (se estiver
sendo executado no HDFS). Se precisarmos particionar os dados em qualquer
outro formato personalizado, o Spark também fornece opções para isso. O Spark
suporta dois tipos de particionamento: particionamento na
memória e particionamento em disco. Vamos examinar esses dois tipos de
particionamento em detalhes.

Particionamento na memória

O Spark fornece os três métodos a seguir para executar o particionamento na


memória:

 repartition()—Para aumentar o número de partições.


 coalesce()—Para diminuir o número de partições.
 repartitionByRange()—Esta é uma especialização do comando onde você
pode especificar os intervalos.repartition

Vamos considerar um exemplo de snippet do Spark para entender esses três tipos
de partição, da seguinte maneira:

columnNames = ["name","license","gender","salary"]

driverData = [

  ('Alice', 'A224455', 'Female', 3000),

  ('Bryan','B992244','Male',4000),

  ('Catherine','C887733','Female',2000),

  ('Daryl','D229988','Male',3000),

  ('Jenny','J663300','Female', 6000)

df = spark.createDataFrame(data= driverData, schema = columnNames)

print("Default Partitions: " + str(df.rdd.getNumPartitions()))

repartitionDF = df.repartition(3)

print("Repartition Partitions: " + str(repartitionDF.rdd.getNumPartitions()))

coalesceDF=df.coalesce(2)

print("Coalesce Partitions: " + str(coalesceDF.rdd.getNumPartitions()))
repartitionRangeDF = df.repartitionByRange(1,'salary')

print("Range Partitions: " + str(repartitionRangeDF.rdd.getNumPartitions()))
CopyExplain

A saída do trecho de código anterior teria a seguinte aparência:

Default Partitions: 8

Repartition Partitions: 3

Coalesce Partitions: 2

Range Partitions: 1
CopyExplain

Como você pode ver, com cada um dos comandos de partição, o número de
partições é atualizado.

Agora que exploramos partições na memória no Spark, vamos examinar os


métodos de particionamento em disco.

Particionamento em disco

O Spark fornece o operador, que pode ser usado para particionar os dados e


armazená-los em diferentes arquivos enquanto grava a saída. Aqui está um trecho
de código de exemplo a ser executado. Este exemplo continua o exemplo da
seção Particionamento na memória:partitionBy()partitionBy()

df = spark.createDataFrame(data= driverData, schema = columnNames)

df.write.partitionBy("gender","salary")..parquet("abfss://path/to/output/")
CopyExplain

O trecho de código anterior criará duas pastas separadas, uma para e outra para .
A saída será como mostrado aqui:FemaleMale
Figura 5.8 – Saída do comando PartitionBy

Com isso, abordamos como podemos realizar o particionamento usando o Spark.


Agora, vamos passar para distribuições, que é um conceito relacionado a
partições em pools SQL dedicados.

Implementando distribuições
Um mecanismo dedicado de processamento paralelo massivo (MPP) do pool
SQL divide os dados em 60 partições paralelas e as executa em paralelo. Cada
uma dessas partições menores, juntamente com os recursos de computação para
executar as consultas, é chamada de distribuição. Uma distribuição é uma
unidade básica de processamento e armazenamento para um pool SQL dedicado.

Os pools SQL dedicados fornecem três opções de distribuição. Vejamos cada um


deles em detalhes.

Distribuição de hash
Esse tipo de distribuição distribui os dados com base em uma função de hash. As
linhas com os mesmos valores para a coluna com hash sempre serão movidas
para a mesma partição. Isso pode ser implementado fornecendo o valor na
cláusula do . Aqui está um exemplo:DISTRIBUTION = HASH (COLUMN_ID)WITHCREATE
TABLE

CREATE TABLE dbo.TripTable

    [tripId] INT NOT NULL,


    [driverId] INT NOT NULL,

    [customerID] INT NOT NULL,

    [tripDate] INT,

    [startLocation] VARCHAR(40),

    [endLocation] VARCHAR(40)

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = HASH ([tripId]),

    PARTITION ([tripDate] RANGE RIGHT FOR VALUES

        ( 20220101, 20220201, 20220301 )

    )

)
CopyExplain

Ponta

Use a distribuição de hash se o tamanho da tabela for maior que


2 gigabytes (GB) ou se a tabela tiver atualizações muito frequentes.

Distribuição de round-robin
Esse tipo de distribuição apenas distribui os dados aleatoriamente entre nós de
forma redonda. Ele pode ser implementado fornecendo o valor na cláusula de .
Aqui está um exemplo:DISTRIBUTION = ROUND_ROBINWITHCREATE TABLE

WITH

    CLUSTERED COLUMNSTORE INDEX,


    DISTRIBUTION = ROUND_ROBIN

    PARTITION (…)

)
CopyExplain

Escolha distribuições round-robin ao carregar dados em tabelas de preparo ou


quando não houver uma boa indexação para escolher.

Distribuição replicada
Esse tipo de distribuição apenas copia a tabela completa em todos os nós. Ele
pode ser implementado fornecendo o valor na cláusula de . Aqui está um
exemplo:DISTRIBUTION = REPLICATEWITHCREATE TABLE

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = REPLICATE

    PARTITION (…)

)
CopyExplain

Use para copiar dados pequenos, mas acessados com frequência, como tabelas
de catálogo de varejo, tabelas de gráfico de preços e assim por diante. REPLICATE

Espero que você tenha uma boa compreensão de fragmentação e distribuições


em um pool SQL Synapse. Agora que sabemos como implementar distribuições,
vamos aprender sobre os outros atributos das tabelas Synapse.
Implementando diferentes geometrias de
tabela com pools do Azure Synapse
Analytics
O termo geometria de tabela não é terminologia de banco de dados padrão,
portanto, estou dando um palpite de que a equipe de certificação se referia aos
diferentes recursos das tabelas de pool dedicadas do Azure Synapse.

Os principais recursos das tabelas de pool dedicadas


do Synapse são partições, índices e distribuições. Já cobrimos partições e
distribuições em detalhes, então vamos nos concentrar no recurso restante, que é
a indexação.

Os pools dedicados do SQL fornecem os três tipos de indexação a seguir:

 Indexação de columnstore clusterizado

 Indexação de heap

 Indexação clusterizada

Vamos examiná-los em detalhes.

Indexação de columnstore clusterizado


O columnstore clusterizado é a opção de indexação padrão de uma tabela de
pool SQL dedicada. Esse tipo de indexação funciona melhor para grandes tabelas
de fatos. É um armazenamento de dados baseado em colunas e fornece níveis
muito altos de compactação e melhor desempenho de consulta do que índices
baseados em linha.

Aqui está um exemplo de como criar uma tabela com indexação columnstore
clusterizada:

CREATE TABLE dbo.Driver


  (  

    [driverId] INT NOT NULL,  

        [name] VARCHAR(40),  

    . . .

  )  

WITH ( CLUSTERED COLUMNSTORE INDEX );


CopyExplain

Indexação de heap
As tabelas de heap são usadas como tabelas temporárias de carregamento de
dados, pois fornecem tempos de carregamento mais rápidos. Eles geralmente são
usados para dados de preparo antes de carregá-los em outras tabelas refinadas.
A indexação de heap funciona melhor para tabelas menores.

Aqui está um exemplo de como criar uma tabela com indexação de heap:

CREATE TABLE dbo.Driver

  (  

    [driverId] INT NOT NULL,  

    [name] VARCHAR(40),  

    . . .

  )  

WITH ( HEAP );
CopyExplain

Indexação clusterizada
As tabelas de índice clusterizadas são tabelas de armazenamento baseadas em
linha. Eles geralmente são mais rápidos para consultas que precisam de
pesquisas de linha com filtros altamente seletivos na coluna de índice clusterizada.
Aqui está um exemplo de como criar uma tabela com indexação clusterizada:

CREATE TABLE dbo.Driver

  (  

    [driverId] INT NOT NULL,  

    [name] VARCHAR(40),  

    . . .

  )  

WITH ( CLUSTERED INDEX (driverId) );


CopyExplain

Nota

Se o tamanho da tabela for menor que as 60 milhões de linhas recomendadas


para indexação de columnstore clusterizada, considere o uso de tabelas de índice
de heap ou clusterizadas.

Agora você aprendeu alguns dos recursos importantes das tabelas de pool
dedicadas do SQL, como particionamento, indexação e distribuições. Agora,
vamos analisar nosso próximo tópico: redundância de dados.

Implementando redundância de dados


A redundância de dados é o processo de armazenar várias cópias de dados em
locais diferentes, a fim de proteger os dados de eventos como falhas de energia,
falhas de disco, falhas de rede e até mesmo grandes catástrofes, como
paralisações inteiras do data center. O Armazenamento do Azure fornece várias
opções para redundância de dados nos níveis do data center local e entre data
centers. Podemos agrupar amplamente as opções nestas duas categorias:

 Redundância de região primária

 Redundância de região secundária

Vejamos essas opções em detalhes.


Redundância de armazenamento do Azure na
região primária
Esse tipo de redundância abrange falhas localizadas, como falhas de disco, falhas
de máquina e falhas de rack. Há dois tipos de redundância de região primária,
conforme detalhado a seguir.

Armazenamento localmente redundante (LRS)

Com esse tipo de redundância, os dados são copiados três vezes em várias
máquinas na mesma região física dentro de um data center. Essa opção fornece
proteção contra falhas locais, como falhas de disco, máquina ou rede local. Se
todas as três cópias de dados acabarem residindo no mesmo rack e se o rack
perder energia, podemos acabar perdendo os dados. Esta é a mais barata de
todas as opções de armazenamento redundante.

Armazenamento com redundância de zona (ZRS)

Esse tipo de redundância é semelhante ao LRS, mas os dados são copiados de


forma inteligente em várias zonas de disponibilidade (AZs). As AZs são regiões
locais dentro de um data center que têm diferentes fontes de alimentação e rede e
períodos de manutenção não sobrepostos. Isso garante que, mesmo que uma das
zonas esteja inativa, as outras zonas possam continuar servindo os dados. Esta
opção é mais cara do que o LRS.

Redundância de armazenamento do Azure em


regiões secundárias
Esse tipo de redundância fornece proteção de dados contra falhas importantes na
região geográfica, como interrupções totais do data center causadas por quedas
massivas de energia, terremotos, furacões e assim por diante. Com esse tipo de
redundância, junto com as cópias locais, uma cópia dos dados é armazenada em
um data center em um local geológico diferente. Se a região primária ficar inativa,
os aplicativos poderão fazer failover automático ou manual para a região
secundária. Há duas opções para redundância de região secundária, conforme
detalhado a seguir.

Armazenamento com redundância geográfica (GRS)

O GRS é basicamente uma configuração LRS nas regiões primária e secundária.


Os dados são gravados primeiro de forma LRS de forma síncrona na região
primária e, em seguida, uma cópia remota acontece de forma assíncrona na
região secundária. No local remoto, os dados são novamente replicados três
vezes usando o LRS local.

O Azure também fornece uma extensão somente leitura para o GRS chamada
GRS de acesso de leitura (RA-GRS). A única diferença é que a cópia remota é
uma cópia somente leitura nesse caso.

Geo ZRS (GZRS)

GZRS é ZRS na região primária e LRS na região secundária. Semelhante ao


GRS, as cópias locais são copiadas de forma síncrona e as remotas são copiadas
de forma assíncrona. O local remoto ainda mantém uma cópia LRS, mas não uma
ZRS. Essa é a opção de redundância de dados mais alta fornecida pelo Azure e,
não surpreendentemente, a mais cara também. Assim como o GRS, o GZRS
também fornece uma opção de cópia remota somente leitura chamada RA-GZRS.

Semelhante às opções de redundância de dados de armazenamento, há algumas


opções adicionais de redundância de dados especializados disponíveis para
serviços como Azure SQL, Synapse SQL, CosmosDB e outros serviços
semelhantes. Vejamos também brevemente a eles.

Replicação geográfica SQL do Azure


O SQL do Azure fornece um recurso chamado replicação geográfica ativa. Esse é
um recurso de redundância de dados que replica a instância completa do SQL
Server do Azure para os servidores secundários configurados em uma região de
backup geográfica diferente. Os servidores secundários servem como servidores
somente leitura e podem ser alternados para leitura-gravação durante failovers.
Os failovers podem ser iniciados programaticamente, reduzindo assim o tempo de
alternância durante falhas.

Você pode saber mais sobre a Replicação Geográfica Ativa do SQL do Azure
aqui: https://docs.microsoft.com/en-us/azure/azure-sql/database/active-geo-
replication-overview

Azure Synapse SQL Data Replication


O Azure Synapse faz backups geográficos em seus data centers emparelhados
(geralmente distribuídos geograficamente) a cada 24 horas, a menos que você
tenha optado por não participar desse recurso. Você pode restaurar de seus
backups geográficos para qualquer pool SQL Synapse em qualquer região se
essa região tiver suporte para pools SQL Synapse.

Você pode saber mais sobre a redundância de dados do SQL Pool do Azure aqui:

https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-warehouse/
backup-and-restore#geo-backups-and-disaster-recovery

Replicação de dados do CosmosDB


O CosmosDB é um banco de dados distribuído globalmente que replica seus
dados de forma transparente para os locais geográficos configurados. Ele fornece
latências muito baixas, permitindo leitura e gravação das réplicas locais do banco
de dados. Assim, apenas configurando o CosmosDB em várias localizações
geográficas você obtém redundância de dados.

O CosmosDB também faz backup automático de seus dados periodicamente.


Você pode usar os backups automáticos para recuperar em caso de exclusões
acidentais, atualização de sua conta do CosmosDB e assim por diante.

Você pode saber mais sobre a replicação global de dados do CosmosDB aqui:

https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally.

Nota
Nem todos os serviços ou regiões do Azure dão suporte a todas as quatro
redundâncias, portanto, leia sobre o suporte de redundância disponível para cada
serviço e planeje sua implantação de produto de acordo.

Agora, vamos ver como implementar a redundância no Armazenamento do Azure.

Exemplo de configuração de redundância no


Armazenamento do Azure
Ao criar uma nova conta de armazenamento, você pode escolher entre as quatro
opções de redundância de dados, conforme mostrado na captura de tela a seguir:

Figura 5.9 – Escolhendo a opção de redundância de dados durante a criação da


conta de armazenamento
Se desejar alterar a redundância após a criação do armazenamento, você ainda
poderá fazer isso na seguinte tela de configuração:

Figura 5.10 – Escolhendo a opção de redundância de dados após a criação da


conta de armazenamento

No entanto, alterar a redundância após a criação exigirá que você faça a migração


manual ou ao vivo. A migração manual refere-se ao processo de copiar os dados
para o novo armazenamento manualmente ou automatizá-los usando o ADF. Isso
geralmente resultará em tempo de inatividade do aplicativo.

Por outro lado, se você precisar que seus aplicativos estejam ativos durante a
migração, poderá solicitar uma migração ao vivo com o Suporte da Microsoft. Isso
pode resultar em algumas cobranças de suporte.

Implementando o arquivamento de
dados
No Capítulo 2, Projetando uma estrutura de armazenamento de dados, já
exploramos como projetar e implementar o arquivamento de dados. Aprendemos
sobre as camadas Quente, Fria e Arquivamento do armazenamento de dados e
como criar políticas de gerenciamento do ciclo de vida dos dados. Como já
abordamos os detalhes, não vamos repeti-los aqui. Consulte a seção Projetando
uma solução de arquivamento de dados do Capítulo 2, Projetando uma estrutura
de armazenamento de dados, novamente se você se esqueceu do arquivamento.

Resumo
Isso nos leva ao final deste capítulo. Espero que tenham gostado tanto quanto eu
gostei de escrevê-lo. Começamos aprendendo a compactar dados de forma limpa
usando Synaspe Pipelines e ADF, e nativamente usando Spark. Em seguida, nos
concentramos em aprender sobre como implementar particionamento,
fragmentação e distribuições em pools dedicados SQL e Spark. Depois disso,
aprendemos sobre os diferentes tipos de tabelas e indexação disponíveis em
pools dedicados SQL e, finalmente, concluímos aprendendo como configurar
redundância e arquivamento de dados.

Todos os tópicos anteriores devem abranger o conteúdo programático do DP203


– Implementar estruturas de armazenamento de dados físicos. Vamos nos
concentrar na implementação de estruturas lógicas de armazenamento de dados
no próximo capítulo.

Capítulo 6: Implementando estruturas de


dados lógicos
Espero que você tenha gostado de aprender sobre os detalhes de implementação
de estruturas de armazenamento. Neste capítulo, abordaremos os detalhes de
implementação de estruturas lógicas de dados. Você aprenderá a implementar
conceitos avançados de carregamento de dados, como dimensões que mudam
lentamente, soluções baseadas em armazenamento para otimizar o desempenho
da consulta e técnicas para ler dados externos sem precisar copiá-los para o
armazenamento local.
Abordaremos os seguintes tópicos neste capítulo:

 Criando uma solução de dados temporais

 Construindo uma dimensão em mudança lenta

 Criando uma estrutura de pastas lógica

 Implementando estruturas de arquivos e pastas para consultas e podas de


dados eficientes

 Construindo mesas externas

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 A CLI do Azure instalada em sua estação de trabalho

 Um espaço de trabalho Synapse ativo

Vamos começar!

Criando uma solução de dados


temporais
Dados temporais referem-se a dados em pontos específicos no tempo. A
construção de uma solução temporal lida com a construção de sistemas que
podem lidar e armazenar esses dados baseados no tempo. Já vimos como usar o
recurso de tabelas temporais do SQL do Azure para criar esse sistema
no Capítulo 4, Projetando a camada de serviço na seção: Projetando uma solução
para dados temporais. Como já exploramos esse tema em detalhes por lá, não
vamos repeti-lo novamente. Consulte o Capítulo 4 para refrescar sua memória
sobre tabelas temporais.
Vamos aprender a seguir como implementar uma dimensão que muda lentamente.

Construindo uma dimensão em mudança


lenta
No Capítulo 4, Projetando a camada de serviço, aprendemos sobre as diferentes
maneiras de criar dimensões que mudam lentamente (SCDs). Nesta seção,
aprenderemos a implementar alguns deles usando fluxos de mapeamento de
pipelines ADF/Synapse. Implementaremos o SCD Tipo 2, pois envolve um fluxo
de trabalho um pouco mais complicado. Uma vez que você saiba como
implementar um dos SCDs, implementar os outros será semelhante.

Vamos considerar o seguinte cenário de exemplo:

 Temos uma tabela de dimensões em um pool dedicado Synapse SQL que


contém os dados do driver. Esses dados não mudam com muita frequência,
por isso é uma boa escolha para um SCD. DimDriver
 Vamos supor que as alterações nos dados do driver apareçam
periodicamente como um arquivo CSV em uma pasta no Azure Data Lake
Gen2.
 Temos que criar um pipeline ADF para pegar os dados do arquivo CSV e
aplicá-los à tabela, mantendo seu histórico. DimDriver
 Criaremos a opção SCD baseada em bandeira neste exemplo.

Criar um pipeline no ADF é como construir as etapas de um fluxograma. Teremos


que levar os dados através de várias etapas para chegar ao resultado final
desejado. O exemplo de SCD a seguir será um pouco mais longo. Tentei explicar
cada passo para que seja fácil para você entender. Mas, se você achar difícil de
seguir, recomendo que você primeiro olhe para o Capítulo 8, Ingerindo e
transformando dados seção: Transformando dados usando o ADF para obter uma
boa compreensão das atividades do ADF. Essa seção tem muitos exemplos
menores de ADF que podem ajudá-lo a entender melhor o seguinte exemplo de
ADF.
Vejamos as etapas necessárias para o exemplo SCD2. Em alto nível, vamos
executar as seguintes etapas:

1. Se os dados de entrada forem para novos drivers, basta adicioná-los


diretamente à tabela Synapse SQL com coluna definida como
1.DimDriverisActive
2. Se os dados de entrada forem uma atualização de uma linha existente na
tabela, precisamos cuidar de duas condições:DimDriver

um. A primeira condição atualiza as linhas mais recentes do arquivo CSV como a
linha ativa para o correspondente, definindo a coluna como 1. DriverIdsisActive

b. A segunda condição atualiza todas as linhas anteriores para aquelas como


inativas, definindo a coluna como 0. DriverIdsisActive

A lógica anterior pode ser executada usando três fluxos separados dentro de um
fluxo de dados, um para as novas linhas e dois para as linhas modificadas.
Vejamos primeiro o caso das novas linhas.

Atualizando novas linhas


Aqui estão as etapas para criar o fluxo para atualizar as novas linhas:

1. O primeiro passo é criar um novo fluxo de dados, que pode ser usado para
encadear as etapas de transformação, também chamadas
de Atividades juntas. Clique no sinal + e escolha a opção Fluxo de
dados no ADF ou Synapse Studio, conforme mostrado:

Figura 6.1 – Criando um novo fluxo de dados em pipelines Synapse


2. A próxima etapa é criar um conjunto de dados de origem para nosso arquivo
CSV. Clique no link Adicionar Origem na região da tela Fluxo de dados,
conforme mostrado na imagem a seguir.

Figura 6.2 – Criando uma nova fonte de dados

3. Quando você clica em Adicionar Origem, uma nova tela de conjunto de


dados de Origem aparece. Nessa tela, você pode criar um novo conjunto de
dados usando o link + Novo, para apontar para a pasta CSV do driver de
entrada, conforme mostrado a seguir:
Figura 6.3 – Criação de conjunto de dados de entrada de amostra

4. Temos que criar um conjunto de dados Source semelhante para encontrar o


da tabela Synapse SQL. Ao criar um novo Dataset apontando para Synapse
SQL, temos que especificar a consulta a ser executada para buscar o max .
Usaremos esse valor posteriormente para distinguir as linhas recém-
adicionadas das linhas existentes na tabela. Aqui está uma captura de tela de
como especificar a consulta.MaxSurrogateIDDimDriversurrogateIdDimDriver
Figura 6.4 – Localizando o valor máximo das chaves substitutas

5. Agora, vamos adicionar o valor recém-calculado ao conjunto de dados do


driver CSV de entrada como uma nova coluna usando a atividade Ingressar,
conforme mostrado na captura de tela a seguir:maxSurrogate
Figura 6.5 – Adicionando a coluna MaxSurrogateID aos dados CSV de entrada

6. Agora que temos os dados do driver CSV, precisamos encontrar a lista de


todas as linhas modificadas vs linhas recém-adicionadas. Podemos usar uma
atividade de pesquisa entre o CSV do driver e a tabela SQL do Synapse para
conseguir isso. Aqui está uma captura de tela de como conseguir
isso:MaxSurrogateIDLEFT OUTER JOINDimDriver
Figura 6.6 – Usando LEFT OUTER JOIN para obter as linhas atualizadas

7. Na configuração Pesquisa anterior, eu teria usado uma tabela ligeiramente


modificada chamada ChangedNames para ingressar. Essa tabela é obtida
renomeando os nomes de coluna da tabela Synapse SQL. Isso é necessário,
pois as tabelas esquerda e direita para a junção terão exatamente os mesmos
nomes de coluna. Veja como podemos renomear os nomes das colunas
usando uma atividade Selecionar.DimDriverDimDriver
Figura 6.7 Alterando nomes de colunas usando a atividade Select

8. Agora que identificamos as linhas a serem atualizadas, vamos dividir o fluxo


de dados em duas ramificações usando a divisão condicional: uma que
cuida dos valores recém-adicionados e outra que atualiza as linhas
modificadas:
Figura 6.8 – Divisão do fluxo em duas ramificações – linhas novas e modificadas

9. Na ramificação NewRows, basta adicionar uma coluna , usando a atividade


Coluna Derivada. Alteraremos esse nome para pouco antes de atualizá-lo
para as tabelas SQL do Synapse na última atividade do Sink.
(isNewActive=1)isActive

Figura 6.9 – Adicionando a coluna isActive às linhas de entrada


10. Agora envie todas essas novas linhas com a coluna renomeada como , para o
destino usando uma atividade Coletor. Estamos usando um sinalizador
temporário para evitar colisões de nome de coluna. Você terá que desabilitar
o mapeamento automático e garantir que o mapeamento de campo seja feito
corretamente no Coletor SQL, conforme mostrado na imagem a
seguir:isNewActiveisActiveisNewActive

Figura 6.10 – Um exemplo de gravação no Sink, que é a tabela Synapse SQL no


nosso caso

Com isso, concluímos o fluxo para as linhas recém-adicionadas. Agora vamos


examinar as etapas para a ramificação de linhas modificada, aquela em que
dividimos condicionalmente a ramificação com base em NewRows vs
ModifiedRows (Figura 6.8).

Atualizando as linhas modificadas


Aqui estão as etapas para atualizar as linhas modificadas.

1. Para a ramificação de linhas modificadas, há duas subtarefas. As linhas


recém-atualizadas podem ser adicionadas diretamente com e as linhas
antigas para o correspondente precisam ser atualizadas com . Portanto,
precisamos dividir o conjunto de dados ModifiedRows em duas ramificações
usando a opção Nova ramificação. Clique no pequeno sinal + após a caixa
de atividade para obter a opção Nova ramificação, conforme
mostrado:isActive=1DriverIdsisActive=0

Figura 6.11 Criando uma nova ramificação

2. Em uma dessas ramificações, basta adicionar a coluna com valor 1 e gravá-la


na tabela Synapse Sink, semelhante ao que fizemos anteriormente para as
novas linhas (consulte a Figura 6.9). Isso deve cuidar da primeira subtarefa
de linhas modificadas.isActiveDimDriver
3. Agora, temos que fazer para as linhas anteriores com o mesmo . Para isso,
podemos adicionar uma atividade de coluna derivada para adicionar uma
coluna isActive a todas as linhas, seguida por uma atividade de filtro para
filtrar apenas as linhas antigas antes de gravar no coletor. Dessa forma, a
linha mais recente para esse , que foi atualizada na etapa anterior, não será
alterada. Aqui também, eu uso uma coluna temporária chamada para evitar
conflito de nome de coluna. Isso será alterado para isActive antes de gravá-lo
no coletor SQL.isActive=0driverIDDriverIdisOldRowActiveDimDriver
Figura 6.12 Adicionando uma coluna extra usando coluna derivada

4. Agora filtre as linhas antigas, usando a condição, conforme


mostrado:Dim_surrogateId <= MaxSurr

Figura 6.13 – Filtrando somente as linhas antigas


5. Use uma etapa para atualizar somente as linhas cujas IDs substitutas são
menores que o valor máximo de substituição no Synapse SQL usando uma
atividade Sink:Alter row

Figura 6.14 – Alteração do número de linhas ao usar o valor MaxSurr como


referência

6. Veja como será a configuração do coletor:

Figura 6.15 Configuração do Synapse SQL Sink


7. Por fim, configure um pipeline e acione-o para executar o fluxo de dados
periodicamente. Seu pipeline do ADF deve ser semelhante ao seguinte:

Figura 6.16 – Exemplo de pipeline de ADF para SCD 2

É assim que construímos SCDs usando Synapse Pipelines (ou ADF). Você pode
achar difícil seguir todos os passos na primeira vez. Portanto, tente ler esta seção
novamente depois de concluir o Capítulo 8, Ingestão e transformação de dados,
que tem mais exemplos de pipelines ADF/Synapse.

Agora, vamos aprender a implementar estruturas de pastas lógicas.

Criando uma estrutura de pastas lógica


Aprendemos sobre estruturas de pastas eficientes no Capítulo 2, Projetando uma
estrutura de armazenamento de dados, onde exploramos as
práticas recomendadas para armazenar dados para processamento em lote e
cenários de streaming. A regra prática é armazenar os dados em uma estrutura de
pasta de data hierárquica, com a parte de data adicionada no final, conforme
mostrado aqui:

{Region}/{SubjectMatter(s)}/{yyyy}/{mm}/{dd}/{hh}/
CopyExplain

Podemos ter mais pastas intermediárias no caminho da pasta com base em


nossos requisitos de negócios. Consulte o Capítulo 2, Projetando uma estrutura
de armazenamento de dados, para atualizar sua memória sobre como projetar
estruturas de pastas eficientes.

Para criar um contêiner no Azure Data Lake Gen 2, você pode usar o seguinte
comando por meio da CLI do Azure:
az storage fs create -n <container name> --account-name <account name> --auth-mode login
CopyExplain

Depois de criar um contêiner, você pode facilmente criar pastas nele usando o
seguinte comando:

az storage fs directory create -n <folder path> -f <container name> --account-name <account name>

--auth-mode login
CopyExplain

Você também pode usar ferramentas de interface do usuário, como o portal de


Armazenamento do Azure ou o Gerenciador de Armazenamento do Azure, para
criar a estrutura de pastas.

Como já abordamos esse tópico em detalhes nos capítulos anteriores, vamos


seguir em frente e ver quais estruturas de dados podemos usar para consultas e
podas eficazes.

Implementando estruturas de arquivos e


pastas para consultas e podas de dados
eficientes
Os conceitos que exploramos na seção anterior também se aplicam aqui. Uma vez
que tenhamos uma estrutura de pastas hierárquica baseada em data, o
desempenho da consulta pode ser melhorado por meio do particionamento de
dados. Se dividirmos os dados em partições e se garantirmos que as partições
sejam armazenadas em diferentes estruturas de pastas, as consultas podem
ignorar completamente a varredura das partições irrelevantes. Esse conceito,
como já sabemos, é chamado de poda de dados.

Outro benefício do particionamento é o aumento da eficiência do carregamento e


exclusão de dados, realizando a comutação de partições e a exclusão de
partições. Aqui, em vez de ler cada linha e atualizá-la, enormes partições de
dados podem ser adicionadas ou excluídas com operações de metadados
simples. O capítulo 2, Projetando uma estrutura de armazenamento de dados, já
abordou exemplos de como as consultas podem se beneficiar da remoção de
dados ignorando a leitura de partições desnecessárias. Nesta seção,
aprenderemos como melhorar o desempenho de carga e descarga de dados por
meio da comutação de partições.

Nota

As partições devem estar perfeitamente alinhadas nos limites para a comutação


de partições.

Vamos considerar o mesmo exemplo de tabela de fatos que temos usado até
agora:

CREATE TABLE dbo.TripTable

    [tripId] INT NOT NULL,

    [driverId] INT NOT NULL,

    [customerId] INT NOT NULL,

    [tripDate] INT,

    [startLocation] VARCHAR (40),

    [endLocation] VARCHAR (40)

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = HASH ([tripId]),

    PARTITION ([tripDate] RANGE RIGHT FOR VALUES

        ( 20220101, 20220201, 20220301 )

  )

)
CopyExplain

Vamos supor que precisamos armazenar apenas 3 meses de dados. Nossa tabela
Fatos, , contém os dados de , e . Agora, vamos aprender como excluir os dados
do primeiro mês e adicionar os dados do último mês, , à
tabela.dbo.TripTable20220101202202012022030120220401

Excluindo uma partição antiga


Para excluir uma partição, precisamos criar uma tabela fictícia que tenha a mesma
estrutura da tabela original e, em seguida, trocar a partição pela tabela fictícia.
Esta seção mostrará como alternar a partição.20220101

Crie uma tabela fictícia que contenha a partição que precisa ser alternada, da
seguinte maneira:

CREATE TABLE dbo.TripTable_20220101

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = HASH ([tripId]),

    PARTITION ([tripDate] RANGE RIGHT FOR VALUES (20220101) )

  )

AS

SELECT * FROM dbo.TripTable WHERE 1=2 ;


CopyExplain

Observe que para alternar tabelas temporárias, podemos ter apenas uma partição
que estamos planejando sair. é a segunda partição, uma vez que a primeira
partição corresponderá a todos os valores anteriores , que, no nosso caso,
estariam vazios. Execute o comando, conforme mostrado no bloco de código a
seguir, para trocar a partição:2022010120220101ALTER TABLE
ALTER TABLE dbo.TripTable SWITCH PARTITION 2 TO dbo.TripTable_20220101 PARTITION

2 WITH (TRUNCATE_TARGET = ON);


CopyExplain

Agora, conterá 0 linhas para a partição 2, que corresponde


a .dbo.TripTable20220101

Em seguida, vamos adicionar uma nova partição, , à tabela. 20220401

Adicionando uma nova partição


Para adicionar nossa nova partição, precisamos dividir a última partição em duas
partições. Podemos usar o seguinte comando para fazer isso: SPLIT

ALTER TABLE dbo.TripTable SPLIT RANGE (20220401);


CopyExplain

Isso dividirá a última partição em e .2022030120220401

Nota

A divisão não funcionará se a partição contiver dados. Assim, teremos que trocar
temporariamente a última partição por uma tabela fictícia, como fizemos
anteriormente na seção Excluindo uma partição antiga. Quando a última partição
estiver vazia, divida essa partição usando o comando e, em seguida, adicione a
partição temporariamente trocada de volta à tabela original. split

Depois de criarmos a nova partição para , devemos criar uma tabela fictícia com o
mesmo alinhamento de partição para carregar os dados. O seguinte trecho de
código faz isso:2022040120220401

CREATE TABLE dbo.TripTable_new

WITH

    CLUSTERED COLUMNSTORE INDEX,


    DISTRIBUTION = HASH ([tripId]),

    PARTITION ([tripDate] RANGE RIGHT FOR VALUES

        (20220101, 20220201, 20220301, 20220401)

  )

AS

SELECT * FROM dbo.TripTable WHERE 1 = 2;


CopyExplain

Para fins deste exemplo, vamos adicionar alguns valores à nova partição:

INSERT INTO dbo.TripTable_new

VALUES (333, 444, 555, 20220401, "New York", "New Jersey");


CopyExplain

Depois de carregarmos os dados da partição na tabela fictícia, podemos alternar a


partição para nossa tabela Fact usando o comando, como mostrado no bloco de
código a seguir. Este comando alternará a última partição de abril () para a
original:ALTER20220401TripTable

ALTER TABLE dbo.TripTable_new SWITCH PARTITION 5 TO dbo.TripTable PARTITION 5

WITH (TRUNCATE_TARGET = ON);


CopyExplain

Esses comandos retornarão quase imediatamente, pois são operações de


metadados e não envolvem a cópia de linhas de uma partição para outra. E é
assim que podemos aumentar a eficiência das operações de carga e exclusão de
dados. Você pode consultar o exemplo completo no repositório GitHub deste
livro.ALTER TABLE

Vejamos a seguir o acesso a dados usando tabelas externas.

Construindo mesas externas


As tabelas externas são semelhantes às tabelas regulares, exceto que os dados
são armazenados em locais de armazenamento externo, como Azure Data Lake,
armazenamento de Blobs do Azure e HDFS. Com tabelas externas, você não
precisa copiar dados em tabelas internas para processamento. Eles podem ler
diretamente os dados de fontes externas, o que economiza no custo de
transferência de dados. No Synapse, tanto o SQL dedicado quanto o SQL sem
servidor oferecem suporte a tabelas externas. Temos que definir os três construtos
a seguir para acessar dados por meio de tabelas externas:

 FONTE DE DADOS EXTERNA

Aqui está um exemplo de como podemos criar uma fonte de dados externa
chamada :users_iacstoreacct

CREATE EXTERNAL DATA SOURCE [Dp203DataSource]

WITH ( LOCATION  = 'abfss://path/to/data')


CopyExplain
 FORMATO DE ARQUIVO EXTERNO

Aqui está um exemplo de como criar um formato de arquivo externo


chamado :SynapseParquetFormat

CREATE EXTERNAL FILE FORMAT [Dp203ParquetFormat]

WITH ( FORMAT_TYPE = PARQUET )


CopyExplain
 TABELA EXTERNA

Podemos usar a fonte de dados externa e o formato de arquivo externo para criar
a tabela externa:

CREATE EXTERNAL TABLE TestExtTable (

[tripId] INT,

[driverId] INT,

...

[endLocation] VARCHAR (50)


)

WITH (

LOCATION = '/path/to/*.parquet',

DATA_SOURCE = [Dp203DataSource],

FILE_FORMAT = [Dp203ParquetFormat]

)
CopyExplain

Você também pode criar facilmente tabelas externas a partir da interface do


usuário do Synapse, conforme mostrado na captura de tela a seguir:

Figura 6.17 – Um exemplo de criação de uma tabela externa a partir da interface


do usuário do Synapse

Na tela exibida, você precisa fazer o seguinte:

1. Selecione Pool SQL.
2. Insira um nome para o banco de dados a ser criado.
3. Insira um nome para a tabela externa a ser criada.

Figura 6.18 – Especificação dos detalhes para a tabela externa

Depois de clicar em Abrir script, o Synapse irá gerar automaticamente o script


SQL para criar tabelas externas.

Resumo
Isso nos leva ao final deste capítulo. Este foi um capítulo menor, mas que tinha
alguns conceitos muito importantes do ponto de vista da certificação. Começamos
analisando a construção de SCDs, que era um processo demorado, mas
relativamente fácil, pois na maioria das vezes tínhamos que apenas arrastar e
soltar os componentes em pipelines Synapse e configurá-los. Em seguida,
revisitamos a regra geral para a criação de uma estrutura de pastas eficiente.
Também aprendemos como alternar partições rapidamente usando o Synapse
SQL. Finalmente, aprendemos como é fácil criar tabelas externas no Synapse.
Todos os tópicos que foram abordados neste capítulo devem abranger o programa
de DP203 – Implementando as estruturas lógicas de dados. No próximo capítulo,
vamos nos concentrar na implementação da camada de serviço.

Capítulo 7: Implementando a camada de


serviço
Espero que você tenha gostado de aprender sobre os detalhes de implementação
das estruturas de dados lógicos no capítulo anterior. Neste capítulo,
aprenderemos sobre a implementação da camada de serviço, que envolve a
implementação de esquemas em estrela, técnicas para ler e gravar diferentes
formatos de dados, compartilhamento de dados entre serviços como SQL e Spark
e muito mais. Depois de concluir este capítulo, você deve ser capaz de entender
as diferenças entre um pool SQL dedicado do Synapse versus sistemas SQL
tradicionais para implementar o esquema Star, as várias maneiras de acessar
dados do Parquet usando tecnologias como Spark e SQL e os detalhes envolvidos
no armazenamento de metadados entre serviços. Todo esse conhecimento deve
ajudá-lo a construir uma camada de serviço prática e sustentável em um data lake
e, claro, limpar a certificação também.

Abordaremos os seguintes tópicos neste capítulo:

 Entregando dados em um esquema de estrela relacional

 Implementando uma hierarquia dimensional

 Entregando dados em arquivos Parquet

 Mantendo metadados

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)


 Um espaço de trabalho Synapse ativo

Vamos começar.

Entregando dados em um esquema de


estrela relacional
Havíamos aprendido sobre o esquema estelar no Capítulo 4, Projetando a
Camada de Serviço. Vamos pegar o mesmo exemplo aqui e mostrar como
implementar um esquema estrela no Synapse SQL e entregar dados a partir dele.

Os esquemas em estrela têm dois tipos de tabelas, tabelas de fatos e tabelas


dimensionais. As tabelas de fatos geralmente são muito mais volumosas do que
as tabelas de dimensão e, portanto, se beneficiariam do uso de uma distribuição
de hash com indexação columnstore clusterizada. Por outro lado, as tabelas de
dimensão são menores e podem se beneficiar do uso de tabelas replicadas.

Observação importante

Os pools SQL dedicados do Synapse não ofereciam suporte a restrições de chave


estrangeira no momento em que este livro foi escrito. Assim, a responsabilidade
de manter a integridade dos dados recai sobre os aplicativos.

Vamos considerar o mesmo exemplo de passeios de táxi Imaginary Airport


Cabs (IAC) para o nosso esquema de estrelas do Capítulo 4, Projetando a
Camada de Serviço. Tínhamos as seguintes tabelas nesse projeto:

 FactTrips
 DimDriver
 DimCustomer
 DimCab
 DimDate

Vamos ver como implementar essas tabelas.


1. Na tela Synapse, crie um novo pool SQL na guia Gerenciar, conforme
mostrado na captura de tela a seguir. Clique no símbolo +Novo e preencha
os detalhes para criar um novo pool SQL dedicado.

Figura 7.1 – Criando um novo pool SQL dedicado

2. Em seguida, crie um novo script SQL na guia Editor clicando no sinal +,


conforme mostrado na próxima captura de tela:

Figura 7.2 – Criando um novo script SQL

3. No editor SQL, você pode inserir comandos SQL para criar tabelas que
representam o esquema em estrela. Aqui está um exemplo de como criar
uma tabela de fatos de exemplo, :FactTrips
4. CREATE TABLE dbo.FactTrips
5. (

6.     [tripId] INT NOT NULL,

7.     [driverId] INT NOT NULL,

8.     [customerId] INT NOT NULL,

9.     [tripdate] INT,

10.     [startLocation] VARCHAR(40),

11.     [endLocation] VARCHAR(40)

12. )

13. WITH

14. (

15.     CLUSTERED COLUMNSTORE INDEX,

16.     DISTRIBUTION = HASH ([tripId])

)
CopyExplain

Aqui está um exemplo de uma tabela de dimensão do cliente de exemplo:

CREATE TABLE dbo.DimCustomer

    [customerId] INT NOT NULL,

    [name] VARCHAR(40) NOT NULL,

    [emailId] VARCHAR(40),

    . . .

    [city] VARCHAR(40)

WITH

    CLUSTERED COLUMNSTORE INDEX,
    DISTRIBUTION = REPLICATE

)
CopyExplain

Aqui está um exemplo de uma tabela de dimensão de data:

CREATE TABLE dbo.DimDate

    [dateId] INT NOT NULL,

    [date] DATETIME NOT NULL,

    [dayOfWeek] VARCHAR(40),

    [fiscalQuarter] VARCHAR(40)

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = REPLICATE

)
CopyExplain
4. Agora, vamos ver como carregar dados nessas tabelas. Você pode usar a
instrução para preencher as tabelas. As tabelas de fato e dimensão terão a
mesma sintaxe para carregar informações: COPY INTO
5. COPY INTO dbo.DimCustomer

6. FROM 'https://path/to/customer.csv'

7. WITH (

8.     FILE_TYPE='CSV',

9.     FIELDTERMINATOR=',',

10.     FIELDQUOTE='',

11.     ROWTERMINATOR='\n',
12.     ENCODING = 'UTF8',

13.     FIRSTROW = 2 // To skip the header line

)
CopyExplain
14. E, finalmente, consulta a partir das tabelas de esquema em estrela. Aqui está
um exemplo de consulta para obter a lista de todos os clientes cujo local final
foi:'San Jose'
15. SELECT trip.[tripId], customer.[name] FROM 

16. dbo.FactTrips AS trip

17. JOIN dbo.DimCustomer AS customer

18. ON trip.[customerId] = customer.[customerId] 

WHERE trip.[endLocation] = 'San Jose';
CopyExplain

Como você pode ver, uma vez que entendemos o conceito de esquemas em
estrela, criá-los é tão simples quanto criar tabelas no Synapse SQL.

Você pode aprender mais sobre Synapse SQL e esquemas


aqui: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/sql-data-warehouse-tables-overview.

Vejamos a seguir a implementação de uma hierarquia dimensional.

Implementando uma hierarquia


dimensional
Como já exploramos a hierarquia dimensional no Capítulo 4, Projetando a camada
de serviço na seção Projetando uma hierarquia dimensional, não a repetiremos
aqui. Por favor, dê uma olhada no Capítulo 4 para atualizar sua compreensão da
hierarquia dimensional.

Vamos a seguir examinar as técnicas disponíveis para ler e gravar dados em


arquivos Parquet.
Entregando dados em arquivos Parquet

Nesta seção, aprenderemos a fornecer dados que estão presentes em arquivos


Parquet via Synapse SQL e Spark. Usaremos o conceito de tabelas externas que
aprendemos no capítulo anterior para conseguir isso.

Vamos considerar um exemplo onde temos os dados armazenados como


arquivos Parquet. Usaremos os pools sem servidor Synapse SQL e o Spark para
acessar os dados e executar algumas consultas de exemplo neles. trips

Synapse SQL sem servidor


Vamos criar uma tabela externa de dentro do editor de consultas Synapse SQL
que aponta para os arquivos Parquet no armazenamento do Azure. A captura de
tela a seguir mostra um exemplo:

Figura 7.3 – Criando tabelas externas do pool SQL


Agora, vamos executar uma consulta de exemplo, como uma ferramenta de BI
acessaria esses dados. Vamos tentar encontrar o número de viagens por local a
partir dos dados carregados na etapa anterior e visualizá-lo como um gráfico:

Figura 7.4 – Exemplo de consulta em dados do Parquet visualizados como um


gráfico

Você precisa selecionar a opção Gráfico na tela Resultados para exibir os


gráficos. O Synapse SQL fornece várias opções para configurar os gráficos, como
mostrado no lado direito da imagem anterior.

Como você pode ver, ler e servir dados de arquivos Parquet é tão simples quanto
definir uma tabela externa e consultá-la.

Você pode aprender mais sobre como usar tabelas externas no Synapse SQL
aqui: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql/develop-tables-
external-tables.

Agora, vamos tentar o mesmo exercício usando o Spark.

Sinapse Faísca
Em um Synapse Spark Notebook, você pode ler arquivos Parquet usando o
comando. A captura de tela a seguir mostra um
exemplo:spark.read.load('path/to/parquet/files', format='Parquet')

Figura 7.5 – Usando o Spark para consultar arquivos do Parquet

O Spark também fornece opções de gráficos, conforme mostrado na imagem


anterior.

Vamos explorar a seguir como podemos fazer o mesmo usando o Azure


Databricks.

Azure Databricks
Os exemplos do Spark do Azure Databricks são semelhantes aos exemplos
do Synapse Spark. No caso do Azure Databricks, você precisará definir
uma entidade de serviço para o Azure Databricks para conversar com o Azure
Data Lake Storage Gen2.

Você pode encontrar informações detalhadas sobre como configurar a entidade de


serviço aqui: https://docs.microsoft.com/en-us/azure/databricks/scenarios/
databricks-extract-load-sql-data-warehouse.

Depois de configurar a sessão, você pode usar exatamente a mesma sintaxe do


Spark que vimos no caso de uso do Synapse Spark aqui também. A seguir está
um exemplo para exibir o conteúdo de todos os arquivos Parquet na
pasta:parquet/trips

Figura 7.6 – Bloco de anotações do Azure Databricks com o exemplo de acesso


do Azure Data Lake Storage Gen2

Aqui está um exemplo da mesma consulta de transformação que executamos


anteriormente no Synapse Spark, no Databricks:
Figura 7.7 – Consulta do Simple Spark nos dados do Parquet

O Azure Databricks também fornece um conjunto avançado de opções de gráficos


que podem ser usados para visualizar os dados. Você pode acessar as opções de
gráficos clicando no ícone Gráfico abaixo dos resultados.

Você pode aprender mais sobre como usar o Spark e o Parquet


aqui: https://spark.apache.org/docs/latest/sql-data-sources-parquet.html.

Espero que agora você tenha uma ideia de como servir dados do Parquet usando
os serviços SQL e Spark no Azure. Em seguida, vejamos as opções de
metadados disponíveis no Azure.

Mantendo metadados
Como vimos no Capítulo 4, Projetando uma estratégia de partição, os metastores
são como catálogos de dados que contêm informações sobre todas as tabelas que
você tem, os esquemas de tabela, as relações entre eles, onde eles são
armazenados e assim por diante. Nesse capítulo, aprendemos em alto nível sobre
como acessar os metadados no Synapse e no Databricks. Agora, vamos aprender
os detalhes de implementá-los.

Metadados usando pools Synapse, SQL e Spark


O Synapse oferece suporte a um modelo de metadados compartilhados. Os
bancos de dados e tabelas que usam formatos de armazenamento Parquet ou
CSV são compartilhados automaticamente entre os pools de computação, como
SQL e Spark.

Observação importante

Os dados criados a partir do Spark só podem ser lidos e consultados por pools
SQL, mas não podem ser modificados no momento em que este livro foi escrito.

Vejamos um exemplo de criação de um banco de dados e uma tabela usando o


Spark e acessando-o via SQL:

1. No bloco de anotações Synapse Spark, crie uma tabela de exemplo,


conforme mostrado na captura de tela a seguir:

Figura 7.8 – Criando uma tabela de exemplo no Spark

2. Agora, vamos consultar o conteúdo da tabela do pool sem servidor do SQL.

Observação importante
Esse banco de dados será sincronizado de forma assíncrona, portanto, pode
haver um pequeno atraso antes que você veja os bancos de dados e tabelas
no pool SQL.

3. O pool sem servidor do SQL é um serviço sob demanda, então tudo o que
você precisa fazer é apenas clicar no sinal + na página do espaço de trabalho
Synapse e selecionar o script SQL para criar um novo editor SQL,
conforme mostrado na captura de tela a seguir:

Figura 7.9 – Criando um novo script SQL

4. Em seguida, no campo Conectar a, selecione o pool interno, conforme


mostrado na captura de tela a seguir:

Figura 7.10 – Conectando-se ao pool SQL sem servidor

5. Agora, basta executar um script simples para consultar a tabela


compartilhada; No exemplo, a tabela compartilhada seria a tabela: tripID
Figura 7.11 – Acessando a tabela Spark no SQL

Como você acabou de notar, o modelo de dados compartilhados do Synapse


facilita muito o compartilhamento de dados entre pools SQL e Spark. Tudo já é
cuidado pela Synapse e os dados são prontamente disponibilizados para nós.

Você pode saber mais sobre como manter metadados no Synapse


aqui: https://docs.microsoft.com/en-us/azure/synapse-analytics/metadata/overview.

Vamos explorar a seguir como trabalhar com metastores no Azure Databricks.

Metadados usando o Azure Databricks


Para compartilhar dados entre o Spark e outros serviços fora do Synapse, temos
que fazer uso do metastore do Hive. O Spark usa o metastore do Hive para
compartilhar informações com outros serviços. Vejamos um exemplo de
compartilhamento de dados entre o Azure Databricks Spark e o Azure HDInsight
Hive. A lógica e as etapas para usar um metastore externo do Hive também
seriam semelhantes para o Synapse Spark. Aqui estão os passos:

1. Precisaremos de um banco de dados autônomo que possa ser usado pelo


Spark para armazenar os metadados. Vamos usar o SQL do Azure para essa
finalidade. Crie um banco de dados SQL do Azure no portal do Azure.
Procure SQL do Azure na caixa de pesquisa do portal e selecione-o. Clique
na opção + Criar. Você verá uma tela, como mostrado na captura de tela a
seguir:

Figura 7.12 – Planos SQL do Azure

2. Selecione a caixa Bancos de dados SQL e clique na opção Banco de


dados único na lista suspensa.
3. Você pode criar o banco de dados com dados de exemplo pré-preenchidos
para que tenhamos dados prontos para experimentação. Selecione a
opção Exemplo para o campo Usar dados existentes, conforme mostrado
na captura de tela a seguir:
Figura 7.13 – Preenchendo o banco de dados com dados de exemplo

4. Preencha o restante das guias e clique em Revisar + criar para criar o banco


de dados SQL do Azure.
5. Recupere a cadeia de conexão JDBC da guia Cadeias de Conexão, conforme
mostrado na captura de tela a seguir, e salve-a no Bloco de Notas.
Precisaremos dessas informações mais adiante:
Figura 7.14 – Obtendo as cadeias de conexão para o SQL do Azure

6. Em seguida, temos que criar um cluster Hive HDInsight. A essa altura, talvez


você já conheça o processo para instanciar qualquer serviço do Azure. Basta
procurar o HDInsight na barra de pesquisa do portal e clicar nele. Na home
page do portal HDInsight, clique no link + Criar para abrir o formulário de
criação e preencher os detalhes.
7. Na tela Criar cluster HDInsight, você pode escolher a opção Hadoop ou a
opção Consulta Interativa para tipo de cluster, pois ambos instalarão o
Hive. Consulte a próxima captura de tela para obter as opções disponíveis:
Figura 7.15 – Selecionando o tipo de cluster para clusters HDInsight

8. Depois de selecionar o tipo de cluster, preencha o restante dos campos na


tela Básico.
9. Na guia Armazenamento, na seção Repositórios de metadados externos,
forneça o banco de dados SQL do Azure que criamos nas etapas anteriores
como banco de dados SQL para o Hive. A captura de tela a seguir mostra o
local:
Figura 7.16 – Criando um cluster do Hive no HDInsight com o SQL do Azure como
metastore

10. Preencha o restante dos campos e clique em Revisar + Criar para criar o


cluster HDInsight.
11. Depois que o cluster for criado, vá para a home page do Ambari no portal
HDInsight clicando no link inicial do Ambari, conforme mostrado na captura
de tela a seguir:
Figura 7.17 – Link para a página inicial do Ambari a partir da home page do portal
HDInsight

12. No painel do Ambari, clique em Hive view 2.0, conforme mostrado na captura


de tela a seguir:

Figura 7.18 – Visualização do Hive 2.0 do painel do Ambari

13. Agora, você deve ser capaz de ver o banco de dados no painel do Hive,
conforme mostrado na captura de tela a seguir:Hivesampletable

Figura 7.19 – Exibição de consulta do Hive da tabela de exemplo


14. Agora que temos o cluster HDInsight, precisamos criar um cluster do Azure
Databricks. Temos que criar um novo cluster com as seguintes configurações.
Vamos ver como inserir essas configurações na tela de criação do Spark na
próxima etapa:
15. spark.sql.hive.metastore.version 2.1.1 // For HDInsight Interactive 2.1 version

16. spark.hadoop.javax.jdo.option.ConnectionUserName <Your Azure SQL Database

Username>

17. spark.hadoop.javax.jdo.option.ConnectionURL <Your Azure SQL Database JDBC

connection string>

18. spark.hadoop.javax.jdo.option.ConnectionPassword <Your Azure SQL Database

Password>

19. spark.hadoop.javax.jdo.option.ConnectionDriverName

com.microsoft.sqlserver.jdbc.SQLServerDriver

20. spark.sql.hive.metastore.jars <Location where you have copied the Hive Metastore Jars>

21. datanucleus.autoCreateSchema true

datanucleus.fixedDatastore false
CopyExplain

Observe que você terá que usar o link JDBC que você salvou anteriormente, para
a configuração que diz .spark.hadoop.javax.jdo.option.ConnectionURL

15. Você terá que inserir as configurações no campo Spark Config na


página Criar Cluster, conforme mostrado na captura de tela a seguir:
Figura 7.20 – Adicionando configuração personalizada ao criar o cluster do Azure
Databricks

Observação importante

Além dos campos de configuração, você também terá que baixar os arquivos JAR
do metastore do Hive e fornecer a eles um local onde os clusters do Azure
Databricks possam acessá-los. O Azure fornece instruções passo a passo junto
com scripts prontos para baixar facilmente os arquivos JAR
aqui: https://docs.microsoft.com/en-us/azure/databricks/_static/notebooks/setup-
metastore-jars.html.

16. Depois de criar o cluster do Spark, você poderá acessar as tabelas do Hive
Metastore diretamente de um bloco de anotações do Spark. Na captura de
tela a seguir, você pode ver como o cluster Databricks Spark é capaz de
acessar a tabela que vimos anteriormente usando a exibição de consulta do
Hive:HiveSampletable

Figura 7.21 – O Spark é capaz de acessar dados do metastore externo do Hive

Viva! Agora você sabe como acessar metadados entre clusters do Spark e do Hive
usando um metastore externo do Hive.

Você pode saber mais sobre os metastores do Azure Databricks


aqui: https://docs.microsoft.com/en-us/azure/databricks/data/metastores/external-
hive-metastore. Com isso, chegamos ao final desta seção e do capítulo. Agora
você deve estar familiarizado com as diferentes maneiras pelas quais os
metadados podem ser compartilhados entre os serviços SQL, Spark e Hive no
Azure.

Resumo
Este foi outro capítulo pequeno, mas interessante. Começamos com a
implementação do esquema em estrela, depois aprendemos sobre a entrega de
dados no formato Parquet e, finalmente, analisamos como podemos compartilhar
dados entre os serviços SQL-Spark e Spark-Hive no Azure. Com todo esse
conhecimento, agora você deve ser capaz de projetar e implementar uma camada
de serviço básica para uma arquitetura de data lake usando os serviços do Azure.
Para saber mais, siga os links que forneci no final de tópicos importantes.

Com isso, chegamos ao final da primeira grande seção do programa DP-


203, Projetando e Implementando o Armazenamento de Dados. Isso cobre cerca
de 40% a 45% do exame de certificação. Estamos cada vez mais perto da
metade. Bom dia!

Na próxima seção, aprenderemos sobre como projetar e desenvolver sistemas de


processamento de dados e, mais especificamente, sobre a ingestão e
transformação de dados em data lakes.

Capítulo 8: Ingestão e transformação de


dados
Bem-vindo à próxima grande seção do livro. Nesta seção, nos concentraremos no
projeto e desenvolvimento de sistemas de processamento de dados.

No último capítulo, aprendemos sobre a implementação da camada de serviço e


vimos como compartilhar dados entre serviços como Synapse SQL e Spark
usando metastores. Neste capítulo, nos concentraremos na transformação de
dados — o processo de transformar seus dados de seu formato bruto para um
formato mais útil que pode ser usado por ferramentas e projetos downstream.
Depois de concluir este capítulo, você poderá ler dados usando diferentes
formatos de arquivo e codificações, executar limpeza de dados e executar
transformações usando serviços como Spark, SQL e Azure Data Factory (ADF).

Abordaremos os seguintes tópicos neste capítulo:

 Transformando dados usando o Apache Spark

 Transformando dados usando Transact-SQL (T-SQL)


 Transformando dados usando o ADF
 Transformando dados usando pipelines do Azure Synapse

 Transformando dados usando o Stream Analytics

 Limpeza de dados

 Dividindo dados

 Destruindo a notação de objeto JavaScript (JSON)


 Codificação e decodificação de dados

 Configurando o tratamento de erros para a transformação

 Normalizando e desnormalizando valores

 Transformando dados usando o Scala

 Realização de análise exploratória de dados (EDA)

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 Um espaço de trabalho Synapse ativo

 Um espaço de trabalho ADF ativo

Vamos começar.

Transformando dados usando o Apache


Spark
O Apache Spark oferece suporte a transformações com três interfaces
de programação de aplicativos (APIs) diferentes: RDDs (Resilient
Distributed Datasets), DataFrames e Datasets. Aprenderemos sobre RDDs e
transformações DataFrame neste capítulo. Os conjuntos de dados são apenas
extensões de DataFrames, com recursos adicionais, como ser seguro para tipo
(onde o compilador verificará estritamente os tipos de dados) e fornecer uma
interface orientada a objeto (OO).

As informações nesta seção se aplicam a todos os tipos de Spark disponíveis no


Azure: Synapse Spark, Azure Databricks Spark e HDInsight Spark.

O que são RDDs?


RDDs são uma coleção imutável tolerante a falhas de objetos de dados que
podem ser operados em paralelo pelo Spark. Essas são as estruturas de dados
mais fundamentais nas quais o Spark opera. Os RDDs oferecem suporte a uma
ampla variedade de formatos de dados, como JSON, valores separados por
vírgulas (CSV), Parquet e assim por diante.

Criando RDDs

Há muitas maneiras de criar um RDD. Aqui está uma maneira fácil de usar a
função:parallelize()

val cities = Seq("New York", "Austin")

val rdd=spark.sparkContext.parallelize(cities)
CopyExplain

Depois de criarmos um RDD, podemos executar diferentes tipos de


transformações neles. Vamos explorar os mais comuns.

Transformações RDD

Aqui estão algumas das transformações RDD mais usadas no Spark:

 map()—Aplica a função fornecida como parâmetro a todos os elementos da


origem e retorna um novo RDD. Aqui está um exemplo para fazer uma
contagem de palavras:
 val maprdd=rdd.map(word => (word,1))

maprdd.collect.foreach(println)
CopyExplain
 flatMap()—Semelhante ao , mas pode aplicar a função fornecida a mais de
um elemento, conforme ilustrado aqui: map()
 val fmrdd = rdd.flatMap(word => word.split(" "))

fmrdd.collect.foreach(println)
CopyExplain
 filter()—Retorna um novo RDD que satisfaz a condição do filtro, conforme
ilustrado aqui:
 val emptystrfilterrdd = rdd.filter(_.nonEmpty)

emptystrfilterrdd.collect.foreach(println)
CopyExplain
 groupByKey()—Coleta dados idênticos em grupos e pode executar ações
agregadas sobre eles, conforme ilustrado aqui:
 val groupbyrdd = rdd.groupBy(word => word.charAt(0))

groupbyrdd.collect.foreach(println)
CopyExplain
 union()—Retorna um novo RDD que é uma união dos dois conjuntos de
dados, conforme ilustrado aqui:
 val rdd1 = spark.sparkContext.parallelize(List(1, 2, 3))

 val rdd2 = spark.sparkContext.parallelize(List(4, 5, 6))

 val unionrdd = rdd1.union(rdd2)

unionrdd.collect().foreach(println)
CopyExplain
 distinct()—Retorna um novo conjunto de dados que contém apenas os
elementos exclusivos do conjunto de dados de entrada, conforme ilustrado
aqui:
 val distrinctrdd = rdd.distinct()

distrinctrdd.collect.foreach(println)
CopyExplain

O Spark suporta uma enorme lista de transformações. Se você quiser ver a lista
completa, consulte a documentação do Apache
Spark aqui: https://spark.apache.org/docs/latest/rdd-programming-guide.html.
Vamos a seguir examinar DataFrames.

O que são DataFrames?


DataFrames são semelhantes a tabelas em bancos de dados relacionais. Eles são
como RDDs, pois também são imutáveis, redundantes e distribuídos, mas
representam uma forma superior de abstração de dados. DataFrames contêm
esquemas, colunas e linhas, assim como em tabelas relacionais, e são úteis no
processamento de grandes volumes de dados ao usar operações semelhantes a
tabelas relacionais.

Criando DataFrames

Vejamos as opções disponíveis para criar DataFrames. Eles estão descritos aqui:

 Convertendo um RDD em um DataFrame, da seguinte maneira:


val df = rdd.toDF()
CopyExplain
 Criando um DataFrame a partir de um arquivo CSV, da seguinte maneira:
csvDf = spark.read.csv("/path/to/file.csv")
CopyExplain
 Criando um DataFrame a partir de um arquivo JSON, da seguinte maneira:
jsonDf = spark.read.json("/path/to/file.json")
CopyExplain
 Criando um DataFrame com um esquema, da seguinte maneira:
 data = [("Adam","Smith","Male","CA"),

         ("Brenda","Jones","Female","FL")]

 schema = ["firstname","lastname","gender","state"]

df = spark.createDataFrame(data = data, schema = schema)


CopyExplain

Em seguida, vamos examinar as transformações do DataFrame.

Transformações DataFrame
Para análise de dados, as transformações DataFrame são mais relevantes do que
as transformações RDD, pois lidam com abstrações semelhantes a tabelas, o que
facilita para os analistas de dados.

Nota

Uma transformação DataFrame é eventualmente convertida em uma


transformação RDD no Spark:

Vejamos algumas transformações importantes do DataFrame. Vamos supor que ,


e são DataFrames válidos. dfdf1df2

 select()—Para selecionar dados de um subconjunto de colunas, da seguinte


maneira:
df.select("firstname","lastname").show()
CopyExplain
 filter()—Para filtrar linhas com base na condição, da seguinte forma:
df.filter('location === "Florida").show()
CopyExplain
 distinct()—Para selecionar linhas exclusivas da entrada, da seguinte
maneira:
df.distinct().show()
CopyExplain
 orderBy()—Para classificar linhas por uma coluna específica, da seguinte
maneira:
df.orderBy("location").show()
CopyExplain
 join()—Juntar dois quadros com base nas condições previstas, da seguinte
forma:
df1.join(df2, df1("id") === df2("id"),"inner")
CopyExplain
 groupBy() e —Pode ser usado em combinação para agregar valores que são
agrupados em alguns valores de coluna, como no seguinte
caso:avg()location
df.groupBy("location").avg("salary").show()
CopyExplain

Os exemplos anteriores devem dar uma boa noção dos tipos de transformações
disponíveis no Spark. Você pode saber mais sobre DataFrames
aqui: https://spark.apache.org/docs/latest/sql-programming-guide.html.

Agora, vamos ver as transformações disponíveis no T-SQL.

Transformando dados usando T-SQL


T-SQL é uma linguagem de procedimento que é usada por pools SQL dedicados e
sem servidor no Synapse. Semelhante às transformações que vimos no Spark, o
T-SQL também fornece um rico conjunto de transformações. Vejamos alguns dos
importantes aqui:

 SELECT—Para selecionar dados de um subconjunto de colunas, da seguinte


maneira:
[firstName], [lastName] from dbo.Driver WHERE [city] = 'New York';
CopyExplain
 ORDER BY—Para classificar linhas por uma coluna específica, da seguinte
maneira:
SELECT [firstName], [lastName] from dbo.Driver ORDER BY [firstName];
CopyExplain
 DISTINCT—Para selecionar linhas exclusivas da entrada, da seguinte maneira:
SELECT DISTINCT [firstName], [lastName] from dbo.Driver;
CopyExplain
 GROUP BY—Agrupar linhas por colunas para que as operações agregadas
possam ser executadas nelas, da seguinte forma:
SELECT [gender], AVG([salary]) AS 'AVG salary' from dbo.Driver GROUP BY [gender];
CopyExplain
 UNION—Para combinar linhas de duas tabelas que contêm o mesmo esquema,
da seguinte maneira:
 SELECT [firstName], [lastName] FROM

 dbo.Driver
 WHERE [city] = 'New York'

 UNION

 select [firstName], [lastName] FROM

 dbo.TempDriver

WHERE [city] = 'New York';


CopyExplain
 JOIN—Juntar dois quadros com base nas condições previstas, da seguinte
forma:
 SELECT driver.[firstName], driver.[lastName], feedback.[rating], Feedback.[comment] FROM

 dbo.Driver AS driver

 INNER JOIN dbo.Feedback AS feedback

 ON driver.[driverId] = feedback.[driverId]

WHERE driver.[city] = 'New York';


CopyExplain
 VIEW—Além das transformações padrão, o T-SQL também fornece uma
transformação, que pode ajudar na geração de relatórios e consultas ad hoc.
Veremos agora um exemplo simples de como criar e usar uma
transformação, da seguinte maneira:VIEWVIEW
 CREATE VIEW CompleteDriverView

 AS

 SELECT driver.[firstName], driver.[lastName], feedback.[rating], feedback.[comment] FROM

 dbo.Driver AS driver

 INNER JOIN dbo.Feedback AS feedback

 ON driver.[driverId] = feedback.[driverId]

WHERE driver.[city] = 'New York';


CopyExplain

Veja como você pode usar uma transformação:VIEW

SELECT DISTINCT * from CompleteDriverView;
CopyExplain
Isso abrange algumas das transformações importantes no T-SQL. Para obter uma
lista mais abrangente, consulte a documentação do T-SQL
disponível aqui: https://docs.microsoft.com/en-us/sql/t-sql/language-reference.

Vamos aprender a seguir sobre as opções de transformação disponíveis no ADF.

Transformando dados usando o ADF


Já vimos alguns exemplos de ADF nos capítulos anteriores. Apenas para
atualizar, procure no portal do Azure e crie uma nova fábrica de dados do Azure.
Depois de criado, você pode iniciar o Azure data factory, conforme mostrado na
captura de tela a seguir:Azure Data Factory

Figura 8.1 – Iniciando o Azure Data Factory

Isso abrirá o espaço de trabalho do ADF onde você poderá criar seus pipelines,
conforme mostrado na captura de tela a seguir:
Figura 8.2 – Estúdio ADF

Todas as transformações do ADF acontecem em conjuntos de dados. Então,


antes de podermos fazer qualquer transformação, teremos que criar conjuntos de
dados dos dados de origem. Você pode clicar no símbolo + para criar um novo
conjunto de dados, conforme mostrado na captura de tela a seguir:

Figura 8.3 – Criando um novo conjunto de dados no ADF

O ADF fornece uma ampla variedade de fontes de dados do Azure e de outros


países, conforme mostrado na captura de tela a seguir.
Figura 8.4 – Opções de origem do conjunto de dados no ADF

Você pode selecionar a fonte de dados apropriada, clicar em Continuar e


adicionar o local dos arquivos de dados de origem ou pastas que precisam ser
transformados. Isso criará conjuntos de dados de origem.

O ADF fornece opções convenientes de transformação sem código chamadas


fluxos de dados de mapeamento. O mapeamento de fluxos de dados fornece três
tipos de transformações, conforme descrito aqui:

 Transformações de esquema — como adicionar novas colunas.


 Transformações de linha — como atualizar linhas, criar modos de exibição e
assim por diante.
 Transformações de várias entradas/saídas (E/S) — como dividir linhas,
mesclar linhas e assim por diante.

Vejamos em detalhes algumas das opções importantes disponíveis nesses três


tipos de transformação.
Transformações de esquema
As transformações de esquema referem-se às ações que resultam na alteração do
esquema da tabela ou DataFrames. Vejamos algumas transformações de
esquema comumente usadas, da seguinte maneira:

 Agregar — para executar , , , e assim por diante nos dados de entrada. Aqui
está uma captura de tela de como encontrar a média da
coluna:MinMaxSumCountSalary

Figura 8.5 – Transformação agregada no ADF

Nota

As transformações agregadas produzirão apenas as colunas usadas na


agregação. Portanto, execute uma auto-junção com os dados de origem após
esse estágio se quiser que as outras colunas estejam presentes para estágios
posteriores.
 Coluna derivada—Use essa transformação para adicionar novas colunas
aos dados existentes. Na captura de tela a seguir, estamos adicionando uma
coluna simples à tabela extraída de um arquivo CSV:isActiveDriver

Figura 8.6 – Transformação de coluna derivada no ADF

 Selecionar—Você pode usar essa transformação para selecionar apenas as


colunas necessárias da entrada ou para alterar o nome das colunas antes de
armazená-las em um armazenamento de dados, conforme demonstrado na
captura de tela a seguir. Você pode clicar no ícone da lixeira para excluir as
colunas que não são necessárias:

Figura 8.7 – Selecionar transformação no ADF

A seguir, vejamos algumas transformações de linha.

Transformações de linha
Essas são transformações que se aplicam às linhas da tabela e são descritas
aqui:

 Alterar linha — usada para inserir, excluir, atualizar e atualizar linhas (inserir
ou atualizar) em um banco de dados ou data warehouse. Na captura de tela a
seguir, inserimos as linhas em um banco de dados somente se o valor não for
:DriverIdNULL

Figura 8.8 – Alterar transformação de linha

Nota

A linha Alter funciona apenas em bancos de dados, coletores de ponto de


extremidade REST (REpresentational State Transfer).

 Filtro—Para filtrar linhas com base em condições. Na captura de tela a


seguir, estamos filtrando as linhas onde o valor é : CityNew York
Figura 8.9 – Transformação do filtro no ADF

 Classificar—Para classificar linhas com base em qualquer coluna ou grupo


de colunas, conforme ilustrado na captura de tela a seguir:

Figura 8.10 – Transformação de classificação

Em seguida, vamos examinar as transformações de várias E/S.

Transformações de E/S múltipla


São transformações que operam em mais de uma entrada ou, inversamente,
dividem a entrada em mais de uma saída. Eles estão descritos aqui:

 Divisão condicional — Isso pode ser usado para dividir a entrada em dois
fluxos de saída com base nas condições. Na captura de tela a seguir,
dividimos a entrada com base em:Rating

Figura 8.11 – Transformação de divisão condicional no ADF

 Ingressar — é usado para unir dois fluxos com base em uma ou mais


condições de junção. A captura de tela a seguir mostra como mesclar os
conjuntos de dados e usando o valor:DriverCSVRatingsCSVDriverId
Figure 8.12 – Join transformation in ADF

 Union—This merges two input datasets with the same schema into one, as


illustrated in the following screenshot:
Figure 8.13 – Union example in ADF

For a complete list of transformations, you can refer to the Azure


ADF documentation available here: https://docs.microsoft.com/en-us/azure/data-
factory/data-flow-transformation-overview.

ADF provides convenient templates that can accomplish a lot of the standard
pipeline activities. Let's look at these next.

ADF templates
ADF provides standard templates that you can use for various data copy and
transformation activities. You can explore the templates under the Pipeline
templates link on the ADF Studio home page, as shown in the following
screenshot:
Figure 8.14 – Pipeline templates link

Here is a sample of the template gallery:


Figure 8.15 – ADF template gallery sample

Por favor, use os modelos sempre que possível em vez de reinventar


os procedimentos, pois isso economizará muito tempo e evitará armadilhas
comuns.

Vamos ver a seguir as transformações usando pipelines Synapse.


Transformando dados usando pipelines
do Azure Synapse
Os pipelines do Azure Synapse são apenas ADF implementados dentro
do Azure Synapse Analytics, portanto, os exemplos de transformação que vimos
na seção ADF também se aplicam aqui. A única diferença é a página de
lançamento. Você pode iniciar pipelines Synapse a partir da
guia Synapse Analytics, conforme mostrado na captura de tela a seguir:

Figura 8.16 – Lançamento de pipelines Synapse

Espero que você tenha entendido as transformações disponíveis nos pipelines


ADF e Synapse. A seguir, vejamos as opções de transformação disponíveis no
Stream Analytics.

Transformando dados usando o Stream


Analytics
A configuração, os conceitos e outros detalhes do Stream Analytics serão
abordados no Capítulo 10, Projetando e desenvolvendo uma solução de
processamento de fluxo. Como precisamos de plano de fundo de streaming antes
de podermos falar sobre as transformações, abordaremos as transformações do
Stream Analytics como parte do Capítulo 10, Projetando e desenvolvendo uma
solução de processamento de fluxo.

Vejamos a seguir o conceito de Limpeza de dados.

Limpeza de dados
A limpeza de dados é uma atividade importante em qualquer pipeline de dados. À
medida que os dados fluem de várias fontes, há chances de que os dados não
adiram aos esquemas e pode haver valores ausentes, entradas não padrão,
duplicatas e assim por diante. Durante a fase de limpeza, tentamos corrigir tais
anomalias. Vejamos algumas técnicas comuns de limpeza de dados.

Manipulando valores ausentes/nulos


Podemos lidar com valores ausentes ou de várias maneiras. Podemos optar por
filtrar essas linhas, substituir valores ausentes por valores padrão ou substituí-los
por alguns valores significativos, como média, mediana, média e assim por diante.
Vejamos um exemplo de como podemos substituir valores ausentes por alguma
cadeia de caracteres padrão, como .Null'NA'

Substituindo por valores padrão

A substituição por valores padrão pode ser obtida usando a


transformação Colunas derivadas, conforme mostrado na captura de tela a
seguir:
Figura 8.17 – Substituição por valores padrão

Vejamos a seguir a filtragem de valores nulos.

Filtrando valores nulos

Você pode filtrar valores nulos usando a transformação de linha Alter, como já


vimos na Figura 8.8.

Vamos ver a seguir como cortar valores de entrada.

Entrada de corte
Valores com espaço em branco à direita são um problema comum. Você pode
facilmente cortar esses valores usando o método de dentro de uma transformação
de coluna derivada. Aqui está um exemplo disso:trim()
Figura 8.18 – Corte de espaço em branco

Vejamos a seguir a padronização dos valores de entrada.

Padronização de valores
Fontes de entrada diferentes podem usar convenções diferentes para os dados.
Por exemplo, digamos que uma das fontes de entrada use o símbolo para
representar o valor em dólar e outro fluxo de entrada use , podemos querer
padronizar as entradas antes de enviá-las a jusante para processamento posterior.
Na captura de tela a seguir, podemos ver como substituir o símbolo na coluna
por . Você só precisa usar o script no campo Expressão:
$USD$SalaryUSDreplace({ Salary}, '$', 'USD')

Figura 8.19 – Substituindo valores usando a coluna Derivada


Vamos ver a seguir como lidar com valores atípicos.

Manipulação de outliers
Se os valores de alguns dos campos parecerem anormais, você poderá substituí-
los por valores médios ou medianos. Vejamos um exemplo de como fazer isso, da
seguinte forma:

Figura 8.20 – Usando a coluna Derivada para substituir valores

Na captura de tela anterior, no campo Expressão, estamos substituindo qualquer


valor pela média salarial. > 5000

Nota

Você pode usar a transformação Agregar para localizar as funções de


agrupamento matemático , , , .averagemedianminmax

Vamos ver a seguir como remover duplicatas.

Removendo duplicatas/deduping
Você pode remover linhas duplicadas usando a transformação Agregar. Aqui está
um exemplo disso:
Figure 8.21 – Deduping using Aggregate transformation

Aggregates by default emit only the column that is operated upon. In this case,
since I've grouped it on , so it would just emit the column. In order to overcome
this, under the Column field, for the Each column that matches option, I've
specified so that all the other columns also show up in the
output.DriverIdDriverIdname != DriverId

Note

You can accomplish any of this cleansing and data preparation work using the
Spark or SQL transformations that we discussed earlier in the chapter. Those
would work perfectly fine too.

Agora abordamos os detalhes das operações de limpeza mais comumente


usadas. Com a variedade de transformações disponíveis no ADF, Spark e SQL,
você pode ser criativo sobre como realizar suas tarefas de maneira eficiente.
Vamos ver a seguir como dividir dados em pipelines de dados.

Dividindo dados
O ADF fornece várias maneiras de dividir dados em um pipeline. Os importantes
são Divisão Condicional e clonagem (Nova ramificação). Enquanto a Divisão
Condicional é usada para dividir dados com base em determinadas condições, a
opção Nova ramificação é usada apenas para copiar todo o conjunto de dados
para um novo fluxo de execução. Já vimos um exemplo de Divisão
Condicional na Figura 8.11. Vamos ver como podemos criar uma nova
ramificação no pipeline de dados.

Para criar uma nova ramificação, basta clicar no ícone + ao lado de qualquer
artefato de fonte de dados (como o bloco mostrado na captura de tela a seguir). A
partir daí, você pode escolher a opção Nova ramificação:DriverCSV11

Figura 8.22 – Nova opção de ramificação no ADF

Além dessas duas opções, o ADF também fornece a capacidade de dividir os


arquivos de entrada em vários subarquivos usando partições. Vamos ver como
fazer isso a seguir.

Divisões de arquivos
Para usar divisões de arquivos, crie um novo artefato Sink e, na guia Otimizar,
basta especificar o número de partições necessárias. A captura de tela a seguir
mostra como isso pode ser feito:

Figura 8.23 – Dividindo arquivos usando o ADF

Agora que sabemos como dividir os dados para processamento, vamos ver a


seguir como extrair dados de arquivos JSON.

Destruindo JSON
Destruição refere-se ao processo de extração de dados de arquivos JSON em
tabelas. Spark, Synapse SQL pools e ADF fornecem suporte nativo para extrair
dados do JSON. Vejamos exemplos para cada um dos serviços.

Extraindo valores de JSON usando o Spark


O Spark pode ler diretamente arquivos JSON e extrair o esquema deles. Aqui está
um trecho de código simples que pode realizar a leitura JSON:

val dfJSON = spark.read.json("abfss://path/to/json/*.json")
dfJSON.printSchema()

dfJSON.show(false)
CopyExplain

Veja como fica a saída:

Figura 8.24 – Saída da operação JSON

Você também pode especificar manualmente o esquema, conforme mostrado no


exemplo a seguir:

val driverSchema = new StructType()

.add("firstname", StringType)

.add("middlename", StringType)

...

.add("salary",IntegerType)
val dfJSON = spark.read.schema(driverSchema).json("abfss://path/to/json/*.json")
CopyExplain

Depois de ter os dados no DataFrame, você pode usar qualquer uma das
transformações disponíveis no Spark para extrair e modificar dados.

Em seguida, vamos ver como extrair valores de JSON usando SQL.

Extraindo valores de JSON usando SQL


O T-SQL fornece a função para consultar armazenamentos de dados remotos.
Podemos usar essa função para carregar dados em massa em instâncias SQL
dedicadas ou sem servidor. Aqui está um exemplo de como podemos carregar e
analisar arquivos JSON do armazenamento remoto usando SQL sem
servidor:OPENROWSET

SELECT     

    JSON_VALUE(doc, '$.firstname') AS firstname,

    JSON_VALUE(doc, '$.lastname') AS lastname,

    CAST(JSON_VALUE(doc, '$.id') AS INT) as driverid,

    CAST(JSON_VALUE(doc, '$.salary') AS INT) as salary

FROM openrowset(

        BULK 'abfss://path/to/json/*.json',

        FORMAT = 'csv',

        FIELDTERMINATOR ='0x0b',

        FIELDQUOTE = '0x0b'

    ) WITH (doc nvarchar(max)) AS ROWS

GO
CopyExplain

Os resultados da consulta anterior teriam a seguinte aparência:


Figura 8.25 – Exemplo de saída da análise JSON usando OPENROWSET

Nota

Você precisa especificar o valor como para JSON, conforme realçado no trecho de


código anterior.FORMATCSV

Extraindo valores de JSON usando ADF


O ADF fornece transformação Flatten para converter estruturas de dados
hierárquicas, como JSON, em estruturas planas, como tabelas. Há outra
transformação de desnormalização semelhante chamada Pivot, sobre a qual você
aprenderá mais adiante neste capítulo.

Vamos supor que você tenha um conjunto de dados de origem com o seguinte
JSON:

  "firstname": "Alice",

  "middlename": "",
  "lastname": "Hood",

  "id": "100",

  "locations": [{"city": "San Francisco","state": "CA"},

    {"city": "San Jose","state": "CA"},

    {"city": "Miami", "state": "FL"}

  ],

  "gender": "Female"

}
CopyExplain

Select Flatten transformation from ADF and specify the column mapping as


shown in the following figure:

Figure 8.26 – Flatten transformation in ADF

For complex structures such as arrays within JSON, you can use Unroll by to split
them into multiple rows. In our example, you can see that the Location field, which
was an array, has been denormalized into separate lines in the Input
columns section.
You can learn more
about Flatten transformation here: https://docs.microsoft.com/en-us/azure/data-
factory/data-flow-flatten.

Let's next look at how to encode and decode data.

Codificação e decodificação de dados


Nesta seção, veremos como cuidar da codificação e decodificação de valores
como American Standard Code for Information Interchange (ASCII), Unicode
Transformation Format 8 (UTF-8), UTF-16 e assim por diante ao ler ou gravar
dados de diferentes fontes. Veremos exemplos usando Spark, SQL e ADF aqui
novamente.

Codificação e decodificação usando SQL


No Synapse SQL, o agrupamento define o tipo de codificação, o tipo de
classificação e assim por diante em cadeias de caracteres SQL. O agrupamento
pode ser definido no nível do banco de dados e da tabela. No nível do banco de
dados, você pode definir o agrupamento, conforme mostrado aqui:

CREATE DATABASE TripsDB COLLATE Latin1_General_100_BIN2_UTF8;


CopyExplain

No nível da tabela, você pode defini-lo como mostrado aqui:

CREATE EXTERNAL TABLE FactTrips (

    [tripId] VARCHAR (40) COLLATE Latin1_General_100_BIN2_UTF8,

    . . .

)
CopyExplain

Depois de definir o agrupamento correto, o Synapse SQL se encarrega de


armazenar os dados no formato certo e usar o conjunto certo de codificação para
operações adicionais nesse conjunto de dados.
Vamos ver a seguir como realizar codificação/decodificação no Spark.

Codificação e decodificação usando o Spark


O Spark oferece suporte aos métodos chamados e , que podem ser usados para
realizar a conversão. O exemplo do Spark SQL a seguir mostra uma operação
simples. Convertemos os dados para o formato hexadecimal (hex) para exibir os
resultados em um formato compacto e legível, mas você também pode usar
diretamente os métodos e sem a
função:encodedecodeencodedecodeencodedecodehex()

>SELECT hex(encode('Azure', 'UTF-16'));

FEFF0041007A007500720065

>SELECT decode(X'FEFF0041007A007500720065', 'UTF-16')

Azure
CopyExplain

Os métodos e também estão disponíveis nas versões Python e Scala do


Spark.encodedecode

Codificação e decodificação usando ADF


O ADF fornece a capacidade de especificar a codificação correta nos artefatos do
conjunto de dados. Se você clicar na guia Conexão, poderá ver o
campo Codificação, conforme mostrado na captura de tela a seguir:
Figura 8.27 – Função de codificação em conjuntos de dados de origem do ADF

Além da opção de codificação de conjunto de dados, o ADF também fornece


funções para codificar e decodificar URIs (Uniform Resource Identifiers),
Base64 e assim por diante usando seus comandos de conversão. Compartilhei
alguns comandos de conversão da documentação do ADF, da seguinte maneira:

Figura 8.28 – Tabela de funções de codificação/decodificação disponíveis no ADF

Você pode encontrar uma lista detalhada de funções de conversão no ADF


aqui: https://docs.microsoft.com/en-us/azure/data-factory/control-flow-expression-
language-functions#conversion-functions.

Vamos ver a seguir como configurar o tratamento de erros em transformações do


ADF.
Configurando o tratamento de erros para
a transformação
Em todos os nossos exemplos de pipelines ADF até agora, vimos apenas casos
de sucesso. O ADF também fornece um fluxo separado para lidar com erros e
falhas. Na verdade, o ADF suporta quatro fluxos diferentes, como mostrado na
captura de tela a seguir:

Figura 8.29 – Fluxos de atividade do ADF

Em caso de erros em qualquer etapa do pipeline, podemos construir uma


ramificação de tratamento de erros que pode ser usada para corrigir os erros ou
armazená-los para ações futuras. A captura de tela a seguir mostra um desses
pipelines. Você terá que conectar a linha laranja à atividade de tratamento de
erros:
Figura 8.30 – Criando um pipeline de tratamento de erros

Selecione a atividade Executar pipeline e vincule o fluxo de falha (a linha laranja)


de qualquer uma das outras atividades a ele. Essa nova atividade do Execute
Pipeline pode ser um pipeline completo em si, como acontece com os pipelines
de transformação que vimos anteriormente no capítulo, ou pode ser uma atividade
autônoma simples para apenas registrar os logs de erros. Ele também pode ser
configurado para inserir os detalhes do erro em um banco de dados para que
possamos analisar os erros posteriormente usando os scripts SQL familiares.

O ADF Sink também fornece opções para gravar automaticamente linhas de erro


em um armazenamento de dados externo, como um repositório de blobs. Esta é
outra opção conveniente que ajuda a analisar erros de forma assíncrona. Ele pode
ser configurado usando a opção Configurações de manipulação de linha de
erro na guia Configurações da atividade Coletor, conforme mostrado na imagem
a seguir.

Figura 8.31 – Redirecionamento de linhas de erro para o armazenamento de blob

Em seguida, veremos os recursos Pivot e Unpivot, que são usados para


normalizar e desnormalizar tabelas.

Normalizando e desnormalizando valores


Já vimos a atividade ADF Flatten, que ajuda a desnormalizar os dados. Há mais
duas transformações desse tipo para ajudar a normalizar e desnormalizar
conjuntos de dados: Pivot e Unpivot. Vamos examiná-los em detalhes.

Desnormalizando valores usando Pivot


Vamos supor que você tenha uma tabela com uma coluna normalizada para
armazenar valores, mas para fins de relatório, você deseja ter uma coluna por
cidade em suas tabelas. Nesse caso, você pode usar a função Pivot para
desnormalizar a tabela. A função Pivot pega os valores de linha exclusivos e os
converte em colunas de tabela. Aqui está um exemplo de como dinamizar as
tabelas:City

1. Vamos considerar a seguinte tabela de exemplo:

Figura 8.32 – Tabela de exemplo antes de pivotar

2. Selecione a atividade Dinâmica no bloco Fluxo de Dados do ADF e, na


guia Agrupar por, especifique , conforme ilustrado na captura de tela a
seguir:Gender
Figura 8.33 – Agrupar por configurações para operação de pivô

3. Na guia Tecla dinâmica, especifique como a tecla dinâmica, conforme


ilustrado na captura de tela a seguir: City

Figura 8.34 – Guia da tecla dinâmica da função Pivot

4. E, finalmente, especifique qualquer agregação necessária, juntamente com o


prefixo a ser usado para os nomes de coluna, conforme mostrado na captura
de tela a seguir:
Figura 8.35 – Especificando o padrão de nome de coluna e a agregação para a
função Pivot

5. Após a operação de pivô, a tabela ficaria assim:

Figura 8.36 – Tabela pós-dinâmica

Você pode ver que as linhas da tabela foram convertidas em colunas aqui. Em
seguida, vamos examinar a operação Unpivot.

Normalizando valores usando Unpivot


Unpivot é o inverso de Pivot. Isso pode ser usado para normalizar os dados —
por exemplo, se tivermos uma coluna para várias cidades, poderemos despivotá-
los em uma única coluna chamada . Siga estes próximos passos:City

1. Para este exemplo, especifique na coluna Desagrupar por, conforme


ilustrado na captura de tela a seguir: Gender
Figura 8.37 – Guia Desagrupar por para operação Unpivot

2. Adicione um novo nome e tipo para a coluna não pivotada na guia Tecla


desdinâmica, conforme ilustrado na captura de tela a seguir:

Figura 8.38 – Especificando a chave Unpivot para a operação Unpivot

3. Na guia Colunas não dinâmicas, você pode especificar operações de


agregação, conforme ilustrado na captura de tela a seguir:

Figura 8.39 – Guia Colunas não pivotadas da operação Unpivot

4. Após a operação Unpivot, a tabela de saída terá a seguinte aparência:


Figura 8.40 – Tabela não pivotada

Agora que você aprendeu como desnormalizar e normalizar usando as


operações Pivot e Unpivot, vamos ver as transformações Scala.

Transformando dados usando o Scala


Todos os exemplos de transformação do Spark que vimos nas seções iniciais
deste capítulo estavam no Scala, então você já sabe como transformar dados
usando o Scala. Uma vez que aprender Scala não está no escopo deste livro, não
vamos nos aprofundar nos aspectos linguísticos de Scala. Se você está
interessado em aprender Scala, então você pode encontrar alguns bons recursos
aqui: https://www.scala-lang.org/.

Realização de Análise Exploratória de


Dados (EDA)
A exploração de dados é muito mais fácil de dentro do Synapse Studio, pois
fornece opções fáceis de um clique para examinar vários formatos de dados.
Vejamos algumas das opções disponíveis para exploração de dados usando
pipelines Spark, SQL e ADF/Synapse.

Exploração de dados usando o Spark


No Synapse Studio, basta clicar com o botão direito do mouse no arquivo de
dados e selecionar Carregar para DataFrame, conforme mostrado na captura de
tela a seguir:

Figura 8.41 – Iniciando um DataFrame a partir do arquivo de dados Synapse

Depois de clicar em Load to DataFrame, o Synapse cria um novo bloco de


anotações, conforme mostrado na captura de tela a seguir. Depois disso, tudo o
que você precisa fazer é apenas clicar no ícone Executar (o pequeno símbolo de
triângulo) para ver o conteúdo do arquivo, que são exibidos na seguinte captura de
tela:

Figura 8.42 – Exploração usando Spark Load para DataFrame

Esta é uma maneira fácil de explorar o conteúdo de um arquivo. Vamos ver a


seguir como fazer o mesmo via SQL.

Exploração de dados usando SQL


O Synapse SQL também fornece opções semelhantes para explorar dados.
Você pode selecionar o arquivo, clicar em Novo script SQL e, em seguida,
escolher Selecionar TOP 100 linhas, conforme mostrado na captura de tela a
seguir:

Figura 8.43 – Iniciando um script SQL para explorar dados do arquivo de dados
Synapse

Depois de clicar na opção Selecionar TOP 100 linhas, o Synapse abre um novo


script SQL, conforme mostrado na captura de tela a seguir. Agora, basta clicar
em Executar para obter as 100 principais linhas:

Figura 8.44 – Exemplo do script SQL que o Synapse inicia automaticamente para
nos ajudar a explorar dados
A seguir, vamos ver como fazer isso no ADF.

Exploração de dados usando ADF


O ADF fornece uma guia Visualização de dados que funciona quando temos a
configuração de depuração de fluxo de dados ativada. Depois que ativarmos a
depuração, um pequeno cluster do Azure Databricks (chamado de Tempo
de Execução de Integração do ADF) é executado nos bastidores e busca dados
reais para que possamos explorar e ajustar rapidamente nossas transformações e
pipelines. Um exemplo é mostrado na captura de tela a seguir:

Figura 8.45 – Exploração de dados usando a guia de visualização de dados do


ADF

Como você pode ver, Synapse e ADF tornam muito fácil explorar dados sem ter
que sair do estúdio.

Resumo
Com isso, chegamos ao final deste interessante capítulo. Havia muitos exemplos e
capturas de tela para ajudá-lo a entender os conceitos. Pode ser esmagador às
vezes, mas a maneira mais fácil de seguir é abrir uma sessão ao vivo do Spark,
SQL ou ADF e tentar executar os exemplos em paralelo.
Abordamos muitos detalhes neste capítulo, como a realização de transformações
no Spark, SQL e ADF; técnicas de limpeza de dados; leitura e análise de dados
JSON; codificação e decodificação; tratamento de erros durante as
transformações; normalização e desnormalização de conjuntos de dados; e,
finalmente, um monte de técnicas de exploração de dados. Este é um dos
capítulos importantes do currículo. Agora você deve ser capaz de criar pipelines
de dados confortavelmente com transformações envolvendo Spark, SQL e ADF.
Espero que você tenha se divertido lendo este capítulo. Exploraremos o projeto e
o desenvolvimento de uma solução de processamento em lote no próximo
capítulo.

Capítulo 9: Projetando e desenvolvendo


uma solução de processamento em lote
Bem-vindo ao próximo capítulo da série de transformação de dados. Se você
chegou até aqui, então você está realmente falando sério sobre a certificação.
Muito bom trabalho! Você já ultrapassou a metade, faltando apenas mais alguns
capítulos.

No capítulo anterior, aprendemos sobre muitas tecnologias, como Spark, Azure


Data Factory (ADF) e Synapse SQL. Vamos continuar a série aqui e aprender
sobre mais algumas tecnologias relacionadas ao processamento em lote.
Aprenderemos como criar pipelines em lote de ponta a ponta, como usar Spark
Notebooks em pipelines de dados, como usar tecnologias como o PolyBase para
acelerar a cópia de dados e muito mais. Também aprenderemos técnicas para
lidar com dados que chegam tarde, dimensionar clusters, depurar problemas de
pipeline e lidar com segurança e conformidade de pipelines. Depois de concluir
este capítulo, você deve ser capaz de projetar e implementar pipelines de lote de
ponta a ponta baseados em ADF usando tecnologias como Synapse SQL, Azure
Databricks Spark, PolyBase e Azure Batch nos pipelines do ADF.

Este capítulo será um pouco mais longo, pois precisamos cobrir muitos conceitos
importantes. Tomei a liberdade de reorganizar os tópicos programáticos para este
capítulo, agrupando os relacionados. Isso ajudará a criar um fluxo melhor para o
capítulo. Abordaremos os seguintes tópicos:

 Projetando uma solução de processamento em lote

 Desenvolvendo soluções de processamento em lote usando Data Factory,


Data Lake, Spark, Azure Synapse Pipelines, PolyBase e Azure Databricks

 Criando pipelines de dados

 Integrando blocos de anotações Jupyter/Python em um pipeline de dados

 Projetando e implementando cargas de dados incrementais

 Projetando e desenvolvendo dimensões que mudam lentamente

 Manipulando dados duplicados

 Tratamento de dados em falta

 Manipulação de dados que chegam tarde

 Atualizando dados

 Regressão a um estado anterior

 Apresentando o Lote do Azure

 Configurando o tamanho do lote

 Recursos de dimensionamento

 Configurando a retenção em lote

 Projetando e configurando o tratamento de exceções

 Projetando e criando testes para pipelines de dados

 Depurando trabalhos do Spark usando a interface do usuário do Spark

 Lidar com requisitos de segurança e conformidade

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 Um espaço de trabalho Synapse ativo

 Um espaço de trabalho ativo do Azure Data Factory

Vamos começar!

Projetando uma solução de


processamento em lote
No Capítulo 2, Projetando uma estrutura de armazenamento de dados,
aprendemos sobre a arquitetura do data lake. Eu apresentei o diagrama aqui
novamente por conveniência. No diagrama a seguir, há duas ramificações, uma
para processamento em lote e outra para processamento em tempo real. A parte
destacada em verde é a solução de processamento em lote para um data lake. O
processamento em lote geralmente lida com maiores quantidades de dados e leva
mais tempo para processar em comparação com o processamento de fluxo.

Figura 9.1 – Arquitetura de processamento em lote


Uma solução de processamento em lote normalmente consiste em cinco
componentes principais:

 Sistemas de armazenamento como armazenamento de Blobs do Azure,


ADLS Gen2, HDFS ou similar

 Sistemas de transformação/processamento em lote, como Spark, SQL ou


Hive (via Azure HDInsight)

 Armazenamentos de dados analíticos, como pool SQL dedicado do Synapse,


Cosmos DB e HBase (via Azure HDInsight)

 Sistemas de orquestração como ADF e Oozie (via Azure HDInsight)

 Sistemas de relatórios de Business Intelligence (BI), como o Power BI

Já exploramos muitas dessas tecnologias de forma independente nos capítulos


anteriores. Nas próximas seções, veremos como vinculá-los para criar um pipeline
para um sistema de processamento em lote.

Mas antes de entrarmos nos detalhes, quero apresentá-lo a outra tecnologia com
o mesmo nome – Lote do Azure. O Lote do Azure é um sistema de
processamento em lote de uso geral que pode ser usado para executar
a Computação de Alto Desempenho (HPC). O Lote do Azure cuida da execução
de seus aplicativos em paralelo em várias Máquinas Virtuais (VMs) ou
contêineres. O Lote do Azure é um serviço independente no Azure, enquanto o
pipeline de lote que estamos discutindo é uma coleção de serviços reunidos como
um pipeline para obter insights de dados. Exploraremos mais sobre o Lote do
Azure mais adiante neste capítulo.

Agora vamos ver como criar um sistema de processamento em lote usando ADF,
Spark, Synapse, PolyBase e Azure Databricks.

Desenvolvendo soluções de
processamento em lote usando Data
Factory, Data Lake, Spark, Azure
Synapse Pipelines, PolyBase e Azure
Databricks
Vamos tentar criar um pipeline de lote de ponta a ponta usando todas
as tecnologias listadas no cabeçalho do tópico. Usaremos nosso exemplo
de Cabine de Aeroporto Imaginária (IAC) dos capítulos anteriores para criar um
requisito de amostra para nosso pipeline de processamento em lote. Vamos
supor que estamos continuamente obtendo dados de viagem de diferentes regiões
(códigos postais), que são armazenados no armazenamento de Blobs do Azure, e
as tarifas de viagem são armazenadas em um SQL Server do Azure. Temos um
requisito para mesclar esses dois conjuntos de dados e gerar relatórios diários de
receita para cada região.

Para atender a esse requisito, podemos construir um pipeline como mostra o


diagrama a seguir:

Figura 9.2 – Arquitetura de alto nível do caso de uso em lote

O pipeline anterior, quando traduzido em um pipeline ADF, seria semelhante à


figura a seguir:
Figura 9.3 – Pipeline de dados de exemplo

Como você pode ver, o pipeline tem quatro estágios:

 Ingestão de dados: Os dois primeiros estágios, FetchTripsFrmBlob e


FetchFaresFrmSQL obtêm os dados no data lake.
 Limpeza de dados: o estágio DataCleansing no diagrama limpa os dados.
 Transformação: o estágio Transformação do Spark Notebook no diagrama
transforma os dados.
 Carregando em um banco de dados analítico: o
estágio PolyBaseCopySQLDW para copiar os dados em um pool SQL
Synapse.

O último estágio seria a leitura das ferramentas de BI do banco de dados analítico


e a geração de relatórios (o que não é mostrado no diagrama, pois não é uma
atividade do ADF).

Antes de começarmos a analisar cada uma dessas etapas, vamos definir qual
será o nosso armazenamento.

Armazenamento
Vamos considerar o ADLS Gen2 como nosso armazenamento de data lake.
Podemos criar a seguinte estrutura de pastas para lidar com nosso pipeline de
lotes:

 Os dados podem ser armazenados aqui: raw trips


iac/raw/trips/2022/01/01
CopyExplain
 Os dados limpos podem ser copiados para a pasta:transform/in
iac/transform/in/2022/01/01
CopyExplain
 A saída dos dados transformados pode ser movida para a pasta: transform/out
iac/transform/out/2022/01/01
CopyExplain
 Finalmente, podemos importar os dados do pool Synapse SQL Dedicated
usando o PolyBase.transform/out

Observe que ferramentas como ADF e PolyBase também fornecem a capacidade


de mover dados diretamente entre o Spark e o pool dedicado do Synapse SQL.
Você pode escolher essa abordagem direta em vez de armazenar os dados
intermediários no data lake, se isso funcionar melhor para você em termos de
desempenho e custo. Mas na maioria dos data lakes, mais de uma ferramenta
pode acessar os dados intermediários do data lake e será útil manter conjuntos de
dados históricos para análises futuras. Portanto, pode fazer sentido manter uma
cópia no data lake também.

Agora vamos examinar cada um dos estágios dalinha de tubulação em lote em


detalhes.

Ingestão de dados
Este é o processo de obter todos os dados brutos no data lake. Dados de
várias fontes pousam na zona bruta do data lake. Com base na origem dos dados,
como sistemas on-premise, outros sistemas em nuvem e assim por diante,
poderíamos usar diferentes ferramentas de ingestão. Vejamos algumas das
opções disponíveis no Azure:

 Azure Data Factory – Você já está familiarizado com essa tecnologia. Ele
fornece suporte à ingestão de dados de centenas de fontes de dados e até
mesmo de outras nuvens, como AWS, GCP, Oracle e assim por diante.
Usaremos isso novamente para construir nosso pipeline conforme
recomendado no programa de estudos.
 Azure Copy (AzCopy) – Esta é uma ferramenta de linha de comando que
pode ser usada para copiar dados pela Internet e é ideal para tamanhos de
dados menores (de preferência no intervalo de 10 a 15 TB). Você pode
saber mais sobre o AzCopy
aqui: https://docs.microsoft.com/en-us/azure/storage/common/storage-use-
azcopy-v10.
 Azure ExpressRoute – Se você precisar de uma maneira segura de transferir
dados para o Azure, use a Rota Expressa. Ele roteia seus dados por meio de
conexões privadas dedicadas ao Azure em vez da Internet pública. Esta
também é a opção preferida se você quiser ter um pipeline dedicado com
uma velocidade de transferência de dados mais rápida. Você pode
saber mais sobre o Azure ExpressRoute aqui: https://docs.microsoft.com/en-
us/azure/expressroute/expressroute-introduction.

Vamos considerar um exemplo de ingestão usando o ADF para ler do repositório


Blob:

1. Para primeiro se conectar ao repositório de Blobs, você terá que criar


um serviço vinculado no ADF. Você pode criar um na guia Gerenciar do
ADF, conforme mostrado na captura de tela a seguir.

Figura 9.4 – Configurando um serviço vinculado no ADF

2. Clique no símbolo + Novo e escolha Armazenamento de Blobs do Azure na


lista. Você receberá uma página como mostrado na captura de tela a seguir.
Depois de preenchê-lo e criar o serviço vinculado, você poderá acessar os
dados em seu armazenamento de Blob diretamente do ADF.
Figure 9.5 – Creating an Azure blob storage linked service

3. The next step is to create a data flow in ADF.


Figure 9.6 – Creating a new data flow in ADF

4. In the data flow, you will have to specify the source and destination.
For Source type, select the Dataset option and define a new dataset using
the Blob storage linked service that you created earlier.

Figure 9.7 – Creating source and destination datasets in a data flow


Here is how the dataset creation screen looks when you click on + New for
the Dataset option.

Figure 9.8 – Sample dataset screen

With the data flow created, we now have the data ingestion part taken care of.
Well, actually the step is still not complete. We still have to add this copy data step
to our pipeline and run it to see the results. But before that, let's learn about all the
remaining batch processing components. Let's next look at the data
preparation/data cleansing component.

Preparação/limpeza de dados
No Capítulo 8, Ingerindo e transformando dados, exploramos
várias transformações de limpeza de dados, como lidar com dados ausentes,
enganar, remover dados atípicos e assim por diante. Você pode usar exatamente
as mesmas transformações para esse estágio. Como já exploramos os detalhes
no capítulo anterior, não vamos repeti-los novamente aqui. Vamos pular para a
etapa de transformação.

Transformação
Depois que nossos dados estiverem limpos e preparados, podemos executar
nossa lógica de transformação usando serviços como Spark, SQL, Hive e assim
por diante. Neste exemplo, de acordo com o programa de certificação, usaremos
o Azure Databricks Spark. Aqui estão os passos:

1. Criar um espaço de trabalho do ADB – selecione Azure Databricks no portal


do Azure e crie um novo espaço de trabalho, conforme mostrado na captura
de tela a seguir.

Figura 9.9 – Exemplo de página de criação do espaço de trabalho do Azure


Databricks

2. Depois que o espaço de trabalho for criado, clique no botão Iniciar espaço de
trabalho para iniciar o espaço de trabalho. Isso o levará ao portal do Azure
Databricks.
Figura 9.10 – Iniciando o espaço de trabalho do Azure Databricks

Nessa tela, você pode criar clusters, blocos de anotações e muito mais. Isso nos
leva ao próximo passo.
Figura 9.11 – Portal do Azure Databricks

3. Criar um cluster ADB – clique no link Novo cluster no portal Databricks e


insira os detalhes.
Figura 9.12 – Página de criação de cluster do Azure Databricks

Isso criará o cluster que será necessário para executar as transformações para o
pipeline em lote.

4. Em seguida, clique em Criar e, em seguida, em Bloco de Anotações para


criar sua lógica de transformação – no portal do Azure Databricks, você pode
escolher Novo Bloco de Anotações ou fazê-lo nas guias laterais, conforme
mostrado:
Figura 9.13 – Criação do novo bloco de anotações do Azure Databricks

Depois de criar o novo bloco de anotações, você receberá um editor como


mostrado na captura de tela a seguir. Você pode escrever o código Spark dentro
dos blocos Cmd. O Azure Databricks dá suporte às linguagens Scala, Python,
SQL e R.

Figura 9.14 – Bloco de anotações do Azure Databricks

Para gerar um relatório de viagem diário, podemos escrever um script de


transformação Scala simples, conforme mostrado nas etapas a seguir. Você terá
que escrevê-los nas seções Cmd mostradas na captura de tela anterior:
1. Primeiro, precisamos configurar as configurações iniciais do ADB Spark para
falar com o ADLS Gen2:
2. spark.conf.set("fs.azure.account.auth.type." + storageAccountName + ".dfs.core.windows.net",

"OAuth")

3. spark.conf.set("fs.azure.account.oauth.provider.type." + storageAccountName +

".dfs.core.windows.net", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")

4. spark.conf.set("fs.azure.account.oauth2.client.id." + storageAccountName +

".dfs.core.windows.net", "" + appID + "")

5. spark.conf.set("fs.azure.account.oauth2.client.secret." + storageAccountName +

".dfs.core.windows.net", "" + secret + "")

6. spark.conf.set("fs.azure.account.oauth2.client.endpoint." + storageAccountName +

".dfs.core.windows.net", "https://login.microsoftonline.com/" + tenantID + "/oauth2/token")

7. spark.conf.set("fs.azure.createRemoteFileSystemDuringInitialization", "true")

spark.conf.set("fs.azure.createRemoteFileSystemDuringInitialization", "false")
CopyExplain
8. Leia os dados da viagem (armazenados como um arquivo CSV):
9. %scala

10.       .add("tripId",IntegerType)

11.       .add("driverId",IntegerType)

12.       .add("customerId",IntegerType)

13.       .add("cabId",IntegerType)

14.       .add("tripDate",IntegerType)

15.       .add("startLocation",StringType)

16.       .add("endLocation",StringType)

17. val tripsCSV = spark.read.format("csv")

18.       .option("header", "true")

19.       .schema(tripsSchema)

      .load("abfss:/path/to/csv")
CopyExplain
20. Leia os dados da tarifa (armazenados como arquivos Parquet):
21. %scala

22. val faresSchema = new StructType()

23.       .add("tripId",IntegerType)

24.       .add("fare",IntegerType)

25.       .add("currency",StringType)

26. val faresParquet = spark.read.format("parquet")

27.             .schema(faresSchema)

28.             .load("abfss:/path/to/parquet")

29. Join them with tripId and group by startLocation:

30. val joinDF = tripsCSV.join(

31. faresParquet,tripsCSV("tripId") ===

32.       faresParquet("tripId"),"inner")

33. .groupBy("startLocation")

.sum("fare");
CopyExplain
34. Junte-se a eles e agrupe-os por:tripIdstartLocation
35. val joinDF = tripsCSV.join(

36. faresParquet,tripsCSV("tripId") ===

37.       faresParquet("tripId"),"inner")

38. .groupBy("startLocation")

.sum("fare");
CopyExplain
39. Imprima a tabela de saída com as colunas e :CityFare
40. import org.apache.spark.sql.functions.col;

val outputDF = joinDF.select(col("startLocation").alias("City"),col("sum(fare)").alias("Fare"));


CopyExplain
41. Finally, write the output back to ADLS Gen2 under
the folder:transform/fares/out
outputDF.write.mode("overwrite").parquet("abfss:/path/to/output")
CopyExplain

Try to run the code and debug any issues within Azure Databricks before we hook
it up to the ADF pipeline.

Tip

Azure Databricks provides a library called that can be used for filesystem


operations such as listing files and managing secrets and data operations such as
summarizing datasets and so on. Here is an example: dbutils

dbutils.fs.cp("/path/to/source.txt", "/path/to/destination.txt")

You can learn more


about here: https://docs.microsoft.com/en-us/azure/databricks/dev-tools/
databricks-utils.dbutils

Next, let's see how to configure ADF to call the Spark notebook that we have just
created.

Configuring an ADB notebook activity in ADF

Here are the steps to add an ADB notebook into an ADF pipeline:

1. From the Azure Data Factory Activities tab,


choose Notebook under Databricks and add it to the pipeline by dragging the
icon into the worksheet area as shown in the following screenshot.

Figure 9.15 – Choosing an Azure Databricks activity in ADF


2. You have to link this Notebook activity to the notebook that you created in the
previous step. In order to link the notebook, you will have to first get the
access token from Azure Databricks. You can generate the access token from
the Azure Databricks portal from the User Settings tab as shown in the
following screenshot. Click on the Generate New Token button to create a
new access token.

Figure 9.16 – Getting the access token from Azure Databricks

3. Now, link the previously created ADB notebook using a linked service. Similar
to how we created a linked service to Azure Blob storage, we need to create
one for Azure Databricks Spark too. The following screen shows the linked
service configuration for Azure Databricks. You will have to fill in Databricks
Workspace URL, the Access token field – with the access token that you
generated in the previous step, and select whether you want to spin up a New
job cluster or point to an Existing interactive cluster, and so on.
Figure 9.17 – Creating an Azure Databricks linked service

Once you have created the linked service and entered those details into the ADF
notebook activity, your sample transformation stage will be complete. The final step
that is pending is to import the data from this transformation stage into SQL
Dedicated pool and to serve the data from there to Power BI. But before we go
there, let's look at the options available for batch processing in Azure.

Batch processing technology choices

Here is a useful table reproduced from Azure that can help you decide on the
technologies to use for your batch scenarios:
Figure 9.18 – Comparison of batch processing technologies in Azure

You can learn more about the batch processing choices


here: https://docs.microsoft.com/en-us/azure/architecture/data-guide/technology-
choices/batch-processing.

Let's next see how to copy the data generated from the transformation stage into
Synapse SQL using PolyBase.

Using PolyBase to ingest the data into the


Analytics data store
PolyBase is a tool that enables services such as SQL Server and Synapse
Dedicated SQL pool to copy and query data directly from external locations. The
external sources could be Azure Storage, Oracle, Teradata, Hadoop, MongoDB,
and so on. PolyBase is integrated into T-SQL, so every time we use a command to
read data from an external storage location, PolyBase kicks in. PolyBase is one of
the fastest and most scalable ways to copy data.COPY INTO <table> FROM
For the data lake scenario, we are going to use PolyBase to copy the transformed
data from Azure Databricks into Synapse Dedicated SQL pool using a staging
ADLS or Blob store. The steps to do this are as follows:

1. Prepare the source data in text files in ADLS or the Blob store.
2. Define an external table with the right schema in the Dedicated SQL pool
instance. The format of the incoming data should match the external table
schema accurately. If not, rows might get dropped.
3. If the data is coming from a non-relational source, we will have to transform it
into a rows and columns format that matches the external table schema
correctly.
4. Run the command to load the data into dedicated SQL pool external tables
using PolyBase. COPY INTO
5. From here, you can either serve the data directly or do more processing using
a Dedicated SQL pool before serving it to the BI tools.

Here is an example of how to use PolyBase:

CREATE EXTERNAL FILE FORMAT [Dp203ParquetFormat]

WITH ( FORMAT_TYPE = PARQUET)

CREATE EXTERNAL DATA SOURCE [Dp203DataSource]

WITH (

LOCATION = 'abfss://path/to/storage/location'

CREATE EXTERNAL TABLE TripExtTable

WITH (

LOCATION = '/path/to/data/*.parquet',

DATA_SOURCE = [Dp203DataSource],

FILE_FORMAT = [Dp203ParquetFormat]

) AS

SELECT
[tripId] INT,

[driverId] INT,

...

[endLocation] VARCHAR(50)

FROM

    OPENROWSET(BULK '/path/to/data/*.parquet', FORMAT='PARQUET')


CopyExplain

Now copy the data from the external table into an actual SQL table:

CREATE TABLE TripsProdTable

WITH

    CLUSTERED COLUMNSTORE INDEX,

    DISTRIBUTION = ROUND_ROBIN

AS

SELECT * FROM TripsExtTable


CopyExplain

With the last statement, PolyBase copies the data into Synapse SQL Dedicated
pool.CREATE EXTERNAL TABLE AS SELECT (CETAS)

Note

PolyBase does not support nested formats such as JSON, XML, and WinZip as of
writing this book. For JSON files, you could try to flatten the data first using the
techniques we saw in Chapter 8, Ingesting and Transforming Data, under
the Shredding JSON section, before using PolyBase to load them into Synapse
SQL.

Options for loading with PolyBase


PolyBase is also available as part of other services, such as the following:

 Azure Data Factory – This version of PolyBase can be used as an activity


within ADF. The data copy activity can be defined as a pipeline that can be
scheduled regularly. You can read more about it
here: https://docs.microsoft.com/en-us/azure/data-factory/connector-azure-sql-
data-warehouse?tabs=data-factory#use-polybase-to-load-data-into-azure-
synapse-analytics.
 Azure Databricks – This version of PolyBase can be used to transfer data
between Azure Databricks and Synapse SQL pools. You can learn more
about it here: https://docs.microsoft.com/en-us/azure/databricks/scenarios/
databricks-extract-load-sql-data-warehouse.
 SQL Server – This version can be used if the source is a SQL Server. The
SQL Server Integration Services (SSIS) platform can be used to define the
source and destination mappings and do the orchestration while using the
SSIS version of PolyBase. You can learn more about it
here: https://docs.microsoft.com/en-us/sql/integration-services/sql-server-
integration-services.

You can learn more about PolyBase


here: https://docs.microsoft.com/en-us/sql/relational-databases/polybase/polybase-
versioned-feature-summary.

Let's next look at the last piece of our puzzle in the batch processing pipeline,
which is to view the insights using Power BI.

Using Power BI to display the insights


Power BI is a Business Intelligence (BI) data visualization tool that is deeply
integrated with Azure cloud services. It has built-in connectivity to many clouds and
on-premises technologies and helps visualize and share insights from data.

The steps involved in visualizing the Synapse SQL data via Power BI are as
follows:
1. Go to and create an account. Once you have logged in, create a new
workspace by clicking on the Create a workspace button from
the Workspaces tab as shown in the following
screenshot.powerbi.microsoft.com

Figure 9.19 – Creating a workspace in Power BI


2. Next, go to the Synapse workspace and create a linked service to Power BI.
Click on the Manage tab in the Synapse workspace and select Linked
services. Then click on + New and search for as shown in the following
screenshot.Power BI

Figure 9.20 – Creating a Power BI linked service

3. On the linked service configuration screen, give a name to the linked service
and select the previously created Power BI workspace for the Workspace
name field.
Figura 9.21 – Configuração do serviço vinculado do Power BI

4. Depois de preencher os campos e clicar em Criar, um novo serviço vinculado


ao Power BI é criado.
5. Agora vá para a guia Editor no espaço de trabalho Sinapse. Você deve ver
uma seção do Power BI, conforme mostrado na captura de tela a seguir.
Clique em + Novo conjunto de dados do Power BI e escolha a tabela SQL
que você deseja incluir como seu conjunto de dados do Power BI.
Figura 9.22 – Criando um novo conjunto de dados do Power BI no Synapse

6. Uma tela de download será exibida conforme mostrado na captura de tela a


seguir. Basta baixar o arquivo..pbids

Figura 9.23 – Baixando o arquivo .pbids para o Power BI

7. Em seguida, clique duas vezes no arquivo e ele abrirá o Power BI Desktop.


Se não tiver o Power BI Desktop, pode instalá-lo a partir daqui: https://Power
BI.microsoft.com/en-us/downloads/..pbids
8. Quando o Power BI Desktop for aberto, escolha qualquer uma
das Visualizações e arraste e solte os campos da tabela na guia Campos à
direita. O Power BI agora mostrará os gráficos dos seus dados.
Figura 9.24 – Visualizando dados do Power BI Desktop

E é assim que você pode conectar uma ferramenta de relatório de BI ao seu pool
Synapse SQL.

Você pode saber mais sobre como vincular o Synapse SQL ao Power BI


aqui: https://docs.microsoft.com/en-us/azure/synapse-analytics/get-started-
visualize-power-bi.

Agora que temos todos os componentes necessários para criar o pipeline, vamos
ver como realmente vinculá-los no Azure Data Factory e criar o pipeline.

Criando pipelines de dados


Os pipelines de dados são uma coleção de várias atividades de processamento de
dados organizadas em uma sequência específica para produzir os insights
desejados a partir de dados brutos. Já vimos muitos exemplos no Azure Data
Factory em que encadeamos as atividades para produzir um resultado final
desejável. O ADF não é a única tecnologia disponível no Azure. O Azure também
oferece suporte a pipelines Synapse (que é uma implementação do ADF no
Synapse) e tecnologias de software livre, como o Oozie (disponível via Azure
HDInsight), que podem ajudar a orquestrar pipelines. Se sua carga de trabalho
usa apenas software de código aberto, então o Oozie poderia se encaixar na
conta. Mas se o pipeline usar outros serviços do Azure ou de terceiros externos, o
ADF pode ser mais adequado, pois o ADF fornece plug-ins de origem e coletor
prontamente disponíveis para uma enorme lista de tecnologias.

Você pode criar um pipeline na guia Pipeline do Azure Data Factory. Tudo o que
você precisa fazer é selecionar as atividades para seu pipeline na
guia Atividades e clicar e arrastá-lo para a tela. Você pode vincular as atividades
usando a caixa verde (no lado direito de cada atividade) e encadear os blocos
juntos sequencialmente ou paralelamente para derivar a saída necessária. A
captura de tela a seguir mostra um exemplo.

Figura 9.25 – Criação de novos pipelines no ADF

Depois de ter o pipeline costurado, você pode acioná-lo usando o botão Adicionar


gatilho. O gatilho pode ser único, baseado em eventos ou recorrente.

Espero que agora você tenha uma compreensão de como criar e publicar um
pipeline de lote de ponta a ponta. Vamos ver a seguir como integrar blocos de
anotações Jupyter e Python em um pipeline de dados.

Integrando blocos de anotações


Jupyter/Python em um pipeline de dados
A integração de notebooks Jupyter/Python em nosso pipeline de dados do
ADF pode ser feita usando a atividade do Spark no ADF. Você precisará de um
cluster do Azure HDInsight Spark para este exercício.
O pré-requisito para integrar blocos de anotações Jupyter é criar serviços
vinculados ao Armazenamento do Azure e ao HDInsight a partir do ADF e ter um
cluster HDInsight Spark em execução.

Você já viu como criar serviços vinculados, na seção Desenvolvendo soluções de


processamento em lote usando Data Factory, Data Lake, Spark, Azure Synapse
Pipelines, PolyBase e Azure Databricks anteriormente neste capítulo, portanto,
não repetirei as etapas aqui.

Selecione a atividade do Spark do ADF e especifique o serviço vinculado do


HDInsight que você criou no campo Serviço vinculado do HDInsight na
guia Cluster HDI, conforme mostrado na captura de tela a seguir.

Figura 9.26 – Configurando uma atividade do Spark no ADF

Agora, inicie o bloco de anotações do Jupyter acessando


https://<YOURHDICLUSTER>.azurehdinsight.net/jupyter ou no painel do
HDInsight, conforme mostrado na captura de tela a seguir.
Figura 9.27 – Iniciando o notebook Jupyter a partir do HDInsight

Na página de inicialização do Jupyter, você pode selecionar PySpark


ou PySpark3 para iniciar um bloco de anotações Python.

Figura 9.28 – Iniciando um notebook PySpark Jupyter a partir do HDInsight

Você pode escrever suas transformações no bloco de anotações Jupyter e


executá-las usando os pipelines do ADF como qualquer outra atividade do ADF.
Agora você sabe como executar notebooks Jupyter a partir de pipelines de dados.
Você pode saber mais sobre como executar blocos de anotações do Spark no
ADF aqui: https://docs.microsoft.com/en-us/azure/data-factory/v1/data-factory-
spark.

As próximas seções se concentrarão em algumas técnicas avançadas para


carregamento de dados e preparação de dados. Alguns desses tópicos são
repetidos dos capítulos anteriores, então vamos pulá-los fornecendo referências
aos capítulos anteriores e nos concentrar nos novos tópicos que ainda não foram
abordados.

Projetando e implementando cargas de


dados incrementais
Abordamos o carregamento incremental de dados no Capítulo 4, Projetando a
camada de serviço. Consulte esse capítulo para atualizar seus conhecimentos
sobre cargas de dados incrementais.

Vamos ver a seguir como implementar dimensões que mudam lentamente.

Projetando e desenvolvendo dimensões


que mudam lentamente
Também abordamos as dimensões de mudança lenta (SCDs) em detalhes
no Capítulo 4, Projetando a camada de serviço. Por favor, consulte esse capítulo
para atualizar seus conhecimentos sobre os conceitos.

Manipulando dados duplicados


Já exploramos esse tema no Capítulo 8, Ingestão e transformação de dados.
Consulte esse capítulo para atualizar sua compreensão do tratamento de dados
duplicados.

Vejamos a seguir como lidar com dados ausentes.


Tratamento de dados em falta
Já exploramos esse tema no Capítulo 8, Ingestão e transformação de dados.
Consulte esse capítulo para atualizar sua compreensão do tratamento de dados
duplicados.

Vejamos a seguir como lidar com dados que chegam atrasados.

Manipulação de dados que chegam tarde


Ainda não cobrimos esse cenário, então vamos nos aprofundar no tratamento de
dados que chegam atrasados.

Um cenário de dados de chegada tardia pode ser considerado em três estágios


diferentes em um pipeline de dados – durante a fase de ingestão de dados, a fase
de transformação e a fase de serviço.

Manipulação de dados que chegam tardiamente


no estágio de ingestão/transformação
Durante as fases de ingestão e transformação, as atividades geralmente incluem
copiar dados para o data lake e executar transformações de dados usando
mecanismos como Spark, Hive e assim por diante. Em tais cenários, os dois
métodos a seguir podem ser usados:

 Solte os dados, se seu aplicativo pode lidar com alguma quantidade de perda
de dados. Esta é a opção mais fácil. Você pode manter um registro do último
carimbo de data/hora que foi processado. E se os novos dados tiverem um
carimbo de data/hora mais antigo, você pode simplesmente ignorar essa
mensagem e seguir em frente.

 Execute novamente o pipeline na guia Monitoramento do ADF, se


o aplicativo não puder lidar com a perda de dados.
Em seguida, vamos ver como lidar com dados que chegam atrasados no estágio
de serviço.

Manipulação de dados que chegam atrasados no


estágio de serviço
Na fase de serviço, o tratamento de dados geralmente é feito por meio de um
esquema de estrela ou floco de neve para cenários OLAP. Nesses casos, pode
haver situações em que uma dimensão chega tarde (ou um fato pode chegar
cedo). Vejamos alguns métodos comuns para lidar com esses cenários:

 Solte a mensagem: como no estágio de ingestão/transformação, essa é a


opção mais fácil, especialmente se os dados antigos não agregarem muito
valor.
 Armazene a mensagem e tente novamente depois de algum tempo: Nesta
técnica, armazene as linhas de fato que chegam cedo em uma tabela de
preparo e tente inserir esse fato quando estiver na próxima iteração,
esperando que a dimensão tenha chegado até lá. Repita esse processo um
número pré-determinado de vezes antes de declarar a falha.
 Inserir um registro fictício na tabela de dimensões: nessa técnica, se o
registro de dimensão correspondente não existir, basta inserir um registro
fictício em seu lugar. Você terá que revisitar todos os registros fictícios e
atualizá-los com valores reais assim que os valores de dimensão chegarem.
 Se você tiver detalhes suficientes sobre a dimensão, poderá inferir a linha de
dimensão e inserir a nova linha de dimensão derivada com uma nova chave
substituta.

Essas são algumas das maneiras de lidar com dados que chegam atrasados.
Vejamos a seguir como atualizar dados.

Atualizando dados
Upsert refere-se a ou transações em armazenamentos de dados. Os
armazenamentos de dados podem ser relacionais, chave-valor ou qualquer outro
repositório que ofereça suporte ao conceito de atualização de linhas ou
blobs. UPDATEINSERT

O ADF oferece suporte a operações upsert se o coletor for um armazenamento


baseado em SQL. O único requisito adicional é que a atividade do coletor deve
ser precedida por uma operação Alter Row. Aqui está um exemplo de captura de
tela de um coletor de ADF com Permitir upsert habilitado.

Figura 9.29 – Operação de upsert no ADF

Depois de salvar a configuração anterior, o ADF fará um upsert automaticamente


se uma linha já existir no coletor configurado. Vejamos a seguir como regredir para
um estado anterior.

Regressão a um estado anterior


Reverter para um estado anterior ou reverter para um estado estável é uma
técnica muito usada em bancos de dados e cenários OLTP. Em cenários OLTP,
as instruções de transformação são agrupadas em uma transação e, se qualquer
uma das instruções falhar ou atingir um estado inconsistente, toda a transação
será revertida. Embora os bancos de dados forneçam essa funcionalidade, não
temos esse suporte pronto no Azure Data Factory ou no Oozie (HDInsight)
atualmente. Teremos que construir nossas próprias etapas de reversão
dependendo da atividade. Vejamos um exemplo de como fazer uma reversão de
uma atividade de cópia de dados no ADF.

O ADF fornece opções para verificar a consistência e definir limites para tolerância
a falhas. Você pode habilitá-los nas opções Configurações de uma atividade de
cópia, conforme mostrado na captura de tela a seguir.

Figura 9.30 – Habilitando a verificação de consistência e tolerância a falhas em


uma atividade de cópia do ADF

Se a atividade falhar devido a verificações de consistência ou tolerância a falhas


além de um nível, você poderá definir uma atividade Excluir acompanhamento no
caminho de falha (link laranja) para limpar completamente o diretório, conforme
mostrado na captura de tela a seguir.
Figura 9.31 – Excluindo uma atividade de cópia incompleta

Nota

Você pode marcar a caixa de seleção Recursivamente para processar todos os


arquivos na pasta de entrada e suas subpastas recursivamente.

Observe que a técnica de atividade de exclusão pode ser estendida para outros
cenários, como inserção de dados em tabelas, repetição de transformações e
assim por diante. As técnicas de reversão correspondentes nesses casos também
serão diferentes, como excluir arquivos, excluir linhas em uma tabela e assim por
diante.

Espero que você tenha a ideia de como reverter para um estágio anterior usando
o ADF. Em seguida, nos concentraremos no serviço de Lote do Azure sobre o qual
falamos na introdução deste capítulo.

Apresentando o Lote do Azure


O Lote do Azure é um serviço do Azure que pode ser usado para executar
processamento em lote paralelo em grande escala. Ele é normalmente usado para
aplicações de computação de alto desempenho, como análise de imagem,
renderização 3D, sequenciamento de genoma, reconhecimento óptico de
caracteres e assim por diante.

O Lote do Azure consiste em três componentes principais:

 Gerenciamento de recursos: cuida do gerenciamento de nós (coisas como


VMs e contêineres do Docker), dimensionamento automático, gerenciamento
de VMs de baixa prioridade e gerenciamento de aplicativos. Os
aplicativos são apenas arquivos ZIP de todos os executáveis, bibliotecas e
arquivos de configuração necessários para serem executados para o trabalho
em lote.
 Gerenciamento de processos: cuida do agendamento de tarefas e
trabalhos, repetindo trabalhos com falha, impondo restrições aos trabalhos
e assim por diante. Um trabalho é uma unidade lógica de trabalho. Um
trabalho é dividido em tarefas que podem ser executadas em paralelo nos nós
da VM ou do pool de contêineres.
 Monitoramento de recursos e processos: Cuida de todos os aspectos de
monitoramento. Há várias opções disponíveis por meio do portal do Azure, do
Application Insights e, finalmente, de logs e métricas.

Como qualquer outro serviço do Azure, o Lote pode ser completamente


provisionado usando o portal do Azure. Aqui está um exemplo de captura de tela
de uma tela em lote.
Figura 9.32 – Tela do portal do Lote do Azure

Você pode configurar e monitorar seus trabalhos em lote diretamente do portal.


Vamos ver como executar um trabalho em lote usando a CLI a seguir.

Executando um trabalho em Lote do Azure de


exemplo
O Lote do Azure fornece várias abordagens para executar trabalhos. Podemos
usar o portal do Azure, a CLI do Azure e até mesmo interfaces programáticas
via .NET e PowerShell. Vejamos um exemplo usando a CLI do Azure para este,
pois já exploramos bastante o portal do Azure.

Neste exemplo, aprenderemos como criar uma conta do Lote do Azure e


configurar um pool de VMs para executar o trabalho. Em seguida, aprenderemos
como executar um aplicativo no pool e baixar os resultados. Você terá que
substituir as opções destacadas dentro <> por suas próprias entradas. Você
pode criar um temporário no portal do Azure e usá-lo nesses exemplos. Para
todas as outras entradas, como , e assim por diante, você pode apenas especificar
seus próprios nomes: ResourceGroupBatchAccountNameBatchPoolName

1. Crie uma conta em lote conforme mostrado:


az batch account create -g <ResourceGroup> -n <BatchAccountName> -l centralus
CopyExplain
2. Crie uma conta de armazenamento conforme mostrado:
az storage account create -g <ResourceGroup> -n <BatchStoreAcct> -l centralus --sku

Standard_LRS
CopyExplain
3. Agora, vincule a conta de armazenamento à conta em lote:
az batch account set -g <ResourceGroup> -n <BatchAccountName> --storage-account

<BatchStoreAcct>
CopyExplain
4. Em seguida, crie um pool usando VMs do Ubuntu para executar nosso
aplicativo em lote. Esta operação leva alguns minutos:
5. az batch pool create \

6.     --id <ResourceGroup> --vm-size Standard_A1_v2 \

7.     --target-dedicated-nodes 2 \

8.     --image canonical:ubuntuserver:16.04-LTS \

    --node-agent-sku-id "batch.node.ubuntu 16.04"


CopyExplain
9. Você pode verificar o status da criação do pool conforme mostrado:
10. az batch pool show --pool-id <BatchPoolName> \

    --query "allocationState"
CopyExplain
11. Em seguida, crie um aplicativo que precisa ser executado pelo trabalho em
lote:
az batch application create --resource-group <ResourceGroup> --name

<BatchAccountName> --application-name sampleapp1


CopyExplain
12. Em seguida, crie um trabalho:
13. az batch job create \

14.     --id <BatchJobName> \

    --pool-id <BatchPoolName>
CopyExplain
15. Crie as tarefas sob o trabalho. As tarefas começarão a ser executadas assim
que você criá-las:
16. for i in {1..4}

17. do

18.    az batch task create \

19.     --task-id sampletask$i \

20.     --job-id <BatchJobName>  \

21.     --command-line "/bin/bash -c 'printenv; sleep 30s'"

done
CopyExplain
22. Monitore os trabalhos conforme mostrado:
23. az batch task show \

24.     --job-id <BatchJobName> \

    --task-id <BatchTaskName>
CopyExplain
25. Faça o download dos resultados conforme mostrado:
26. az batch task file download \

27.     --job-id <BatchJobName> \

28.     --task-id <BatchTaskName> \

29.     --file-path stdout.txt \

    --destination ./stdout.txt
CopyExplain
30. Finalmente, você pode excluir cada uma das entidades conforme mostrado:
31. az batch job delete --job-id <BatchJobName>

32. az batch task delete –job-id <BatchJobName> --task-id <BatchTaskName>

az batch pool delete --pool-id <BatchPoolName>


CopyExplain

Este exemplo deve ter fornecido uma imagem de todo o ciclo de vida de um


trabalho em Lote do Azure. Você pode saber mais sobre o Lote do Azure
aqui: https://docs.microsoft.com/en-us/azure/batch/batch-technical-overview.

Agora que você conhece os conceitos básicos do Lote do Azure, vamos ver como
configurar tamanhos de lote.

Configurando o tamanho do lote


Para configurar o tamanho do lote, exploraremos como determinar o tamanho do
lote no Lote do Azure. O tamanho do lote refere-se ao tamanho dos pools de lotes
e ao tamanho das VMs nesses pools. As diretrizes a seguir são genéricas o
suficiente para que possam ser aplicadas a outros serviços, como Spark e Hive
também.

Aqui estão alguns dos pontos a serem considerados ao decidir sobre o tamanho
do lote:

 Requisitos do aplicativo: com base no uso intensivo de CPU, memória,


armazenamento intensivo ou rede intensiva, você terá que escolher os tipos
certos de VMs e os tamanhos certos. Você pode encontrar todos os
tamanhos de VM com suporte usando o seguinte comando da CLI do Azure
(aqui, está um exemplo):centralus
az batch location list-skus –location centralus
CopyExplain
 Perfil de dados: se você souber como seus dados de entrada são
espalhados, isso ajudará a decidir os tamanhos de VM que serão
necessários. Teremos que planejar a maior quantidade de dados que serão
processados por cada uma das VMs.
 O número de tarefas que podem ser executadas por nó (VM): se suas
tarefas não precisarem de uma VM inteira, será benéfico executar várias
tarefas nas mesmas VMs.
 Pools diferentes para cargas em lote diferentes: se você tiver diferentes tipos
de trabalhos em lote que precisam de capacidades de VM diferentes, será
eficiente ter pools diferentes para os diferentes trabalhos em lote.
 Disponibilidade de VM por região: Nem todos os tipos de VM estarão
disponíveis em todas as regiões. Portanto, você precisa considerar as
geolocalizações ao planejar a criação do pool de lotes.
 Cotas de VM por conta de lote: além da disponibilidade de VM por região,
geralmente há limitações de cota em suas contas de lote e assinaturas do
Azure. Alguns desses limites de cota são limites suaves e podem ser
aumentados por meio de uma solicitação de suporte. Mas, eventualmente,
você atingirá os limites duros. Portanto, planeje o tamanho do pool de lotes
com base em suas limitações de cota. Você pode verificar sua cota na
guia Cotas de contas em lote. Aqui está um exemplo de captura de tela
dessa página.
Figura 9.33 – Cotas de VM em lote

Você pode saber mais sobre as opções de VM em lote


aqui: https://docs.microsoft.com/en-us/azure/batch/batch-pool-vm-sizes.

Vamos ver a seguir como dimensionar recursos no Lote do Azure e em outros


serviços de processamento em lote, como Spark e Synapse SQL.

Recursos de dimensionamento
Dimensionamento refere-se ao processo de aumentar ou diminuir os recursos de
computação, armazenamento ou rede para melhorar o desempenho de trabalhos
ou reduzir despesas. Existem dois tipos de
dimensionamento: Manual e Automático. Como pode ser óbvio, com o
dimensionamento manual, decidimos o tamanho de antemão. Com o
dimensionamento automático, o serviço decide dinamicamente o tamanho dos
recursos com base em vários fatores, como a carga no cluster, o custo de
execução do cluster, restrições de tempo e muito mais.

Vamos explorar as opções de dimensionamento disponíveis no Lote do Azure e,


em seguida, examinar rapidamente as opções disponíveis no Spark e no SQL
também.

Lote do Azure
O Lote do Azure fornece uma das opções de dimensionamento automático mais
flexíveis. Ele permite que você especifique sua própria fórmula de
dimensionamento automático. O Lote do Azure usará sua fórmula para decidir
quantos recursos aumentar ou reduzir.

Uma fórmula de dimensionamento pode ser escrita com base no seguinte:

 Métricas de tempo: usando estatísticas de aplicativo coletadas em intervalos


de 5 minutos
 Métricas de recursos: usando CPU, memória e uso de largura de banda de
rede
 Métricas de tarefas: usando o número de tarefas enfileiradas ou concluídas

A própria tela de dimensionamento automático do Lote do Azure fornece fórmulas


de dimensionamento automático de exemplo que você pode adaptar e aprimorar
às suas necessidades. Aqui está um exemplo de tela de dimensionamento
automático com a fórmula:

Figura 9.34 – Tela de fórmula de dimensionamento automático em lote

O exemplo na captura de tela anterior é definir o número de nós com base na hora
do dia. Você pode encontrar mais exemplos desse tipo para o dimensionamento
em Lote do Azure aqui: https://docs.microsoft.com/en-us/azure/batch/batch-
automatic-scaling.

Vamos ver a seguir como podemos definir opções de dimensionamento nos pools
Spark e Synapse SQL Dedicado.

Azure Databricks
No Azure Databricks, ao criar o cluster, você pode selecionar Habilitar
Dimensionamento Automático e especificar o número de Trabalhadores
Mínimos e Trabalhadores Máximos. O cluster aumentará e reduzirá
automaticamente a escala entre esses dois números com base na carga. Ao
contrário do Lote do Azure, você não tem a flexibilidade de fornecer sua própria
fórmula de dimensionamento aqui.

Figura 9.35 – Opção de dimensionamento automático do Azure Databricks Spark

Se você quiser ter um cluster de tamanho fixo, basta desmarcar a opção Habilitar


dimensionamento automático e fornecer a contagem exata de trabalhadores.

Você pode economizar no custo de seus clusters usando instâncias spot. As


instâncias spot são VMs do Azure não utilizadas que são oferecidas pelo Azure a
um custo mais barato, mas sem garantias de disponibilidade. Se o Azure precisar
da capacidade de volta, ele poderá retirar as VMs spot com 30 segundos de aviso.
Você pode usar essa opção se seus trabalhos puderem lidar com interrupções,
como trabalhos em lote muito grandes, trabalhos de desenvolvimento/teste e
assim por diante.

Sinapse Faísca
Semelhante ao Azure Databricks, o Synapse Spark também oferece a opção de
dimensionamento automático na tela de criação de cluster. A captura de tela a
seguir mostra a tela com a opção Autoscale.

Figura 9.36 – Opção Synapse Spark Autoscale

Em seguida, vamos examinar a opção disponível para pools dedicados do


Synapse SQL.

Sinapse SQL
O Synapse SQL não fornece a opção de dimensionamento automático, mas
fornece a opção de escolher o nível de desempenho do cluster ao criar o cluster,
conforme mostrado na captura de tela a seguir. Quanto maior o número, melhor o
desempenho.

Figura 9.37 – Configuração de desempenho do Synapse SQL durante a criação do


cluster

Agora você sabe como configurar o dimensionamento no Lote do Azure, no Azure


Databricks Spark, no Synapse Spark e no Synapse SQL.

Vamos ver a seguir como configurar a retenção em lote.

Configurando a retenção em lote


O tempo de retenção padrão para tarefas no Lote do Azure é de 7 dias, a menos
que o nó de computação seja removido ou perdido. No entanto, podemos definir o
tempo de retenção necessário ao adicionar um trabalho.

Aqui está um exemplo usando APIs REST. As necessidades devem ser definidas
no corpo da solicitação, conforme mostrado:retentionTime

POST account.region.batch.azure.com/jobs/jobId/tasks?api-version=2021-06-01.14.0
CopyExplain

Examine o seguinte corpo de solicitação:


{

  "id": "jobId",

  "priority": 100,

  "jobManagerTask": {

    "id": "taskId",

    "commandLine": "test.exe",

    "constraints": {

      "retentionTime": "PT1H"

   }

}
CopyExplain

PT1H especifica 1 hora e usa o formato ISO_8601. Você pode saber mais sobre o
formato aqui: https://en.wikipedia.org/wiki/ISO_8601#Durations.

Vejamos a seguir o design e a configuração do tratamento de exceções.

Projetando e configurando o tratamento


de exceções
O Lote do Azure fornece códigos de erro, logs e eventos de monitoramento para
identificar e manipular erros. Uma vez que os erros são identificados, podemos
manipulá-los programaticamente por meio de APIs e código .NET.

Aqui estão alguns exemplos de códigos de erro retornados pelo Batch:


Figura 9.38 – Códigos de erro de lote de amostra

Você pode obter a lista completa de códigos de erro


aqui: https://docs.microsoft.com/en-us/rest/api/batchservice/batch-status-and-error-
codes.

Em seguida, vamos examinar alguns tipos de erro comuns no Lote do Azure.

Tipos de erros
Há quatro grupos comuns de erros:

 Erros de aplicativo: para erros de aplicativo, o Lote do Azure grava a saída


padrão e o erro padrão em e arquivos no diretório de tarefas no nó
de computação. Podemos analisar esses arquivos para identificar o problema
e tomar medidas corretivas.stdout.txtstderr.txt
 Erros de tarefa: uma tarefa é considerada falha se retornar um código de
saída diferente de zero. A falha pode acontecer devido a vários
motivos, como erros de pré-processamento, erros de upload de arquivos ou
erros de linha de comando. Em todos esses casos, os códigos de erro
correspondentes serão definidos. E podemos configurar programaticamente o
Batch para repetir as tarefas até um determinado número de vezes. Para
erros de tarefa, precisamos verificar a propriedade. Essa propriedade contém
detalhes de erros como , , e assim por diante, que podem ajudar a identificar
os erros.executionInforesultexitCodefailureInfo
 Erros de trabalho: um trabalho é uma coleção de tarefas. Semelhante aos
erros de tarefa, precisamos verificar a propriedade para determinar a causa
do erro para os trabalhos.executionInfo
 Erros de arquivo de saída: Durante o upload de arquivos, o Batch grava os
logs em dois arquivos, ou seja, e . Esses dois arquivos precisam ser
verificados em caso de erros de carregamento do arquivo de
saída.fileuploadout.txtfileuploaderr.txt

Vejamos a seguir algumas das ações corretivas comuns.

Ações corretivas
Embora a ação corretiva para cada tipo de erro seja exclusiva, os seguintes
genéricos ajudam se os trabalhos ficarem presos por muito tempo ou se houver
problemas com os nós:

 Reinicialize o nó:
API: POST {batchUrl}/pools/{poolId}/nodes/{nodeId}/reboot?api-version=2021-06-01.14.0
CopyExplain
 Recrie a imagem do nó:
API: POST {batchUrl}/pools/{poolId}/nodes/{nodeId}/reimage?api-version=2021-06-01.14.0
CopyExplain
 Remova o nó do pool:
POST {batchUrl}/pools/{poolId}/removenodes?api-version=2021-06-01.14.0
CopyExplain
 Desative o agendamento de trabalhos nesse pool:
API: POST {batchUrl}/pools/{poolId}/nodes/{nodeId}/disablescheduling?api-version=2021-

06-01.14.0
CopyExplain

A seguir, veremos alguns dos requisitos de segurança e conformidade para


pipelines de dados em geral. Os conceitos e ideias discutidos aqui também se
aplicam a outras tecnologias, como pipelines baseados em Spark e Hive.
Lidar com requisitos de segurança e
conformidade
A segurança e a conformidade continuarão sempre a ser um dos principais
requisitos para qualquer sistema baseado na nuvem. O Azure fornece um serviço
chamado Política do Azure para habilitar e impor políticas de conformidade e
segurança em qualquer um dos serviços do Azure. No nosso caso, pode ser o
Azure Synapse, o Lote do Azure, VMs, VNets e assim por diante. A Política do
Azure ajuda a impor políticas e ações corretivas em escala.

A Política do Azure contém regras de política predefinidas chamadas de


internas. Por exemplo, uma das regras poderia ser Permitir que apenas VMs de
um tipo específico sejam criadas em minha assinatura. Quando essa política é
aplicada, se alguém tentar criar uma VM de uma SKU diferente, a política falhará
na criação da VM. Ele mostrará um erro dizendo Não permitido pela política na
tela de validação para a criação do recurso.

A Política do Azure tem uma enorme lista de políticas predeterminadas e ações


corretivas para diferentes casos de uso de conformidade. Você pode escolher as
políticas que são relevantes para seu aplicativo e aplicá-las. Aqui está uma tela de
exemplo de políticas do Azure:

Figura 9.39 – Exemplos de Política do Azure


Aqui está uma captura de tela da tela Política do Azure onde podemos aplicar
políticas e métodos de correção do Azure.

Figura 9.40 – Aplicar políticas do Azure


Por exemplo, para estar em conformidade com a HIPAA, um dos requisitos é
garantir que o log de auditoria esteja habilitado.

Portanto, se qualquer um dos seus serviços do Azure não tiver o log de auditoria
habilitado, a Política do Azure sinalizará um erro de conformidade. Você pode até
configurar a ferramenta para desabilitar o serviço se ele não estiver em
conformidade.

Você pode saber mais sobre o serviço de Política do Azure


aqui: https://docs.microsoft.com/en-us/azure/governance/policy/overview.

Em seguida, vejamos outra técnica recomendada para aprimorar a segurança dos


sistemas de processamento em lote, o Benchmark de Segurança do Azure.

O Benchmark de Segurança do Azure


Além da Política do Azure, o Azure também fornece um conjunto de
recomendações para melhorar a segurança de dados, serviços e cargas de
trabalho baseados em nuvem. Esse conjunto de práticas recomendadas é
chamado de Benchmark de Segurança do Azure. Esse benchmark abrange uma
ampla gama de áreas, como segurança de rede, gerenciamento de identidade,
registro em log, proteção de dados e assim por diante. Você pode validar seu
serviço em relação a esse benchmark para garantir que está seguindo o padrão
do setor.

Exemplos de regras de benchmark de segurança de rede (NS) são os seguintes:

 NS-1: Implantar pool(s) de Lotes do Azure em uma rede virtual.


 NS-2: Conecte redes privadas.
 NS-3: Estabeleça acesso de rede privada aos serviços do Azure.
 NS-4: Proteja aplicativos e serviços contra ataques de rede externa.

Exemplos de regras de benchmark de gerenciamento de identidades são os


seguintes:

 IM-1: Padronize o Azure AD como o sistema central de identidade e


autenticação.
 IM-2: Gerencie identidades de aplicativos de forma segura e automática.
 IM-3: use o logon único (SSO) do Azure AD para acesso ao aplicativo e
assim por diante.

Você pode encontrar a lista completa


aqui: https://docs.microsoft.com/en-us/security/benchmark/azure/overview.

Vamos examinar a seguir algumas das práticas recomendadas para o serviço Lote
do Azure.

Práticas recomendadas para o Lote do Azure


Aqui está um resumo de algumas das práticas recomendadas para proteger
sistemas em lote derivados da documentação do Azure:

 Usar pontos de extremidade privados: você pode usar o serviço Link


Privado do Azure para restringir o acesso aos serviços de processamento em
lote de redes externas.
 Criar pools em redes virtuais: no serviço de Lote do Azure, você pode criar
pools de lotes em uma rede virtual para que os nós possam se comunicar
com segurança uns com os outros.
 Criar pools sem endereços IP públicos: para reduzir as chances de
descoberta de redes públicas.
 Limite o acesso remoto aos nós do pool configurando firewalls.

 Criptografe dados em trânsito usando https://.

 Criptografe dados em lote em repouso usando chaves secretas.

 Aplique políticas de conformidade e segurança descritas nas seções


anteriores à sua instância do Lote do Azure.

Você pode encontrar uma lista exaustiva


aqui: https://docs.microsoft.com/en-us/azure/batch/security-best-practices.

Resumo
Espero que agora você tenha uma boa ideia sobre os pipelines de lote e o serviço
de Lote do Azure. Aprendemos sobre a criação de pipelines em lote de ponta a
ponta mergulhando profundamente em cada um dos estágios, como ingestão,
transformações, integrações de BI e assim por diante. Em seguida, aprendemos
sobre um novo serviço chamado Lote do Azure e aprendemos sobre retenção de
lote, manipulação de erros, manipulação de dimensionamento automático, criação
de pipelines de dados usando Lote e muito mais. Também aprendemos sobre
alguns dos aspectos críticos de segurança e conformidade. É muita informação
para mastigar. Apenas tente olhar o capítulo mais uma vez se tiver alguma dúvida.

Em seguida, nos concentraremos em como projetar e desenvolver uma solução de


processamento de fluxo.

Capítulo 10: Projetando e desenvolvendo


uma solução de processamento de fluxo
Bem-vindo ao próximo capítulo da série de transformação de dados. Este capítulo trata de
soluções de processamento de fluxo, também conhecidas como sistemas de processamento
em tempo real. Semelhante ao processamento em lote, o processamento de fluxo é outro
segmento importante dos pipelines de dados. Este também é um capítulo muito importante
para a sua certificação.

Este capítulo se concentrará na introdução dos conceitos e tecnologias envolvidos na


construção de um sistema de processamento de fluxo. Você aprenderá sobre tecnologias
como o Azure Stream Analytics (ASA), os Hubs de Eventos do Azure e o Spark (de uma
perspectiva de streaming). Você aprenderá a criar soluções de streaming de ponta a ponta
usando essas tecnologias. Além disso, você aprenderá sobre conceitos importantes de
streaming, como ponto de verificação, agregações em janelas, reprodução de dados de
fluxo mais antigos, manipulação de desvio e conceitos de gerenciamento de fluxo, como
distribuição de fluxos entre partições, dimensionamento de recursos, manipulação de erros
e atualização de dados.

Depois de concluir este tópico, você deve estar confiante o suficiente para criar um pipeline
de streaming de ponta a ponta usando as tecnologias disponíveis no Azure.
Assim como nos outros capítulos, tomei a liberdade de reorganizar os tópicos
programáticos para este capítulo, agrupando os relacionados. Isso ajuda a criar um bom
fluxo para o capítulo. Abordaremos os seguintes tópicos:

 Projetando uma solução de processamento de fluxo

 Desenvolvendo uma solução de processamento de fluxo usando ASA, Azure


Databricks e Hubs de Eventos do Azure

 Processando dados usando o Spark Structured Streaming

 Monitoramento de desempenho e regressões funcionais

 Processamento de dados de séries temporais

 Projetando e criando agregados em janela

 Configurando pontos de verificação/marca d'água durante o processamento

 Reprodução de dados de fluxo arquivados

 Manipulando desvios de esquema

 Processamento entre partições

 Processamento dentro de uma partição

 Recursos de dimensionamento

 Tratamento de interrupções

 Projetando e configurando o tratamento de exceções

 Atualizando dados

 Projetando e criando testes para pipelines de dados

 Otimização de pipelines para fins analíticos ou transacionais

Requisitos técnicos
Para este capítulo, você precisará do seguinte:
 Uma conta do Azure (pode ser gratuita ou paga)

 A capacidade de ler código Python básico (não se preocupe, é muito fácil)

Vamos começar!

Projetando uma solução de processamento de


fluxo
Sistemas de processamento de fluxo ou sistemas de processamento em tempo real são
sistemas que realizam processamento de dados quase em tempo real. Pense em atualizações
do mercado de ações, atualizações de tráfego em tempo real, detecção de fraude de cartão
de crédito em tempo real e muito mais. Os dados recebidos são processados à medida que
chegam com latência mínima, geralmente na faixa de milissegundos a segundos.
No Capítulo 2, Projetando uma estrutura de armazenamento de dados, aprendemos sobre a
arquitetura Data Lake, onde vimos duas ramificações de processamento: uma para
streaming e outra para processamento em lote. No capítulo anterior, Capítulo 9, Projetando
e desenvolvendo uma solução de processamento em lote, nos concentramos no pipeline de
processamento em lote. Neste capítulo, vamos nos concentrar no processamento de fluxo.
As caixas azuis no diagrama a seguir mostram o pipeline de streaming:
Figura 10.1 – A arquitetura de processamento de fluxo

Os sistemas de processamento de fluxo consistem em quatro componentes principais:

 Um serviço de Ingestão de Eventos, como Hubs de Eventos do Azure, Hub IoT do


Azure, Apache Kafka e assim por diante. que ajuda a capturar, armazenar e
transmitir eventos de várias fontes de entrada para os serviços de processamento de
fluxo. Eles atuam como um buffer entre as fontes de entrada e os serviços de
processamento de dados. Às vezes, a taxa de entrada de eventos pode ser muito grande
para os sistemas de processamento de fluxo manipularem e, às vezes, pode ser muito
pouco. Se a taxa de entrada de eventos for maior, o serviço de ingestão armazenará os
eventos até que os serviços downstream possam processá-los. Se a taxa de entrada de
eventos for menor, o serviço de ingestão pode agrupá-los em lote para obter eficiência
e enviá-los para baixo.
 Sistemas de processamento de fluxo, como ASA, Spark Streaming,
Apache Storm, Apache Flink e assim por diante, que fornecem a capacidade de
filtrar, unir e agregar rapidamente os eventos de entrada para obter insights. Eles
são muito semelhantes às transformações em lote, mas funcionam em tamanhos de
dados muito menores e com mais frequência do que os sistemas em lote.
 Armazenamentos de dados analíticos, como Synapse Dedicated SQL
pool, CosmosDB, HBase e assim por diante, onde os dados processados dos sistemas
de processamento de fluxo geralmente são armazenados para relatórios de BI e outras
consultas ad hoc. Alguns sistemas, como o ASA, podem enviar dados diretamente
para sistemas de relatório, como o Power BI, sem a necessidade de um
armazenamento de dados analíticos.
 Sistemas de relatórios como o Power BI. Esta é a parte final do pipeline onde
apresentamos os dados processados na forma de relatórios para consumo empresarial e
tomada de decisão.

Agora, vamos examinar os serviços que estão disponíveis no Azure para criar sistemas de
processamento de fluxo. Começaremos com os Hubs de Eventos do Azure.

Apresentando os Hubs de Eventos do Azure


Os Hubs de Eventos do Azure são um serviço de ingestão distribuído que pode ingerir,
armazenar e transferir milhões de eventos de várias fontes de entrada para vários
consumidores. Ele atua como um amortecedor entre os produtores de eventos e os
consumidores de eventos e desacopla os produtores de eventos dos consumidores de
eventos. Isso ajuda os componentes downstream, como ASA ou Spark Streaming, a
processar os dados de forma assíncrona. Os Hubs de Eventos do Azure são um serviço
PaaS totalmente gerenciado, portanto, não precisamos nos preocupar com a manutenção do
serviço. Os Hubs de Eventos podem inflar automaticamente para atender aos crescentes
requisitos do sistema de streaming.

Aqui está um diagrama de arquitetura simplificado dos Hubs de Eventos do Azure:

Figura 10.2 – A arquitetura dos Hubs de Eventos do Azure

Como você pode ver no diagrama anterior, os Hubs de Eventos podem receber entradas por
meio de dois protocolos: o HTTP (Hypertext Transfer Protocol) ou o AMQP (Advanced
Message Queuing Protocol). Em seguida, distribui os dados em partições. Os receptores
de eventos, que fazem parte de grupos de consumidores, podem se inscrever nas partições e
ler os eventos a partir daí. Vamos dar uma olhada no que essas terminologias, incluindo
partições e grupos de consumidores, significam.

Partições de Hubs de Eventos


Os Hubs de Eventos distribuem os dados de entrada em uma ou mais partições, como
mostra a Figura 10.2. As partições ajudam no dimensionamento horizontal, pois permitem
que vários consumidores leiam dados em paralelo.

Grupos de consumidores dos Hubs de Eventos

Um grupo de consumidores é uma exibição do hub de eventos. Pode haver muitos grupos
de consumidores para cada hub de eventos, e cada grupo de consumidores pode ter sua
própria visão do hub de eventos. Em outras palavras, eles têm acesso a diferentes conjuntos
de fluxos ou partições. Os consumidores (normalmente, aplicativos downstream) acessam
as partições por meio de seu próprio grupo de consumidores. O grupo de
consumidores mantém compensações semelhantes a estados no fluxo, informações de
checkpoint e muito mais. Os aplicativos dentro de um grupo de consumidores podem
processar os dados de forma independente sem se preocupar com outros clientes.

Você pode saber mais sobre os Hubs de Eventos


em https://docs.microsoft.com/en-us/azure/event-hubs/.

A seguir, vejamos o ASA.

Apresentando o ASA
O ASA é o mecanismo de processamento de fluxo principal do Azure. Ele pode processar
grandes volumes de dados com latências mínimas. Ele pode ser usado para executar
funções analíticas, como filtrar, agregar, unir e muito mais para derivar resultados rápidos
do fluxo de dados recebido. O ASA pode ser usado para cenários como análise de ponto de
venda de varejo, detecção de fraude de cartão de crédito, detecção de IoT e detecção de
falhas, análise de fluxo de cliques e assim por diante. Normalmente, um trabalho ASA tem
três estágios:

1. Ele lê a partir de um serviço de ingestão, como Hubs de Eventos, Hub IoT ou Kafka.
2. Ele processa os dados e gera insights.
3. Por fim, ele grava os dados em um repositório analítico, como o Azure Synapse
Analytics, o CosmosDB ou envia os resultados diretamente para um serviço de
relatório de BI. O ASA pode enviar diretamente os resultados para o Power BI.
Semelhante aos Hubs de Eventos, o ASA também é um serviço PaaS totalmente
gerenciado. Assim, não precisamos nos preocupar com suas atualizações e patches.

Você pode saber mais sobre o ASA em https://docs.microsoft.com/en-us/azure/stream-


analytics/.

A seguir, vamos dar uma olhada no Spark Streaming.

Apresentando o Spark Streaming


Nos capítulos anteriores, analisamos o Spark de uma perspectiva de processamento em lote,
mas o que você pode não estar ciente é que você pode usar as mesmas APIs principais do
Apache Spark para criar uma solução de streaming. Semelhante ao ASA, o Spark também
pode ler serviços de ingestão de dados, como Hubs de Eventos do Azure, Kafka e muito
mais, implementar as transformações de dados e, finalmente, gravar a saída em bancos de
dados analíticos ou qualquer outro armazenamento.

O Spark Streaming divide internamente o fluxo de entrada em microlotes e os processa, de


modo que a saída será um fluxo de microlotes.

Você pode saber mais sobre o Spark Streaming


em https://spark.apache.org/docs/latest/streaming-programming-guide.html.

Em seguida, vamos ver como criar uma solução de processamento de fluxo usando todas as
tecnologias que aprendemos até agora.

Desenvolvendo uma solução de


processamento de fluxo usando ASA, Azure
Databricks e Hubs de Eventos do Azure
Nesta seção, veremos dois exemplos: um com ASA como mecanismo de streaming e outro
com Spark como mecanismo de streaming. Usaremos um gerador de eventos fictício para
gerar continuamente eventos de viagem. Configuraremos o ASA e o Azure Databricks
Spark para executar o processamento em tempo real e publicar os resultados. Primeiro,
vamos começar com o ASA.

Uma solução de streaming usando Hubs de Eventos e


ASA
Neste exemplo, criaremos um pipeline de streaming criando uma instância de Hubs de
Eventos, uma instância de ASA e vinculando-os. O pipeline lerá um fluxo de exemplo de
eventos, processará os dados e exibirá o resultado no Power BI:

1. Primeiro, vamos criar uma instância do Hub de Eventos. No portal do Azure,


pesquise e clique no botão Criar, conforme mostrado na captura de tela a seguir:Event
Hubs

Figura 10.3 – A tela de criação dos Hubs de Eventos

2. Isso abrirá a tela Criar namespace dos Hubs de Eventos, conforme mostrado na


captura de tela a seguir. Preencha os detalhes, incluindo Grupo de recursos, Nome
do namespace, Local, Unidades de taxa de transferência e quaisquer outros campos
obrigatórios:
Figura 10.4 – Criando o namespace dos Hubs de Eventos

3. Insira os detalhes e clique no botão Revisar + criar para criar o espaço de trabalho


Hubs de Eventos. Depois que o espaço de trabalho tiver sido criado, clique no link +
Hub de Eventos (conforme mostrado na captura de tela a seguir) para criar um novo
hub de eventos dentro do espaço de trabalho:
Figura 10.5 – Criando um hub de eventos de dentro do espaço de trabalho Hubs de Eventos

4. Isso exibirá uma tela, conforme mostrado na captura de tela a seguir. Digite


um Nome no campo fornecido, selecione o valor de Contagem de
Partições (aprenderemos mais sobre partições mais tarde) e clique em Criar:

Figura 10.6 – A tela Criar Hub de Eventos

5. Agora que temos um hub de eventos, em seguida, vamos criar uma instância ASA.
Pesquise no portal do Azure e selecione a opção. Na página de trabalhos do Stream
Analytics, clique no link + Criar:Stream Analyticsjobs
Figura 10.7 – Criando um trabalho ASA

6. Isso exibirá a tela de criação de trabalho de análise, conforme mostrado na captura de


tela a seguir. Preencha os detalhes, incluindo Nome do trabalho, Assinatura, Grupo
de recursos, Local, Unidades de streaming e quaisquer outros campos obrigatórios.
Em seguida, clique no botão Criar para criar um novo trabalho ASA:
Figura 10.8 – A tela de criação do ASA

7. A próxima etapa é vincular a entrada aos Hubs de Eventos. Antes desta etapa,


precisaremos obter a cadeia de conexão dos Hubs de Eventos. Vá para a página Hubs
de Eventos e clique em Políticas de acesso compartilhado. Clique no botão +
Adicionar e adicione uma nova política, conforme mostrado na captura de tela
a seguir:
Figura 10.9 – Criando políticas de acesso compartilhado em Hubs de Eventos

8. Depois que a política tiver sido criada, você pode simplesmente clicar na política para
recuperar o link Cadeia de conexão, conforme mostrado na captura de tela a seguir:
Figura 10.10 – Acessando a cadeia de conexão para Hubs de Eventos

9. Agora, volte para o portal do ASA e vincule a entrada (Hubs de Eventos) e a saída


(Power BI) à instância do ASA. Clique na guia Entradas e selecione Hub de
Eventos na lista suspensa + Adicionar entrada de fluxo. Isso exibirá uma tela onde
você poderá selecionar a instância do Hub de Eventos criada anteriormente:
Figura 10.11 – Selecionando um hub de eventos como entrada para o trabalho do ASA

10. Na tela de entrada Novo do Hub de Eventos, insira a cadeia de conexão copiada


da Figura 10.10:
Figura 10.12 – Vinculando o hub de eventos como uma entrada no ASA

11. Da mesma forma, clique na guia Saídas e selecione Power BI para a saída ASA:

Figura 10.13 – Selecionando o Power BI como saída para o trabalho do ASA

12. Isso exibirá uma tela da seguinte maneira. Aqui, você terá que preencher seus
detalhes do Power BI:
Figura 10.14 – Configurando os detalhes do coletor do Power BI para o trabalho do ASA

13. Agora que temos a entrada e a saída configuradas e prontas, execute um gerador de


eventos de exemplo para gerar eventos de teste. Aqui está um módulo gerador de
eventos Python simples. O código completo está disponível no repositório GitHub que
o acompanha.

a) Importe as bibliotecas necessárias do Hub de Eventos:


from azure.eventhub.aio import EventHubProducerClient

from azure.eventhub import EventData


CopyExplain

b) Instanciar um cliente:producer

producer = EventHubProducerClient.from_connection_string(

      conn_str=<SAS Access Connection String>,

      eventhub_name=<Event Hub Name>)


CopyExplain

c) Crie uma instância de lote de eventos:

eventDataBatch = await producer.create_batch()


CopyExplain

d) Criar um evento JSON:

cityList = ["San Franciso", "San Jose", "Los Angeles",…]

tripDetail = {'tripId': str(uuid.uuid4()),

     'timestamp': str(datetime.datetime.utcnow()),

     'startLocation': random.choice(cityList),

     'endLocation': random.choice(cityList),

     'distance': random.randint(10, 1000),

     'fare': random.randint(100, 1000) }


CopyExplain

e) Adicionar eventos ao lote:

eventDataBatch.add(

      EventData(json.dumps(tripDetail)))
CopyExplain

f) Enviar o lote de eventos para o hub de eventos:


producer.send_batch(eventDataBatch)
CopyExplain

Você pode repetir as etapas d, e e f em um loop pelo tempo que precisar.for

14. Ao executar o código anterior a partir da linha de comando, você poderá exibir os
eventos que chegam ao hub de eventos na página de visão geral dos Hubs de Eventos,
da seguinte maneira:

Figura 10.15 – As páginas de visão geral dos Hubs de Eventos mostrando as métricas de
evento

15. Agora, vamos ler esses dados e publicar o número de viagens por local. Na
página Visão geral do ASA, você pode inserir a Consulta, conforme mostrado na
captura de tela a seguir, e clicar em Iniciar:
Figura 10.16 – O código de exemplo ASA

16. Agora, o trabalho do ASA lerá continuamente o fluxo do hub de eventos de entrada,
processará os dados e os publicará no Power BI. Se você navegar até Meu espaço de
trabalho no portal do Power BI, verá o conjunto de dados ASA configurado
anteriormente na tela de configuração de saída do Power BI (Figura 10.14):
Figura 10.17 – A tela do conjunto de dados do Power BI

17. Você pode clicar com o botão direito do mouse no conjunto de dados e criar um
relatório a partir dele, conforme mostrado na captura de tela a seguir:
Figura 10.18 – Criando o painel do Power BI a partir da saída de streaming do ASA

Agora você sabe como criar um pipeline de streaming usando Hubs de Eventos, ASA e
Power BI.

O ASA também pode trabalhar com o Hub IoT como serviço de ingestão. Com o Hub IoT,
o ASA pode ser implantado em dois modos diferentes:

 No modo de nuvem: aqui, os dispositivos IoT enviam os eventos para um trabalho


ASA na nuvem do Azure, que é muito semelhante ao modelo de Hubs de Eventos.
 No modo de Borda: aqui, o ASA pode ser executado diretamente nos próprios
dispositivos IoT, executar processamento em tempo real e enviar os eventos para o
Hub IoT.

Você pode encontrar mais detalhes sobre o modo Edge do ASA


em https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-deploy-stream-analytics?
view=iotedge-2020-11.

Em seguida, vamos ver como criar uma solução de streaming usando o Azure Databricks
Spark.
Uma solução de streaming usando Hubs de Eventos e
Spark Streaming
Neste exemplo, usaremos o mesmo hub de eventos e gerador de dados que usamos para a
opção ASA. A única alteração é que usaremos o Azure Databricks Spark em vez do ASA.
Vejamos como ler dados de Hubs de Eventos usando o Databricks Spark.

Antes de nos conectarmos aos Hubs de Eventos e começarmos a ler, teremos que criar um
cluster do Spark. Aprendemos como criar um cluster Databricks Spark no Capítulo
9, Projetando e desenvolvendo uma solução de processamento em lote, na
seção Desenvolvendo soluções de processamento em lote usando Data Factory, Data Lake,
Spark, Azure Synapse Pipelines, PolyBase e Azure Databricks. Use as mesmas instruções
para criar um novo cluster do Spark:

1. Quando o cluster do Spark estiver em funcionamento, abra um Bloco de Anotações do


Spark e insira o seguinte código de exemplo para processar os dados de fluxo no bloco
de anotações.
2. Defina a conexão com a instância dos Hubs de Eventos da mesma forma que a
geramos na Figura 10.10, conforme mostrado no bloco de código a seguir:
3. EHConnectionString = "<EVENT HUB CONNECTION STRING>"

4. EHConfig = {}

EHConfig['eventhubs.connectionString'] = sc._jvm.org.apache.spark.eventhubs.EventHubsUtils

.encrypt( EHConnectionString )
CopyExplain
5. Conecte-se ao hub de eventos:
EHStreamDF = spark.readStream.format("eventhubs") .options(**EHConfig).load()
CopyExplain
6. Em seguida, precisamos definir o esquema da entrada de streaming:
7. JsonSchema = StructType() \

8. .add("tripId", StringType()) \

9. .add("createdAt", TimestampType()) \

10. .add("startLocation", StringType()) \


11. .add("endLocation", StringType()) \

12. .add("distance", IntegerType()) \

.add("fare", IntegerType())
CopyExplain
13. Agora, vamos definir o DataFrame () de manipulação de fluxo para extrair os valores
de chave dos eventos JSON de entrada:EHStreamJsonDF
14. stringDF = EHStreamDF.selectExpr("CAST(body AS STRING)")

15. jsonDF= stringDF.withColumn('tripjson', from_json(col('body'),schema=JsonSchema))

EHStreamJsonDF= jsonDF.select("tripjson.*")
CopyExplain
16. Até este ponto, garantimos que os eventos do hub de eventos possam ser processados
e acionados diretamente usando DataFrames. O próximo passo é definir a
transformação a ser aplicada e realmente iniciar o streaming:
17. EHStreamJsonDF.groupBy(window('createdAt',"1

minutes"),'startLocation').count().orderBy('window')\

18. .writeStream.format("memory") \

19. .outputMode("complete") \

20. .option("truncate", "false") \

21. .option("checkpointLocation", "dbfs:/tripsCheckpointLocation/") \

.queryName("TripsTumblingQuery").start()
CopyExplain
22. Na etapa anterior, estamos usando uma janela de 1 minuto e contando o número de
viagens com base no . Nas próximas seções, aprenderemos sobre janelas, os diferentes
modos de saída, pontos de verificação e muito mais.startLocation
23. Depois de executar a Etapa 6, o streaming é iniciado e procura continuamente eventos
do hub de eventos, processa-os e envia a saída para uma tabela chamada . Se você da
tabela, você pode ver as contagens de viagem: TripsTumblingQuerySELECT *
Figura 10.19 – Exibindo os resultados da consulta de streaming

9. Você pode interromper o streaming, conforme mostrado no bloco de código a seguir:


10. for s in spark.streams.active:

    s.stop()
CopyExplain

Portanto, é assim que podemos conectar o Azure Databricks aos Hubs de Eventos e
processar dados em tempo real.

Você pode saber mais sobre os Hubs de Eventos e Databricks do Azure


em https://docs.microsoft.com/en-us/azure/databricks/scenarios/databricks-stream-from-
eventhubs.

A seguir, vamos analisar o Spark Structured Streaming.

Processando dados usando o Spark


Structured Streaming
O Streaming Estruturado é um recurso do Apache Spark em que o fluxo de entrada é
tratado como uma tabela ilimitada. Os dados de streaming de entrada são continuamente
anexados à tabela. Esse recurso facilita a gravação de consultas de streaming, pois agora
podemos escrever transformações de streaming da mesma forma que lidamos com
transformações baseadas em tabela. Portanto, a mesma sintaxe de processamento em lote
do Spark também pode ser aplicada aqui. O Spark trata as consultas de Streaming
estruturado como consultas incrementais em uma tabela ilimitada e as executa em
intervalos frequentes para processar continuamente os dados.

O Spark oferece suporte a três modos de gravação para a saída do Streaming estruturado:

 Modo completo: nesse modo, toda a saída (também conhecida como tabela de


resultados) é gravada no coletor. O coletor pode ser um repositório de blobs, um data
warehouse ou uma ferramenta de BI.
 Modo de acréscimo: neste modo, somente as novas linhas da última vez são gravadas
no coletor.
 Modo de atualização: neste modo, apenas as linhas que foram alteradas são
atualizadas; as outras linhas não serão atualizadas.

Na seção anterior, quando usamos o Azure Databricks Spark para processar o fluxo, já
havíamos usado o conceito de Spark Structured Streaming. Toda vez que usamos os
métodos or, o Spark usa o Structured Streaming. Vejamos outro exemplo em que
escrevemos continuamente os dados de viagens de streaming e os consultamos como uma
tabela normal:writestreamreadstream

EHStreamJsonDF.selectExpr(

                  "tripId"\

                  ,"timestamp"\

                  ,"startLocation"\

                  ,"endLocation"\

                  ,"distance"\

                  ,"fare")\

.writeStream.format("delta")\

.outputMode("append")\

.option("checkpointLocation", "dbfs:/TripsCheckpointLocation/")\

.start("dbfs:/TripsEventHubDelta")
CopyExplain
Na consulta anterior, estamos especificando os nomes de coluna a serem extraídos como
parte de , o formato a ser gravado como delta, o modo de saída como , o local do ponto de
verificação como e, finalmente, o local do coletor a ser gravado como dentro do
método. Delta é uma camada de armazenamento de código aberto que pode ser executada
sobre data lakes. Ele aprimora o data lake para suportar recursos como transações ACID,
atualizações, exclusões, sistemas unificados em lote, interativos e streaming via Spark.
Aprenderemos mais sobre a Delta na seção Compactando arquivos pequenos do Capítulo
14, Otimizando e solucionando problemas de armazenamento e processamento de
dados.selectExprappenddbfs:/TripsCheckpointLocationdbfs:/TripsEventHubDeltastart
()

Agora você pode consultar os dados como uma tabela normal, da seguinte maneira:

%sql

CREATE TABLE IF NOT EXISTS TripsAggTumbling

    USING DELTA LOCATION "dbfs:/TripsEventHubDelta/"

SELECT * FROM TripsAggTumbling


CopyExplain

É assim que podemos usar o Spark Structured Streaming para lidar com dados de
streaming. Você pode saber mais sobre Streaming Estruturado em
https://docs.microsoft.com/en-us/azure/databricks/getting-started/spark/streaming.

A seguir, vamos ver como monitorar o desempenho do streaming.

Monitoramento de desempenho e regressões


funcionais
Vamos explorar as opções de monitoramento disponíveis em Hubs de Eventos, ASA e
Spark para cenários de streaming.

Monitoramento em Hubs de Eventos


A guia Métrica dos Hubs de Eventos fornece métricas que podem ser usadas para
monitoramento. Aqui está uma captura de tela de exemplo das opções de métrica
disponíveis:

Figura 10.20 – A tela de métricas dos Hubs de Eventos

Podemos obter métricas úteis, como o número de Mensagens de Entrada, o número de


Mensagens de Saída, Erros de Servidor, utilização de CPU e memória e muito mais. Você
pode usar todas essas métricas para plotar gráficos e painéis, conforme necessário.

Em seguida, vamos examinar as opções de monitoramento no ASA.

Monitoramento em ASA
A página Visão geral do ASA fornece métricas de monitoramento de alto nível, conforme
mostrado na captura de tela a seguir:
Figura 10.21 – Página de visão geral do ASA com métricas

Semelhante à página de métricas dos Hubs de Eventos, o ASA também fornece um


conjunto avançado de métricas que podem ser usadas para monitoramento. Aqui está um
exemplo de captura de tela da guia Métrica ASA:

Figura 10.22 – A guia Métrica ASA com métricas

Como você pode ver na captura de tela anterior, ele fornece informações úteis, como SU %
Utilização, Erros de Tempo de Execução, Atraso de Marca D'Água e muito mais.
Podemos até configurar alertas em cima dessas métricas. Vejamos um exemplo de como
configurar um alerta para disparar se o SU% ultrapassar 80%.
Configurando alertas no ASA

Vamos examinar como configurar um alerta para alto uso de SU%.

Selecione o link Nova regra de alerta na Figura 10.22. Isso o levará a uma página que


lista todos os sinais disponíveis para criar o alerta. Selecione a opção SU % de utilização,
conforme mostrado na captura de tela a seguir:

Figura 10.23 – Selecionando o nome do sinal para configurar o alerta

Na página que é aberta, você pode configurar a lógica de alerta para definir o limite para
80%. Isso é mostrado na captura de tela a seguir:
Figura 10.24 – Configurando a lógica de alerta do ASA

Depois de definirmos a lógica de alerta, temos que definir um grupo de ação (não mostrado
na captura de tela anterior) para determinar o que deve ser feito quando a condição anterior
corresponder. Podemos vinculá-lo a um runbook de automação, acionar uma função do
Azure para executar uma ação, acionar um Webhook ou simplesmente enviar notificações
usando emails.

O processo de criação de alertas é semelhante a outras tecnologias, como Hubs de Eventos,


Synapse SQL e muito mais.

Em seguida, vamos ver as opções de monitoramento disponíveis no Spark Streaming.

Monitoramento no Spark Streaming


Os blocos de anotações do Azure Databricks Spark fornecem gráficos internos que exibem
continuamente métricas como taxa de entrada, taxa de processamento, duração do
lote e muito mais. Aqui está um exemplo de captura de tela:
Figura 10.25 – Métricas do Spark Streaming de dentro de um bloco de anotações do Spark

Esses gráficos podem ser usados para monitorar o progresso dos trabalhos do Spark
Streaming.

É assim que podemos monitorar os trabalhos de streaming. Vejamos a seguir como


processar dados de séries temporais.

Processamento de dados de séries temporais


Dados de séries temporais nada mais são do que dados registrados continuamente ao longo
do tempo. Exemplos de dados de séries temporais podem incluir preços de ações
registrados ao longo do tempo, valores de sensores IoT, que mostram a integridade das
máquinas ao longo do tempo, e muito mais. Os dados de séries temporais são usados
principalmente para analisar tendências históricas e identificar quaisquer anormalidades nos
dados, como fraude de cartão de crédito, alertas em tempo real e previsão. Os dados de
séries temporais serão sempre fortemente acrescentados com atualizações muito raras.

Os dados de séries temporais são um candidato perfeito para processamento em tempo real.
As soluções de processamento de fluxo que discutimos anteriormente neste capítulo, na
seção Desenvolvendo uma solução de processamento de fluxo usando ASA, Azure
Databricks e Hubs de Eventos do Azure, funcionariam perfeitamente para dados de série
temporal. Vejamos alguns dos conceitos importantes de dados de séries temporais.

Tipos de carimbos de data/hora


O aspecto central de qualquer dado de série temporal é o atributo temporal. Existem dois
tipos de dados de séries temporais no tempo:

 Hora do evento: indica a hora real em que o evento ocorreu.


 Tempo de processamento: O momento em que o evento é processado por um sistema
de processamento de dados.

É importante considerar o tempo do evento durante o processamento de eventos em vez do


tempo de processamento, pois este último pode ser atrasado devido à velocidade de
processamento, atrasos na rede e outros problemas no pipeline de processamento de fluxo.

Agregados janelados
Como os eventos de séries temporais são eventos ilimitados, ou em outras palavras, como
eles não têm uma hora de término bem definida, é necessário processar os eventos em
pequenos lotes (ou seja, janelas de tempo). Existem diferentes mecanismos de janelas
disponíveis, como janelas de tombamento, janelas saltitantes, janelas de correr e muito
mais. Exploraremos essas técnicas de janelamento, em detalhes, na próxima seção.

Ponto de verificação ou marca d'água


Ponto de verificação ou marca d'água refere-se ao processo de manter o controle do último
evento ou carimbo de data/hora que foi processado pelo sistema de processamento de fluxo.
Isso ajuda a garantir que comecemos do local parado anteriormente e não percamos o
processamento de nenhum evento após interrupções, atualizações do sistema, atrasos de
processamento e muito mais. Aprenderemos como podemos conseguir isso na
seção Configurando pontos de verificação/marca d'água durante o processamento deste
capítulo.

Reproduzir dados de um carimbo de data/hora anterior


Podemos ser obrigados a reprocessar eventos mais antigos no caso de falhas de máquina ou
erros na lógica de processamento. Nesses casos, ferramentas como Hubs de Eventos
fornecem recursos que permitem reproduzir os eventos novamente de um local de
deslocamento anterior.

Você pode saber mais sobre dados de séries temporais em https://docs.microsoft.com/en-


us/azure/architecture/data-guide/scenarios/time-series.

A seguir, vamos dar uma olhada em cada um dos conceitos, em detalhes, começando com
as diferentes opções de agregação em janela.

Projetando e criando agregados em janela


Nesta seção, vamos explorar as diferentes agregações em janela disponíveis no ASA. O
ASA suporta os seguintes cinco tipos de janelas:

 Janelas de tombo

 Janelas de salto

 Janelas de correr

 Janelas de sessão

 Janelas de instantâneo

Vejamos cada um deles em detalhes. Usaremos o seguinte esquema de evento de exemplo


em nossos exemplos.

eventSchema = StructType()

  .add("tripId", StringType())

  .add("createdAt", TimestampType())

  .add("startLocation", StringType())

  .add("endLocation", StringType())

  .add("distance", IntegerType())

  .add("fare", IntegerType())
CopyExplain

Comecemos pelas janelas do Tumbling.

Janelas de tombo
As janelas de tombo são janelas de tempo não sobrepostas. Todas as janelas são do mesmo
tamanho. Aqui está uma representação de como eles se parecem:

Figura 10.26 – Um exemplo de janela de tombamento

Aqui está a sintaxe de como usar uma janela de tombamento:

{TUMBLINGWINDOW | TUMBLING} ( timeunit  , windowsize, [offsetsize] )  

{TUMBLINGWINDOW | TUMBLING} ( Duration( timeunit  , windowsize ), [Offset(timeunit  ,

offsetsize)] )
CopyExplain

Aqui está o código de exemplo para usar uma janela de tombamento no ASA. Ele calcula o
número de viagens agrupadas por , em janelas de tombamento de 10 segundos de
largura:tripLocation

SELECT System.Timestamp() AS WindowEnd, tripLocation, COUNT(*)  

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt  

GROUP BY tripLocation, TumblingWindow(Duration(second, 10), Offset(millisecond, -1))


CopyExplain

Em seguida, vamos olhar para as janelas de salto.

Janelas de salto
Janelas saltitantes são apenas janelas sobrepostas. Cada janela terá uma sobreposição de
tamanho fixo com a janela anterior. Aqui está uma representação de como parece:

Figura 10.27 – Um exemplo de uma janela de salto

Aqui está a sintaxe de uma janela de salto:

{HOPPINGWINDOW | HOPPING} ( timeunit  , windowsize , hopsize, [offsetsize] )

{HOPPINGWINDOW | HOPPING} ( Duration( timeunit  , windowsize ) , Hop (timeunit  ,

windowsize ), [Offset(timeunit  , offsetsize)])


CopyExplain

Se e tiver o mesmo, você pode usar a primeira sintaxe.windowsizehopsizetimeunit

Aqui está um exemplo de uma janela de salto. A cada 10 segundos, busque a contagem de
viagens para os últimos 20 segundos. Aqui, o tamanho da janela é de 20 segundos e o
tamanho do salto é de 10 segundos:tripLocation

SELECT System.Timestamp() AS WindowEnd, tripLocation, COUNT(*)  

INTO [Output]
FROM [Input]  TIMESTAMP BY createdAt  

GROUP BY tripLocation, HoppingWindow(Duration(second, 20), Hop(second, 10),

Offset(millisecond, -1))
CopyExplain

A seguir, vejamos as janelas deslizantes.

Janelas de correr
As janelas deslizantes têm um tamanho fixo, mas a janela só avança quando um dos
eventos é adicionado ou removido. Caso contrário, eles não emitem nenhum resultado:

Figura 10.28 – Exemplo de janela deslizante

Aqui está a sintaxe da janela deslizante:

{SLIDINGWINDOW | SLIDING} ( timeunit, windowsize )

{SLIDINGWINDOW | SLIDING} ( Duration( timeunit, windowsize ) )


CopyExplain
Aqui está um exemplo de uma janela deslizante. A cada 10 segundos, alerte se um local
aparecer mais de 5 vezes:

SELECT System.Timestamp() AS WindowEnd, tripLocation, COUNT(*)  

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt

GROUP BY tripLocation, SlidingWindow(second, 10)

HAVING COUNT(*) > 5


CopyExplain

Em seguida, vamos examinar as janelas de sessão.

Janelas de sessão
As janelas de sessão não têm tamanhos fixos. Precisamos especificar um tamanho máximo
de janela e duração de tempo limite para janelas de sessão. A janela de sessão tenta capturar
o maior número possível de eventos dentro do tamanho máximo da janela. Por outro lado,
se não houver eventos, ele aguarda a duração do tempo limite e fecha a janela. Aqui está
uma representação de como parece:

Figura 10.29 – Um exemplo de uma janela de sessão

Aqui está a sintaxe da janela de sessão:


{SESSIONWINDOW | SESSION} (timeunit, timeoutSize, maxDurationSize) [OVER (PARTITION

BY partitionKey)]

{SESSIONWINDOW | SESSION} (Timeout(timeunit , timeoutSize), MaxDuration(timeunit,

maxDurationSize)) [OVER (PARTITION BY partitionKey)]


CopyExplain

Aqui está um exemplo de uma janela de sessão. Encontre o número de viagens que ocorrem
dentro de 5 segundos uma da outra:

SELECT System.Timestamp() AS WindowEnd, tripId, COUNT(*)  

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt

GROUP BY tripId, SessionWindow(second, 5, 10)


CopyExplain

Em seguida, vamos dar uma olhada nas janelas de instantâneo.

Janelas de instantâneo
Uma janela de instantâneo não é realmente uma técnica de janela. Ele é simplesmente
usado para obter um instantâneo dos eventos em um determinado momento:

Figura 10.30 – Um exemplo de uma janela de instantâneo

Aqui está como podemos usar uma janela de instantâneo:


SELECT tripId, COUNT(*)

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt

GROUP BY tripId, System.Timestamp()


CopyExplain

Estas são todas as opções de janelas que temos no ASA. Você pode saber mais sobre as
funções de janelas ASA
em https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-window-
functions.

O próximo conceito importante para lidar com dados de séries temporais é o ponto de
verificação ou marca d'água. Vamos mergulhar nesse tópico a seguir.

Configurando pontos de verificação/marca


d'água durante o processamento
Vejamos as opções de ponto de verificação disponíveis no ASA, Hubs de Eventos e Spark.

Apontamento de verificação no ASA


A ASA faz checkpoints internos periodicamente. Os usuários não precisam fazer
checkpoint explícito. O processo de apontamento de verificação é usado para recuperações
de trabalho durante atualizações do sistema, tentativas de trabalho, falhas de nó e muito
mais.

Durante falhas de nó ou atualizações do sistema operacional, o ASA restaura


automaticamente o estado do nó com falha em um novo nó e continua o processamento.

Nota

Durante as atualizações do serviço ASA (não as atualizações do sistema operacional), os


pontos de verificação não são mantidos e o fluxo correspondente ao tempo de inatividade
precisa ser repetido.
Em seguida, vamos ver como fazer checkpoint nos Hubs de Eventos.

Apontamento de verificação em Hubs de Eventos


O ponto de verificação ou marca d'água nos Hubs de Eventos refere-se ao processo de
marcar o deslocamento dentro de um fluxo ou partição para indicar o ponto até onde o
processamento está concluído. O checkpoint nos Hubs de Eventos é de responsabilidade do
processo do consumidor do evento. O checkpoint é uma operação relativamente cara, por
isso geralmente é melhor verificar o ponto após um lote de processamento de eventos. A
ideia principal do checkpoint é ter um ponto de reinicialização no caso de o hub de eventos
falhar ou passar por atualizações de serviço.

Aqui está o código de exemplo de como executar o checkpointing em Hubs de Eventos


usando o armazenamento. Todas as entradas dentro são valores fornecidos pelo
usuário:BlobCheckpoint< >

Import asyncio

from azure.eventhub.aio import EventHubConsumerClient

from azure.eventhub.extensions.checkpointstoreblobaio import BlobCheckpointStore

async def on_event(partition_context, event):

    # Process the event

    # Checkpoint after processing

    await partition_context.update_checkpoint(event)

async def main():

    storeChkPoint = BlobCheckpointStore.from_connection_string(

        <STORE_CONN_STRING>,

        <STORE_CONTAINER_NAME>

    )

    ehClient = EventHubConsumerClient.from_connection_string(

        <EVENTHUB_CONN_STRING>,

        <CONSUMER_GROUP_NAME>,
        eventhub_name=<EVENTHUB_NAME>,

        checkpoint_store= storeChkPoint

    )

    async with ehClient:

        await ehClient.receive(on_event)

if __name__ == '__main__':

    loop = asyncio.get_event_loop()

    loop.run_until_complete(main())
CopyExplain

Em seguida, vamos ver o checkpoint no Spark.

Checkpoint no Spark
O recurso de streaming estruturado do Spark oferece semântica de ponta a ponta. Em outras
palavras, garante que um evento seja entregue exatamente uma vez. O Spark usa logs de
checkpoint e write-ahead para fazer isso. Em nosso exemplo de Streaming estruturado
anteriormente, aprendemos como configurar o local de checkpoint nas consultas do Spark.
Aqui está outro exemplo simples:

EHStreamJsonDF.writeStream.format("delta")\

.outputMode("append")\

.option("checkpointLocation", "dbfs:/TripsCheckpointLocation/")\

.start("dbfs:/TripsEventHubDelta")
CopyExplain

O Spark Structured Streaming cuida do checkpoint internamente. Isso é para que o usuário
não precise se preocupar em verificar manualmente o fluxo de entrada.

Agora que aprendemos como verificar dados de ponto, vamos ver como reproduzir dados
antigos no caso de falhas, reinicializações, atualizações e muito mais.
Reprodução de dados de fluxo arquivados
Os Hubs de Eventos armazenam até 7 dias de dados, que podem ser reproduzidos usando as
bibliotecas de cliente consumidor do EventHub. Aqui está um exemplo simples de Python:

Consumer_client = EventHubConsumerClient.from_connection_string(

    conn_str=CONNECTION_STR,

    consumer_group='$Default',

    eventhub_name=EVENTHUB_NAME,

consumer_client.receive(

    on_event=on_event,

    partition_id="0",

    starting_position="-1" # "-1" is the start of the partition.

)
CopyExplain

Você pode especificar deslocamentos ou carimbos de data/hora para o


valor.starting_position

Você pode saber mais sobre as APIs do Python EventHub


em https://azuresdkdocs.blob.core.windows.net/$web/python/azure-eventhub/latest/
azure.eventhub.html.

Vamos dar uma olhada em algumas das transformações de dados comuns que são possíveis
usando a análise de streaming.

Transformações usando análise de streaming


Um dos temas comuns que você pode notar em consultas de streaming é que, se houver
qualquer tipo de transformação envolvida, sempre haverá agregação de janelas que precisa
ser especificada. Tomemos o exemplo de contar o número de entradas distintas em um
período de tempo.

As transformações COUNT e DISTINCT


Esse tipo de transformação pode ser usado para contar o número de eventos distintos que
ocorreram em uma janela de tempo. Aqui está um exemplo para contar o número de
viagens exclusivas nos últimos 10 segundos:

SELECT

    COUNT(DISTINCT tripId) AS TripCount,

    System.TIMESTAMP() AS Time

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt

GROUP BY TumblingWindow(second, 10)


CopyExplain

Em seguida, vamos ver um exemplo em que podemos converter o tipo de entrada em um


formato diferente.

Transformações CAST
A transformação pode ser usada para converter o tipo de dados em tempo real. Aqui está
um exemplo para converter a tarifa em um e calcular a tarifa total a cada 10
minutos:CASTFLOAT

SELECT tripId, SUM(CAST(fare AS FLOAT)) AS TenSecondFares

INTO [Output]

FROM [Input] TIMESTAMP BY createdAt

GROUP BY tripId, TumblingWindow(second, 10)


CopyExplain

A seguir, vamos ver como comparar entradas usando o .LIKE


Transformações LIKE
Podemos usar essa transformação para executar a correspondência de cadeias de caracteres
usando padrões. No exemplo a seguir, tentamos corresponder a todos os
de:startLocationSan Francisco

SELECT *

INTO [Output]

FROM [Input] TIMESTAMP BY timestamp

WHERE startLocation LIKE 'S%F'


CopyExplain

Essas são apenas algumas transformações de amostra. Você pode encontrar uma lista mais
detalhada em https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-
stream-analytics-query-patterns.

Em seguida, vamos ver como lidar com desvios de esquema em uma solução de streaming.

Manipulando desvios de esquema


Um desvio de esquema refere-se às alterações no esquema ao longo do tempo devido a
alterações que ocorrem nas fontes de eventos. Isso pode ser devido a colunas ou campos
mais recentes ficando mais antigos, colunas sendo excluídas e muito mais.

Manipulando desvios de esquema usando Hubs de


Eventos
Se um editor de eventos precisar compartilhar detalhes do esquema com o consumidor, ele
precisará serializar o esquema junto com os dados, usando formatos como o Apache Avro,
e enviá-lo pelos Hubs de Eventos. Aqui, o esquema tem que ser enviado com cada evento,
o que não é uma abordagem muito eficiente.

Se você estiver lidando com esquemas definidos estaticamente no lado do consumidor,


qualquer alteração de esquema no lado do produtor significaria problemas.
Os Hubs de Eventos fornecem um recurso chamado Registro de Esquema do Azure para
manipular a evolução do esquema e o desvio do esquema. Ele fornece um repositório
central para compartilhar os esquemas entre editores de eventos e consumidores. Vamos
examinar como criar e usar o Registro de Esquema do Azure.

Registrando um esquema com o registro de esquema

Aqui está um exemplo de como registrar um esquema:

1. Importe as bibliotecas necessárias:


2. From azure.schemaregistry import SchemaRegistryClient

from azure.identity import DefaultAzureCredential


CopyExplain
3. Defina seu esquema:
4. sampleSchema = """

5. {"namespace": "com.azure.sampleschema.avro",

6. "type": "record",

7. "name": "Trip",

8. "fields": [

9.      {"name": "tripId", "type": "string"},

10.      {"name": "startLocation", "type": "string"},

11.      {"name": "endLocation", "type": "string"}

12. ]

}"""
CopyExplain
13. Crie o cliente do Registro de Esquema:
14. azureCredential = DefaultAzureCredential()

15. schema_registry_client = SchemaRegistryClient(

16. fully_qualified_namespace=<SCHEMA-NAMESPACE>.servicebus.windows.net,

credential=azureCredential)
CopyExplain
17. Registre o esquema:
18. With schema_registry_client:

19.     schema_properties = schema_registry_client.register_schema(

20.       <SCHEMA_GROUPNAME>,

21.       <SCHEMA_NAME>,

22.       sampleSchema,

      "Avro")
CopyExplain
23. Obtenha a ID do esquema:
    schema_id = schema_properties.id
CopyExplain

Em seguida, vamos ver como recuperar o esquema.

Recuperando um esquema do Registro de esquema

Aqui estão as etapas de alto nível para recuperar o esquema:

1. Importe as bibliotecas necessárias:


2. from azure.identity import DefaultAzureCredential

from azure.schemaregistry import SchemaRegistryClient


CopyExplain
3. Crie o cliente do Registro de Esquema:
4. azureCredential = DefaultAzureCredential()

5. schema_registry_client = SchemaRegistryClient(

6. fully_qualified_namespace=<SCHEMA-NAMESPACE>.servicebus.windows.net,

credential=azureCredential)
CopyExplain
7. Recupere o esquema:
8. With schema_registry_client:

9.     schema = schema_registry_client.get_schema(schema_id)

10.     definition = schema.definition


    properties = schema.properties
CopyExplain

Depois de ter o esquema, você pode definir seus eventos e começar a ler os dados no
formato correto.

Você pode saber mais sobre o Registro de Esquema de Hubs de Eventos


em https://docs.microsoft.com/en-us/azure/event-hubs/schema-registry-overview.

Em seguida, vamos ver como lidar com desvios de esquema no Spark.

Manipulando desvios de esquema no Spark


O Azure Databricks Delta Lake fornece um recurso chamado Schema Evolution para cuidar
das alterações de esquema ao longo do tempo. Ele se adapta automaticamente ao novo
esquema quando novas colunas são adicionadas. O Schema Evolution pode ser ativado
adicionando a opção ao comando streaming..option('mergeSchema', 'true')writeStream

Aqui está um exemplo simples:

StreamDF.writeStream.format("delta")\

.option("mergeSchema", "true") \

.outputMode("append")\

.option("checkpointLocation", "dbfs:/CheckpointLocation/")\

.start("dbfs:/StreamData")
CopyExplain

Depois que a opção for especificada, o Spark se encarregará de lidar com colunas mais
recentes no fluxo automaticamente. mergeSchema

Em seguida, vamos examinar o particionamento de eventos nos Hubs de Eventos.

Processamento entre partições


Antes de analisarmos como processar dados entre partições, primeiro, vamos entender as
partições.

O que são partições?


Os Hubs de Eventos podem distribuir eventos de entrada em vários fluxos para que possam
ser acessados, em paralelo, pelos consumidores. Esses fluxos paralelos são chamados de
partições. Cada partição armazena os dados reais do evento e metadados do evento, como
seu deslocamento na partição, seu carimbo de data/hora do lado do servidor quando o
evento foi aceito, seu número na sequência de fluxo e muito mais. O particionamento ajuda
no dimensionamento do processamento em tempo real, pois aumenta o paralelismo
fornecendo vários fluxos de entrada para mecanismos de processamento downstream. Além
disso, melhora a disponibilidade redirecionando os eventos para outras partições saudáveis
se algumas das partições falharem.

Você pode saber mais sobre partições de Hubs de Eventos


em https://docs.microsoft.com/en-in/azure/event-hubs/event-hubs-scalability.

Agora, vamos ver como enviar dados entre partições e como processar dados entre
partições.

Processando dados entre partições


As bibliotecas do cliente para acessar os Hubs de Eventos estão disponíveis em
diferenteslinguagens, como C#, Python, Java e muito mais. Nesta seção, usaremos a
biblioteca Python para nossos exemplos.

Os Hubs de Eventos fornecem a classe como parte das bibliotecas de cliente Python para
consumir os dados do hub de eventos. pode ser usado para ler eventos de todas as partições
com balanceamento de carga e checkpointing. Já usamos essa classe no exemplo de
checkpointing na seção Checkpointing em Hubs de Eventos. O mesmo exemplo funcionará
para leitura entre partições. Aqui, forneceremos os passos importantes novamente por
conveniência.EventHubConsumerClientEventHubConsumerClient

Observe que todas as entradas dentro dos colchetes angulares, , são valores fornecidos pelo
usuário:< >
1. Instancie o repositório do ponto de verificação:
2. storeChkPoint = BlobCheckpointStore.from_connection_string(

3.         <STORE_CONN_STRING>,

4.         <STORE_CONTAINER_NAME>

    )
CopyExplain
5. Instancie a classe:EventHubConsumerClient
6. ehClient = EventHubConsumerClient.from_connection_string(

7.         <EVENTHUB_CONN_STRING>,

8.         <CONSUMER_GROUP_NAME>,

9.         eventhub_name=<EVENTHUB_NAME>,

10.         checkpoint_store= storeChkPoint # This enables load balancing across partitions

    )
CopyExplain
11. Defina um método para processar o evento quando ele chegar:on_event
12. Def on_event(partition_context, event):

13.     # Process the event

    partition_context.update_checkpoint(event)
CopyExplain
14. Chame o método quando um evento chegar:on_event
15. With ehClient:

16.     ehClient.receive(

17.         on_event=on_event,

18.         starting_position="-1",  # To start from the beginning of the partition.

    )
CopyExplain

Quando não especificamos uma partição específica durante a instanciação da classe, ela


será lida automaticamente em todas as partições no grupo de consumidores especificado.
Você pode saber mais sobre as bibliotecas Python dos Hubs de
Eventos em https://azuresdkdocs.blob.core.windows.net/$web/python/azure-eventhub/
latest/azure.eventhub.html.EventHubConsumerClient

Em seguida, vamos ver os detalhes de como processar os dados dentro de uma partição.

Processamento dentro de uma partição


Semelhante ao exemplo anterior, onde aprendemos a processar entre partições, também
podemos usar a classe para processar dados dentro de partições únicas. Tudo o que
precisamos fazer é especificar o ID da partição na chamada, conforme demonstrado no
trecho de código a seguir. O restante do código permanecerá o mesmo que o exemplo
anterior:EventHubConsumerClientclient.receive

With client:

    client.receive(

        on_event=on_event,

        partition_id='0', # To read only partition 0

    )
CopyExplain

É assim que podemos processar programaticamente os dados de partições específicas dos


Hubs de Eventos.

Em seguida, vamos ver como dimensionar recursos para processamento de fluxo.

Recursos de dimensionamento
Vejamos como dimensionar recursos nos Hubs de Eventos, no ASA e no Azure Databricks
Spark.

Dimensionamento em Hubs de Eventos


Há duas maneiras pelas quais os Hubs de Eventos oferecem suporte ao dimensionamento:
 Particionamento: já aprendemos como o particionamento pode ajudar a dimensionar
nossa instância de Hubs de Eventos, aumentando o paralelismo com o qual os
consumidores de eventos podem processar dados. O particionamento ajuda a reduzir a
contenção se houver muitos produtores e consumidores, o que, por sua vez, o torna
mais eficiente.
 Inflar automaticamente: esse é um recurso de expansão automática dos Hubs de
Eventos. À medida que o uso aumenta, o EventHub adiciona mais unidades de taxa de
transferência à sua instância dos Hubs de Eventos, aumentando assim sua capacidade.
Você pode habilitar esse recurso se já tiver saturado sua cota usando a técnica de
particionamento que exploramos anteriormente, na seção Processamento entre
partições.

Em seguida, vamos explorar o conceito de unidades de taxa de transferência.

O que são unidades de throughput?

As unidades de taxa de transferência são unidades de capacidade que podem ser adquiridas
nos Hubs de Eventos. Uma única unidade de taxa de transferência permite o seguinte:

 Entrada de até 1 MB por segundo ou 1.000 eventos por segundo

 Saída de até 2 MB por segundo ou 4.096 eventos por segundo

Nota

Na camada Premium dos Hubs de Eventos, as unidades de taxa de transferência são


chamadas de unidades de processamento.

Veja como você pode habilitar o recurso de inflar automaticamente nos Hubs de Eventos:
Figura 10.31 – Habilitando o inflar automático nos Hubs de Eventos

Você pode saber mais sobre a escalabilidade dos Hubs de Eventos


em https://docs.microsoft.com/en-in/azure/event-hubs/event-hubs-scalability.

Em seguida, vamos ver como dimensionar o mecanismo de processamento, ASA.

Dimensionamento no ASA
Você pode dimensionar seus clusters ASA diretamente do portal do Azure. Basta clicar na
guia Escala na página inicial do ASA e configurar a alternância de unidades de
streaming, conforme mostrado na captura de tela a seguir:

Figura 10.32 – Dimensionamento de um trabalho ASA

As unidades de streaming são uma medida da capacidade de streaming. As unidades de


dimensionamento não têm uma configuração de capacidade absoluta, como no caso das
unidades de taxa de transferência dos Hubs de Eventos. Em geral, quanto maior o número
de unidades de streaming, maior a capacidade. Você terá que fazer algumas corridas de
tentativa e erro para identificar o ponto ideal.

Ponta

Para consultas ASA que não estão usando a transformação, a recomendação é começar com
seis SUs e, em seguida, modificar os números iterativamente executando seus trabalhos e
monitorando a métrica de utilização de SU%.PARTITION BY

Você pode aprender sobre a otimização de unidades de streaming


em https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-streaming-
unit-consumption.

Você pode saber mais sobre o dimensionamento do ASA em https://docs.microsoft.com/en-


us/azure/stream-analytics/scale-cluster.

O ASA não tem um mecanismo interno de autoescala. No entanto, você pode simular um
usando serviços como a Automação do Azure. Esse é um serviço externo que pode ser
usado para monitorar as métricas ASA e acionar uma escala para cima ou para baixo
externamente.

Se você está interessado em saber mais, você pode consultar https://docs.microsoft.com/en-


us/azure/stream-analytics/stream-analytics-autoscale.

Em seguida, vamos ver como dimensionar o Azure Databricks Spark.

Dimensionamento no Azure Databricks Spark


Streaming
Aprendemos como configurar o dimensionamento automático para o Azure Databricks
no Capítulo 9, Projetando e desenvolvendo uma solução de processamento em lote, na
seção Recursos de dimensionamento. Consulte essa seção para atualizar sua memória sobre
como configurar o dimensionamento automático para o Spark.

A seguir, vamos ver como lidar com interrupções.

Tratamento de interrupções
Interrupções no processamento de fluxo podem ocorrer devido a vários motivos, como
problemas de conectividade de rede, atualizações de serviço em segundo plano, bugs
intermitentes e muito mais. Os Hubs de Eventos e o ASA fornecem opções para lidar com
essas interrupções nativamente usando o conceito de zonas de Disponibilidade do Azure.
As zonas de disponibilidade são locais fisicamente isolados no Azure que ajudam os
aplicativos a se tornarem resilientes a falhas e paralisações locais. O Azure lista as regiões
que são emparelhadas para formar zonas de disponibilidade.

Os serviços que oferecem suporte a zonas de disponibilidade implantam seus aplicativos


em todos os locais dentro da zona de disponibilidade para melhorar a tolerância a falhas.
Além disso, eles garantem que as atualizações de serviço sejam sempre feitas uma após a
outra para os locais da zona de disponibilidade. Portanto, eles garantem que em nenhum
momento todos os locais sofrerão uma interrupção devido a bugs de atualização do serviço.
Os Hubs de Eventos e o ASA oferecem suporte a zonas de disponibilidade. Vejamos como
habilitar esse recurso para Hubs de Eventos e ASA.
Manipulando interrupções em Hubs de Eventos
Quando os Hubs de Eventos são implantados em regiões que fazem parte das zonas de
disponibilidade, os metadados e os eventos são replicados para todos os locais nessa zona
de disponibilidade. Para usar zonas de disponibilidade, tudo o que você precisa fazer é
selecionar uma região que ofereça suporte à zona de disponibilidade para o campo Local,
conforme mostrado na captura de tela a seguir:

Figura 10.33 – Escolhendo locais com zonas de disponibilidade nos Hubs de Eventos

Depois de escolher a região com suporte para a zona de disponibilidade e clicar em Revisar
+ criar, a instância dos Hubs de Eventos será criada em todos os locais da zona de
disponibilidade.
Aqui estão alguns outros pontos para tornar a instância dos Hubs de Eventos mais
resiliente:

 Tente criar novamente e repetir a lógica em seus aplicativos. Isso é para que erros
transitórios possam ser detectados e o processamento do fluxo possa ser repetido. Se
seu aplicativo for criado usando os SDKs dos Hubs de Eventos, a lógica de repetição
já estará interna.

 Se o aplicativo não precisar de mensagens estritamente ordenadas, você poderá enviar


os eventos sem especificar uma partição. Isso garantirá que os Hubs de Eventos
balanceiem a carga dos eventos em todas as partições. Se uma partição falhar, a
instância dos Hubs de Eventos distribuirá o evento para outras partições, melhorando
assim a disponibilidade.

Você pode saber mais sobre as zonas de disponibilidade dos Hubs de Eventos


em https://docs.microsoft.com/en-in/azure/event-hubs/event-hubs-geo-dr.

A seguir, vamos ver como lidar com interrupções no ASA.

Tratamento de interrupções no ASA


Semelhante aos Hubs de Eventos, o ASA também implanta em zonas de
disponibilidade (ou regiões emparelhadas com o Azure) por padrão. Além disso, o ASA
garante que as atualizações de serviço sempre aconteçam em lotes separados entre os locais
das zonas de disponibilidade. Não há nenhuma configuração necessária dos usuários.

Nota

No momento em que escrevo, a região da Índia Central não tem uma região emparelhada
para ASA.

Você pode saber mais sobre zonas de disponibilidade e tratamento de interrupções no ASA


em https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-job-reliability.

Em seguida, vamos ver como projetar e configurar o tratamento de exceções.


Projetando e configurando o tratamento de
exceções
As exceções dos Hubs de Eventos fornecem informações muito claras sobre o motivo dos
erros. Todos os problemas do EventHub lançam um objeto de exceção.EventHubsException

O objeto de exceção contém as seguintes informações:EventHubsException

 IsTransient: Isso indica se as exceções podem ser repetidas.


 Reason: Isso indica o motivo real da exceção. Alguns exemplos de motivos podem
incluir tempos limites, exceder limites de cota, exceder tamanhos de mensagens,
desconexões de conexão de cliente e muito mais.

Aqui está um exemplo simples de como capturar exceções no .NET:

try

    // Process Events

catch (EventHubsException ex) where

(ex.Reason == EventHubsException.FailureReason.MessageSizeExceeded)

    // Take action for the oversize messages

}
CopyExplain

Você pode saber mais sobre o tratamento de exceções em https://docs.microsoft.com/en-


us/azure/event-hubs/exceptions-dotnet.

Em seguida, vamos examinar a atualização de dados usando o Synapse Analytics.


Atualizando dados
Upserting refere-se à atividade ou em um banco de dados ou qualquer armazenamento
de dados analíticos que o suporte. Já vimos como parte da atividade em lote, na
seção Upserting data do Capítulo 9, Projetando e desenvolvendo uma solução de
processamento em lote. ASA suporta com CosmosDB. O CosmosDB é um banco de dados
No-SQL totalmente gerenciado e distribuído globalmente. Aprenderemos mais sobre o
CosmosDB no Capítulo 14, Otimizando e solucionando problemas de armazenamento e
processamento de dados, na seção Implementando HTAP usando Synapse Link e
CosmosDB. INSERTUPDATEUPSERTUPSERT

O ASA tem dois comportamentos diferentes com base no nível de compatibilidade


definido. O ASA suporta três níveis de compatibilidade diferentes. Você pode pensar em
níveis de compatibilidade como versões de API. À medida que o ASA evoluiu, os níveis de
compatibilidade aumentaram. 1.0 foi a primeira versão de compatibilidade e 1.2 é a versão
de compatibilidade mais recente. A principal mudança na versão 1.2 é o suporte para o
protocolo de mensagens AMQP.

Você pode definir o nível de compatibilidade, conforme mostrado na captura de tela a


seguir:
Figura 10.34 – Atualização do nível de compatibilidade no ASA

Com os níveis de compatibilidade 1.0 e 1.1, o ASA faz uma inserção ou atualização de


nível de propriedade no documento. Ele permite atualizações parciais do documento como
uma operação.PATCH

Com um nível de compatibilidade de 1,2 em diante, o ASA faz uma operação de inserção


ou substituição de documentos. Primeiro, o ASA faz uma inserção. Se isso falhar devido a
um conflito de ID do documento, ele fará uma atualização.

Nota

Upserts funcionam no CosmosDB quando o ID do documento é definido. Se não tiver sido


definido, os cenários de atualização lançarão um erro.

Você pode aprender mais sobre o ASA – CosmosDB


Upserts em https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-
documentdb-output#upserts-from-stream-analytics.

Em seguida, vamos ver como criar testes para pipelines de dados.

Projetando e criando testes para pipelines de


dados
Esta seção já foi abordada no Capítulo 9, Projetando e desenvolvendo uma solução de
processamento em lote, na seção Projetando e criando testes para pipelines de dados.
Consulte essa seção para obter detalhes.

Otimização de pipelines para fins analíticos


ou transacionais
Abordaremos este tópico no Capítulo 14, Otimizando e solucionando problemas de
armazenamento e processamento de dados, na seção Otimizando pipelines para fins
analíticos ou transacionais, já que todo esse capítulo trata de otimizações.
Resumo
Isso nos leva ao final deste capítulo. Este é um dos capítulos importantes tanto do ponto de
vista do currículo quanto do ponto de vista da engenharia de dados. Soluções em lote e
streaming são fundamentais para a construção de um bom sistema de processamento de big
data.

Então, vamos recapitular o que aprendemos neste capítulo. Começamos com projetos para
sistemas de streaming usando Hubs de Eventos, ASA e Spark Streaming. Aprendemos
como monitorar esses sistemas usando as opções de monitoramento disponíveis em cada
um desses serviços. Em seguida, aprendemos sobre dados de séries temporais e conceitos
importantes, como agregações em janelas, pontos de verificação, reprodução de dados
arquivados, manipulação de desvios de esquema, como dimensionar usando partições e
adição de unidades de processamento. Além disso, exploramos o recurso upsert e, no final,
aprendemos sobre tratamento de erros e tratamento de interrupções.

Agora você deve estar confortável com a criação de soluções de streaming no Azure. Como
sempre, por favor, passe pelos links de acompanhamento que foram fornecidos para saber
mais e experimente os exemplos você mesmo para entender os detalhes minuciosos dessas
tecnologias.

No próximo capítulo, aprenderemos a gerenciar lotes e pipelines.

Capítulo 11: Gerenciando lotes e


pipelines
Bem-vindo ao Capítulo 11! Este é um dos capítulos menores e mais fáceis e será
uma brisa para ler. Neste capítulo, nos concentraremos em quatro grandes
categorias: acionamento de trabalhos em lote, manipulação de falhas em
trabalhos em lote, gerenciamento de pipelines e configuração do controle de
versão para nossos pipelines. Depois de concluir este capítulo, você deve ser
capaz de configurar e gerenciar confortavelmente pipelines de lote usando
pipelines do Lote do Azure, do Azure Data Factory (ADF) ou do Synapse.
Neste capítulo, abordaremos os seguintes tópicos:

 Acionamento de lotes

 Manipulação de cargas em lote com falha

 Validando cargas em lote

 Gerenciando pipelines de dados em pipelines do Data Factory/Synapse

 Agendamento de pipelines de dados em pipelines Data Factory/Synapse

 Gerenciando trabalhos do Spark em um pipeline

 Implementando o controle de versão para artefatos de pipeline

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 Um espaço de trabalho Synapse ativo

 Um espaço de trabalho ativo do Azure Data Factory

Vamos começar!

Acionamento de lotes
Aprendemos sobre o Lote do Azure no Capítulo 9, Projetando e desenvolvendo
uma solução de processamento em lote, na seção Apresentando o Lote do Azure.
Nesta seção, aprenderemos como disparar esses trabalhos em lote usando
o Azure Functions. O Azure Functions é um serviço sem servidor fornecido pelo
Azure que ajuda a criar aplicativos de nuvem com código mínimo, sem que você
precise se preocupar em hospedar e manter a tecnologia que executa o código. O
Azure cuida de todas as complexidades de hospedagem, como implantações,
atualizações, patches de segurança, dimensionamento e muito mais. Mesmo que
o nome diga serverless, ele tem servidores em execução em segundo plano. Isso
significa apenas que você não precisa manter esses servidores – o Azure faz isso
por você.

Para nosso requisito de disparar um trabalho em lote, usaremos a


funcionalidade Trigger do Azure Functions. Um Gatilho define quando e como
invocar uma função do Azure. O Azure Functions oferece suporte a uma ampla
variedade de gatilhos, como gatilho de timer, gatilho HTTP, gatilho de Blob do
Azure, gatilho do Azure EventHub e assim por diante.

Nota

Uma função do Azure pode ter apenas um gatilho associado a ela. Se você
precisar de várias maneiras de acionar uma função, você terá que definir funções
diferentes para ela.

Para nosso exemplo, definiremos um gatilho de blob e definiremos uma função do


Azure que pode chamar nosso trabalho em lote:

1. No portal do Azure, procure Aplicativo de Função e crie um novo aplicativo de


função. Uma vez criado, clique no botão + Criar para criar uma nova função,
como mostrado na captura de tela a seguir:

Figura 11.1 – Criando um novo aplicativo de função do Azure

2. A tela Criar função terá a aparência mostrada na imagem a seguir. Selecione


a opção de gatilho do Armazenamento de Blobs do Azure na
seção Selecionar um modelo e configure os detalhes necessários, como o
nome da função (Nova Função), Caminho e assim por diante:

Figura 11.2 – Criando um gatilho de Armazenamento de Blobs do Azure

3. Clique no botão Criar para criar a função que você usará como gatilho.


4. Agora que temos o gatilho, precisamos definir o que fazer quando o gatilho
disparar. Vá para a guia Código + Teste e adicione sua lógica de negócios
lá. O código da lógica de negócios pode estar em C#, Java, Python ou
PowerShell:
Figura 11.3 – Inserindo código para a função Trigger

Em nosso exemplo, usaremos trechos de código C# para demonstrar o fluxo.


Devemos adicionar a lógica de negócios dentro de um método. Aqui está um bloco
de referência de código de exemplo: Run()

public static void Run(…)

   // Initialize the credentials

   BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(…);

   // Create a Batch client

   BatchClient batchClient = BatchClient.Open(cred))

   // Create a Batch job

   CloudJob job = batchClient.JobOperations.GetJob(<JOB_ID>);

   // Add your business logic

   // Add tasks to the job.

   CloudTask task = new CloudTask(<TASK_ID>, <COMMAND>);

   batchClient.JobOperations.AddTask(<JOB_ID>, task);
}
CopyExplain

Agora, toda vez que adicionarmos ou atualizarmos um arquivo no armazenamento


de blob no campo Caminho, a função anterior será chamada, o que iniciará um
trabalho em lote.

Você pode consultar o trabalho C# de exemplo completo acessando o repositório


GitHub deste livro: https://github.com/Azure-Samples/batch-functions-tutorial.

Em seguida, vamos aprender como lidar com trabalhos com falha no Lote do


Azure.

Manipulação de cargas em lote com


falha
Um trabalho em Lote do Azure pode falhar devido a quatro tipos de erros:

 Erros de pool

 Erros de nó

 Erros de trabalho

 Erros de tarefa

Vejamos alguns dos erros comuns em cada grupo e maneiras de lidar com eles.

Erros de pool
Os erros de pool ocorrem principalmente devido a problemas de infraestrutura,
problemas de cota ou problemas de tempo limite. Aqui estão alguns exemplos de
erros de pool:

 Cota insuficiente: se não houver cota suficiente para sua conta em lote, a
criação do pool poderá falhar. A mitigação é pedir aumento de cota. Você
pode conferir os limites de cota
aqui: https://docs.microsoft.com/en-us/azure/batch/batch-quota-limit.
 Recursos insuficientes em sua rede virtual: se sua rede virtual (VNet) não
tiver recursos suficientes, como endereços IP disponíveis, NSGs
(Grupos de Segurança de Rede), VMs e assim por diante, o processo de
criação do pool poderá falhar. A atenuação é procurar esses erros e solicitar
maior alocação de recursos ou mover para uma rede virtual diferente que
tenha capacidade suficiente.
 Tempos limite curtos: algumas das operações, como o redimensionamento
do pool, podem levar mais de 15 minutos, que é o padrão definido pelo Lote
do Azure. Nesses casos, aumentar o tempo limite usando a seguinte API
pode ajudar:
POST {batchUrl}/pools?timeout={timeout}&api-version=2021-06-01.14.0
CopyExplain

Em seguida, vamos examinar alguns dos erros comuns do nó.

Erros de nó
Os erros de nó podem ser devidos a problemas de hardware ou a falhas nas
atividades de configuração do trabalho, como scripts de inicialização, scripts
de download e assim por diante. Aqui estão alguns exemplos de erros de nó:

 Falhas na tarefa inicial: se você configurou uma tarefa inicial para seu
trabalho e ela falhar, o nó se tornará inutilizável. Você pode procurar os erros
nos campos e na resposta da seguinte
API:TaskExecutionResultTaskFailureInformation
GET {batchUrl}/pools/{poolId}/nodes/{nodeId}?api-version=2021-06-01.14.0
CopyExplain

Depois de identificar o erro, você terá que tomar ações corretivas, como corrigir os
scripts de início do usuário.

 Falhas de download do aplicativo: Se o Batch não conseguir baixar o pacote


do aplicativo, ele lançará um erro de nó. A propriedade na resposta da API
GET mostrada anteriormente listará essas falhas de download de aplicativo.
Verifique se há permissões de arquivo, locais corretos e assim por diante para
corrigir esses problemas.ComputeNodeError
 Nós entrando em um estado incorreto: Isso pode acontecer devido a falhas
de infraestrutura, problemas de rede, atualizações incorretas de sistema
operacional/segurança, o disco estar cheio e assim por diante.

Nesses casos, a propriedade na resposta da API GET indicará o erro. Com base
no erro, você terá que tomar ações corretivas, como girar novos nós, corrigir
problemas de rede, limpar o disco e assim por diante. ComputeNodeError

Você pode saber mais sobre como lidar com erros de pool e nó


aqui: https://docs.microsoft.com/en-us/azure/batch/batch-pool-node-error-
checking.

Em seguida, vamos examinar os erros de trabalho.

Erros de trabalho
Os trabalhos podem falhar devido a vários motivos. Vejamos alguns deles:

 Restrições de trabalho, como a configuração, podem resultar em falhas de


trabalho.maxWallClockTime
 Erros na preparação do trabalho ou tarefas de liberação do trabalho. Essas
são tarefas que são executadas antes da primeira tarefa e após a última
tarefa do trabalho. Quaisquer falhas nestes podem fazer com que o trabalho
falhe.

Em todos esses casos, as propriedades e na resposta da API a seguir conterão os


detalhes do erro:JobExecutionInformationJobSchedulingError

GET {batchUrl}/jobs/{jobId}?api-version=2021-06-01.14.0
CopyExplain

Com base no erro real identificado pela resposta da API anterior, devemos ser
capazes de corrigir o problema. Agora, vamos analisar os erros de tarefa.
Erros de tarefa
Falhas de tarefa podem acontecer nos seguintes casos:

 O comando falha e retorna um código de saída diferente de zero. tasks


 Problemas de download de arquivo de recurso, como se a tarefa não
conseguir baixar os arquivos de recurso das pastas de origem.

 Problemas de carregamento de arquivos de saída, como se a tarefa não


conseguir carregar o arquivo de saída para as pastas de destino.

Em todos esses casos, você pode verificar a propriedade na resposta da seguinte


API REST para obter os detalhes do erro da tarefa: TaskExecutionInformation

GET {batchUrl}/jobs/{jobId}/tasks/{taskId}?api-version=2021-06-01.14.0
CopyExplain

Para os problemas de saída do arquivo, as tarefas em lote também gravam os


arquivos e no nó. Esses arquivos também podem fornecer informações valiosas
sobre os erros.Fileuploadout.txtfileuploaderr.txt

Você pode saber mais sobre como lidar com erros de trabalho e tarefa
aqui: https://docs.microsoft.com/en-us/azure/batch/batch-job-task-error-checking.

Na próxima seção, examinaremos as opções disponíveis para validar


carregamentos em Lote do Azure.

Validando cargas em lote


Os trabalhos em lote geralmente são executados como parte do Azure Data
Factory (ADF). O ADF fornece funcionalidades para validar o resultado dos
trabalhos. Vamos aprender a usar a atividade Validação no ADF para verificar a
exatidão das cargas em lote:
1. A atividade de Validação do ADF pode ser usada para verificar a
existência de um arquivo antes de prosseguir com o restante das atividades
no pipeline. O pipeline de validação será semelhante ao seguinte:

Figura 11.4 – Atividade de validação do ADF

2. Depois de validarmos que os arquivos existem, podemos usar a


atividade Obter metadados para obter mais informações sobre os arquivos
de saída. Na captura de tela a seguir, produzimos a contagem de colunas,
que verificaremos mais tarde usando uma atividade If Condition para decidir
se os arquivos de saída são bons:
Figura 11.5 – Configurando a atividade Obter metadados para publicar a
contagem de colunas

3. Depois de obter os metadados, devemos usar a atividade If Condition para


decidir se queremos continuar processando o pipeline ou não com base nos
metadados do estágio anterior:

Figura 11.6 – Usando os metadados da atividade Obter metadados para tomar


uma decisão

A condição pode ser algo como segue, onde verificamos se o número de colunas
é igual à contagem de colunas esperada. Neste exemplo, espero cinco colunas:

@equals(activity('TripFileMetadata').output.columnCount, 5)
CopyExplain

Você pode executar verificações de validação semelhantes usando uma


combinação de atividades do ADF para Batch e outras tecnologias.

Agora, vamos aprender como agendar pipelines de dados no ADF e Synapse


Pipelines.
Agendamento de pipelines de dados em
pipelines Data Factory/Synapse
Agendamento de pipelines refere-se ao processo de definir quando e como um
pipeline precisa ser iniciado. O processo é o mesmo entre os dutos ADF e
Synapse. Os pipelines ADF e Synapse têm um botão chamado Add Trigger na
guia Pipelines que pode ser usado para agendar os pipelines, conforme mostrado
na captura de tela a seguir:

Figura 11.7 – Adicionando um gatilho de pipelines ADF/Synapse

A captura de tela a seguir mostra os detalhes necessários para configurar um


gatilho de agendamento:
Figura 11.8 – Definição do gatilho no ADF

Os serviços de pipeline ADF e Synapse oferecem suporte a quatro tipos de


gatilhos:

 Gatilho de agendamento: aciona um pipeline uma vez ou regularmente com


base no tempo do relógio de parede.
 Gatilho de janela de tombamento: aciona um pipeline com base em
intervalos periódicos, mantendo o estado; ou seja, o gatilho entende qual
janela de dados foi processada por último e reinicia a partir daí.
 Gatilho baseado em evento: aciona um pipeline com base em eventos de
armazenamento, como arquivos sendo criados em Blob ou ADLS.
 Gatilho personalizado: aciona pipelines com base em eventos da Grade de
Eventos do Azure. O ADF pode listar n para tópicos na Grade de Eventos do
Azure e dispararpipelines com base em determinadas mensagens ou eventos
que ocorrem no tópico Grade de Eventos.

Depois que o gatilho tiver sido configurado, você poderá ver os pipelines sendo
acionados automaticamente na guia Monitoramento dos pipelines ADF ou
Synapse.

Você pode saber mais sobre gatilhos e pipelines de agendamento


aqui: https://docs.microsoft.com/en-us/azure/data-factory/concepts-pipeline-
execution-triggers.

Agora, vamos aprender a gerenciar e monitorar pipelines de dados em pipelines


ADF e Synapse.

Gerenciando pipelines de dados em


pipelines do Data Factory/Synapse
Os pipelines ADF e Synapse fornecem duas guias chamadas Manage e Monitor,
que podem nos ajudar a gerenciar e monitorar os pipelines, respectivamente.

Na guia Gerenciar, você pode adicionar, editar e excluir serviços vinculados,


tempos de execução de integração, gatilhos, configurar o Git e muito mais,
conforme mostrado na captura de tela a seguir:
Figura 11.9 – A tela Gerenciar do ADF

Já aprendemos sobre serviços vinculados ao longo deste livro. Agora, vamos


explorar o tópico de tempos de execução de integração em pipelines ADF e
Synapse.

Tempos de execução de integração


Um tempo de execução de integração (IR) refere-se à infraestrutura de
computação usada pelo ADF e pelo Synapse Pipelines para executar pipelines de
dados e fluxos de dados. Essas são as máquinas ou VMs reais que executam o
trabalho nos bastidores.

O IR cuida da execução de fluxos de dados, da cópia de dados em redes públicas


e privadas, do envio de atividades para serviços como o Azure HDInsight e o
Azure Databricks e da execução do SQL Server Integration Services (SSIS).

Você pode criar IRs na guia Gerenciar de pipelines ADF e Synapse clicando no


botão + Novo, conforme mostrado na captura de tela a seguir:
Figura 11.10 – Criando um novo tempo de execução de integração

O ADF fornece suporte para três tipos de RIs:

 Tempo de Execução de Integração do Azure: essa é a opção padrão e


oferece suporte à conexão de armazenamentos de dados e serviços de
computação entre pontos de extremidade públicos. Use essa opção para
copiar dados entre serviços hospedados no Azure. O Azure IR também dá
suporte à conexão de armazenamentos de dados usando links privados.
 Tempo de Execução de Integração Auto-Hospedada: use essa opção
quando precisar copiar dados entre clusters locais e serviços do Azure. Você
precisará de máquinas ou VMs na rede privada local para instalar um IR auto-
hospedado.
 Azure – Tempo de Execução de Integração do SSIS: As IRs do SSIS são
usadas para casos de uso de elevação e deslocamento do SSIS.

Você pode saber mais sobre IRs


aqui: https://docs.microsoft.com/en-us/azure/data-factory/create-azure-integration-
runtime?tabs=data-factory.

Em seguida, vamos examinar as opções de monitoramento no ADF.

Monitoramento de ADF
Os pipelines podem ser acionados manualmente ou automaticamente (usando
gatilhos). Uma vez que eles são acionados, podemos monitorá-los a partir da
guia Monitor, como mostrado na captura de tela a seguir:

Figura 11.11 – Monitoramento de pipelines de ADF

Você pode Cancelar todas as execuções em andamento e Executar


novamente os pipelines com falha na guia Monitor. Você pode clicar em cada
uma dessas execuções para ver os detalhes de cada fluxo, conforme mostrado na
captura de tela a seguir. Clique no ícone de óculos para obter estatísticas sobre a
corrida, como quantas etapas estavam lá, quantas linhas foram processadas,
quanto tempo cada etapa levou e assim por diante:

Figura 11.12 – Detalhes do fluxo de dados na guia Execuções de atividade

Os pipelines Synapse também fornecem telas semelhantes de


Gerenciar e Monitorar, então não vamos repeti-las aqui.
Em seguida, vamos aprender a gerenciar trabalhos do Spark em um pipeline do
ADF.

Gerenciando trabalhos do Spark em um


pipeline
O gerenciamento de trabalhos do Spark em um pipeline envolve dois aspectos:

 Gerenciando os atributos do tempo de execução do pipeline que inicia a


atividade do Spark: gerenciar os atributos do pipeline de atividade do
Spark não é diferente de gerenciar quaisquer outras atividades em um
pipeline. As páginas de Gerenciamento e Monitoramento que vimos na
Figura 11.9, na Figura 11.11 e na Figura 11.12 também são as mesmas para
qualquer atividade do Spark. Você pode usar as opções fornecidas nessas
telas para gerenciar sua atividade do Spark.
 Gerenciando tarefas e configurações do Spark: isso envolve entender
como o Spark funciona, ser capaz de ajustar os trabalhos e assim por diante.
Temos um capítulo completo dedicado à otimização de trabalhos Synapse
SQL e Spark no final deste livro. Você pode consultar o Capítulo
14, Otimizando e solucionando problemas de armazenamento e
processamento de dados, para saber mais sobre como gerenciar e ajustar
trabalhos do Spark.

Nesta seção, aprenderemos como adicionar um trabalho do Apache Spark (via


HDInsight) ao nosso pipeline para que você tenha uma ideia dos parâmetros que
podem ser configurados durante a configuração de um trabalho do Spark usando
o ADF e o HDInsight. Isso é um pouco diferente de adicionar Databricks
Notebooks ao pipeline do ADF. Aqui estão os passos:

1. Devemos criar um serviço vinculado para um cluster HDInsight na


guia Gerenciar do ADF. A captura de tela a seguir mostra como criar esse
serviço vinculado. Você pode usar o AutoResolveIntegrationRuntime como
seu cluster HDInsight, já que eles também estão hospedados no Azure.
Especifique os outros detalhes, como um nome de cluster HDI existente ou
um cluster HDInsight sob demanda, bem como o nome do
serviço vinculado do Armazenamento do Azure associado à conta de
armazenamento desse cluster HDI para criar o serviço vinculado:

Figura 11.13 – Criando um serviço vinculado ao HDInsight

2. Em seguida, selecione a atividade do Spark na guia Atividade do ADF e


selecione o serviço vinculado que criamos na etapa anterior para o
campo Serviço vinculado do HDInsight:
Figura 11.14 – Configurando o cluster HDInsight Spark dentro do pipeline do ADF

3. Na guia Script/Jar, forneça o link para o arquivo de trabalho do driver Spark


real. Nesse caso, vamos apontá-lo para um script, que foi carregado no
armazenamento de Blob:wordcount
Figura 11.15 – Criando um pipeline com o Spark

4. Agora, se apenas acionarmos esse pipeline usando o botão Adicionar


gatilho, todo o pipeline do Spark será executado.

Isso deve ter lhe dado uma boa compreensão do gerenciamento do Spark em
pipelines. A seguir, vamos aprender como implementar o controle de versão no
ADF.

Implementando o controle de versão


para artefatos de pipeline
Por padrão, os pipelines ADF e Synapse salvam os detalhes do pipeline em seus
armazenamentos internos. Esses repositórios internos não fornecem opções de
colaboração, controle de versão ou quaisquer outros benefícios fornecidos pelos
sistemas de controle de origem. Toda vez que você clicar no botão Publicar tudo,
suas alterações mais recentes serão salvas no serviço. Para superar essa falha,
os pipelines ADF e Synapse fornecem opções para integração com sistemas de
controle de origem, como o Git. Vamos explorar como configurar o controle de
versão para nossos artefatos de pipeline.

Configurando o controle do código-fonte no ADF


O ADF fornece um botão Configurar repositório de código na parte superior da
tela inicial, conforme mostrado na captura de tela a seguir. Você pode usar este
botão para iniciar o processo de configuração do Git:

Figura 11.16 – O botão Configurar repositório de código na tela inicial do ADF

Você também pode acessar a página Configuração do Git na guia Gerenciar (o


ícone do kit de ferramentas), conforme mostrado na captura de tela a seguir. Esta
captura de tela mostra pipelines Synapse, mas o ADF tem uma página muito
semelhante:
Figura 11.17 – Iniciando a configuração do Git a partir da guia Gerenciar do
Synapse

Os pipelines ADF e Synapse dão suporte à versão Azure DevOps do Git e contas


externas do GitHub. Vamos aprender como integrar esses dois sistemas de
controle de origem no ADF e no Synapse.

Integração com o Azure DevOps


Vejamos a configuração do Azure DevOps. Você precisará ter uma conta existente
do Azure DevOps. Se você não tiver um, você pode facilmente criar um:

1. Basta procurar Organizações de DevOps do Azure no portal do Azure.


Clique no botão Minhas Organizações de DevOps do Azure na tela
de DevOps do Azure, conforme mostrado na captura de tela a seguir, e
configure uma. Como alternativa, você também pode visitar
diretamente https://azure.microsoft.com/en-us/services/devops/ para começar
a usar o Azure DevOps:
Figura 11.18 – Criando uma nova organização de DevOps

Depois de criar uma nova organização do Azure DevOps, você pode criar novos
repositórios Git sob ela.

2. Agora, volte para a tela Configuração do Git do Azure Data Factory e clique


no botão Configurar (Figura 11.17). aqui, você poderá escolher entre o Azure
DevOps e o GitHub. Se você escolher o Azure DevOps, verá a
tela Configurar um repositório, conforme mostrado na captura de tela a
seguir. Aqui, você deve fornecer um nome de organização do Azure
DevOps, nome do projeto, nome do repositório, ramificação de
colaboração, ramificação de publicação, pasta raiz e assim por diante:
Figura 11.19 – Configurando o Azure DevOps Git como o controle de origem para
o ADF

3. Preencha os detalhes e clique em Aplicar para configurar o repositório Git do


Azure DevOps. A partir de agora, toda vez que você clicar em Publicar, ele
salvará as alterações no repositório git especificado por você.

Agora, vamos examinar os detalhes de configuração do GitHub.


Integração com o GitHub
A tela de configuração do GitHub também é muito semelhante. Você terá que
especificar atributos como Nome do repositório, Ramificação de colaboração,
Ramificação de publicação, Pasta raiz e assim por diante, conforme mostrado na
captura de tela a seguir:

Figura 11.20 – Configurando o GitHub como o controle de origem para o ADF

Nota
Em ambos os casos, o ADF cria uma nova ramificação chamada , que ele usará
como origem para publicar no serviço ADF. Você não poderá fazer alterações
nessa ramificação diretamente, mas poderá mesclar suas alterações por meio de
solicitações pull.adf_publish

Depois de configurar a versão do Azure DevOps ou do GitHub do Git, sempre que


você clicar em Publicar, os artefatos de pipeline serão armazenados no
repositório do Git.

Agora que você sabe como configurar o controle de versão para artefatos de
pipeline, vamos resumir este capítulo.

Resumo
Com isso, chegamos ao fim deste pequeno capítulo. Começamos aprendendo
como acionar cargas em lote, como lidar com erros e validar trabalhos em lote e,
em seguida, passamos para pipelines ADF e Synapse. Aprendemos sobre como
configurar gatilhos, gerenciar e monitorar pipelines, executar pipelines do Spark e
configurar o controle de versão no ADF e no Synapse Pipelines. Com todo esse
conhecimento, agora você deve estar confiante na criação e no gerenciamento de
pipelines usando o ADF, o Synapse Pipelines e o Lote do Azure.

Este capítulo marca o fim da seção Projetando e Desenvolvendo Processamento


de Dados, que responde por cerca de 25-30% das metas de certificação. A partir
do próximo capítulo, passaremos para a seção Projetando e Implementando
Segurança de Dados, onde nos concentraremos nos aspectos de segurança do
processamento de dados.

Chapter 12: Designing Security for Data


Policies and Standards
Welcome to the next section of the syllabus, Design and Implement Data Security.
This section accounts for about 10–15% of the questions in the certification.
According to the syllabus, this section is supposed to have two chapters: one
focusing on the design aspects, and another focusing on implementation aspects.
But, to ensure a better flow of topics and to avoid too many context switches, I've
merged both the design and implementation details into this single chapter. Once
you have completed this chapter, you should be able to recognize sensitive
information and be able to design and implement various sensitive information-
handling techniques such as data masking, row and column level security,
implementing role-based access and access-controlled lists, enabling encryption
and more. You will also be aware of the good practices for handling keys, secrets,
and certificates, and understand the low-level implementation details of handling
secure data in Spark. Overall, you will be able to take care of the design and
implementation of the data security and privacy aspects of your data lake.

We will be covering the following topics in this chapter:

 Designing and implementing data encryption for data at rest and in transit

 Designing and implementing data auditing strategies

 Designing and implementing data masking strategies

 Designing and implementing Azure role-based access control and POSIX-like


access control lists for Data Lake Storage Gen2

 Designing and implementing row-level and column-level security

 Designing and implementing data retention policies

 Designing and implementing purging data based on business requirements

 Managing identities, keys, and secrets across different data platform


technologies

 Implementing secure endpoints (private and public)

 Implementing resource tokens in Azure Databricks

 Loading DataFrames with sensitive information

 Writing encrypted data to tables or Parquet files

 Designing for data privacy and managing sensitive information


Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

Vamos começar!

Introducing the security and privacy


requirements
How do you go about designing for the security and privacy of data? Well, let's
take an example and try to walk through some scenarios. Let's consider our
faithful Imaginary Airport Cabs (IAC) example that we used in our previous
chapters. We have already seen that the cab company gets a lot of trips,
customers, and driver information streaming in. We have also learned how to store
the data in the data lake and SQL stores. Now, let's get a little deeper into the
storage topic and figure out how to safeguard confidential and private information.

Let's consider the following requirements from the IAC security team:

 Data needs to be stored and transferred securely as we are dealing with cloud
systems, and no one other than the IAC employees should have access to the
data.

 Changes to data and any activity on the data should be recorded for
compliance reasons.

 Not everyone should have access to all the data. It should be on a need-to-
know basis.

 Maintain customer privacy at all costs.

 Older data should be safely deleted after one month.


These look like pretty standard requirements for any company. Now, let's get into
each of the topics in this chapter and learn how they help accomplish the
preceding requirements.

Designing and implementing data


encryption for data at rest and in transit
The usual questions from anyone who wants to store data on a public cloud would
be as follows:

 How safe is my data?

 Can the employees of the cloud company access my data?

 Can any outsiders access my data?

Such concerns are usually addressed by cloud companies like Azure using


encryption at rest and in transit. This also happens to be the first requirement of
our example requirements for IAC. Let's look at encryption at rest in detail.

Encryption at rest
Encryption at rest is the process of encrypting data before writing it to disks and
decrypting the data when requested by applications. Encryption at rest protects
data from physical disk theft, retrieval of data from lost disks, unauthorized data
access by malicious cloud company employees, and so on. Unless someone has
the decryption key or possesses insanely powerful supercomputing resources (the
kind that governments might have – although, even with the current
supercomputers, it is extremely difficult if the encryption key is strong and big
enough), the data cannot be retrieved. It will just appear as gibberish if anyone
tries to directly copy the data from the disks.

This form of security has become a fundamental requirement for any data stored
on the cloud, and Azure does a good job of providing encryption-at-rest options for
most of its storage solutions. In this topic, we will look at the encryption-at-rest
options available in Azure Storage and Azure Synapse SQL.
Encryption at rest and in transit is usually required for compliance with various
regulations. So, it is not just about customer concerns; it might be required by law
too. You can learn about the various regulations and the levels of compliance
provided by the various Microsoft services
here: https://docs.microsoft.com/en-us/compliance/regulatory/offering-home.

Let's now learn how Azure Storage and Synapse SQL pools provide encryption at
rest.

Encryption at rest in Azure Storage

Azure Storage provides encryption at rest by default. It secures your data without


you even requesting it. In fact, you cannot disable Azure Storage encryption. Azure
Storage uses its own keys to encrypt data. It also provides the option for customers
to use their own encryption keys. This provides additional control to the user. Such
user-provided keys are called Customer-Managed Keys (CMKs). You can enable
CMKs from the Azure Storage screen, as shown here:

Figure 12.1 – Enabling CMKs in Azure Storage


One of the requirements for the CMK is that the customer's key needs to be safely
stored in Azure Key Vault. Think of Azure Key Vault as an online version of a
physical vault. You can store all your passwords, secret keys, access keys, and so
on in Key Vault and applications can access these keys securely during runtime.
This method ensures that secrets and passwords need not be stored as part of the
code base. We will learn more about Key Vault later in this chapter.

You can learn more about CMKs


here: https://docs.microsoft.com/en-us/azure/storage/common/customer-managed-
keys-overview.

Encryption using CMKs would address IAC's concerns about the secure storage of
data. Let's look next at how Synapse SQL encrypts data files.

Encryption at rest in Azure Synapse SQL

This section applies to Azure SQL technologies in general. In Azure Synapse SQL,
encryption at rest is accomplished using a feature called Transparent Data
Encryption (TDE). In TDE, the encryption happens in real time at the page level.
Pages are encrypted before writing to disk and decrypted before reading back into
memory. Unlike Azure Storage, TDE must be manually enabled for Azure Synapse
SQL. But for other SQL technologies such as Azure SQL, it is enabled by default.

You can enable TDE in Azure Synapse SQL from the SQL pool screen under


the Transparent data encryption tab:
Figure 12.2 – Enabling TDE using the Azure portal

You can also enable TDE by executing the following statement as an admin user
on the Azure Synapse SQL terminal:

ALTER DATABASE <TABLENAME> SET ENCRYPTION ON;


CopyExplain

Nota

TDE encrypts the database and secures against data theft by encrypting the
backup and snapshot files too.

You can learn more about TDE


here: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/sql-data-warehouse-encryption-tde-tsql.

Azure Synapse SQL also provides the option for customers to bring in their own
encryption keys. If you need to configure a Customer Managed Key (CMK), you
should enable double encryption using a CMK during the creation of a
Synapse workspace itself, as shown in the following screenshot.
Figure 12.3 – Configuring a CMK in Azure Synapse SQL

You can learn more about CMKs with TDE here: https://docs.microsoft.com/en-


us/azure/azure-sql/database/transparent-data-encryption-tde-overview?
tabs=azure-portal#customer-managed-transparent-data-encryption---bring-your-
own-key.

Let's look at the Always Encrypted feature of Azure SQL next.

Always Encrypted

Always Encrypted is a feature provided by Azure SQL and SQL Server databases


to encrypt selected database columns using client drivers. The Always Encrypted
client driver fetches the encryption key from a secure location such as Azure Key
Vault to encrypt or decrypt the specified column data. Since the encryption key is
never available to the database engine, the database administrators cannot access
the data; only the data owners who have access to the encryption keys will be able
to access the data.

There are two types of keys used for Always Encrypted:

 Column encryption key – The key that is used to encrypt/decrypt a column

 Column master key – The protection key to encrypt column encryption keys

Here is sample code to encrypt the two columns Email and SSN of a Customer


table:

CREATE COLUMN MASTER KEY CMK  

WITH (  

     KEY_STORE_PROVIDER_NAME = 'AZURE_KEY_VAULT',   

     KEY_PATH = 'KeyVault/key/path'  

   );  

---------------------------------------------  

CREATE COLUMN ENCRYPTION KEY CEK   

WITH VALUES (  

    COLUMN_MASTER_KEY = CMK,   

    ALGORITHM = 'RSA_OAEP',   

    ENCRYPTED_VALUE = 0x020002134……

);  

---------------------------------------------  

CREATE TABLE Customer (  

   [name] VARCHAR(30),

   [email] VARCHAR(10)   

        COLLATE  Latin1_General_BIN2 ENCRYPTED WITH

(COLUMN_ENCRYPTION_KEY = CEK,  
        ENCRYPTION_TYPE = RANDOMIZED,  

        ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),   

   [phone] VARCHAR (12),

   [SSN] VARCHAR (11)   

        COLLATE  Latin1_General_BIN2 ENCRYPTED WITH

(COLUMN_ENCRYPTION_KEY = CEK,  

        ENCRYPTION_TYPE = DETERMINISTIC ,  

        ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),   

);  
CopyExplain

The option specified for ensures the client driver always generates the same


encrypted value for the given plain text. The option, on the other hand, generates a
different encrypted value each time.DETERMINISTICemailRANDOMIZED

Tip

If you plan to use the encrypted column in JOINs, INDEXES, AGGREGATES, and
so on, use the type and not a type.Deterministicrandom

There are four database permissions that are needed for Always Encrypted.

 ALTER ANY COLUMN MASTER KEY – For creating and deleting column master keys
 ALTER ANY COLUMN ENCRYPTION KEY – For creating and deleting
column encryption keys
 VIEW ANY COLUMN MASTER KEY DEFINITION  – To read column master keys to query
encrypted columns
 VIEW ANY COLUMN ENCRYPTION KEY DEFINITION  – To read column master keys to
query encrypted columns

Note
Since the encryption and decryption are done using a client driver, server-side
operations such as , , and will not work with Always Encrypted columns. SELECT
INTOUPDATEBULK INSERT

You can learn more about Always Encrypted here: https://docs.microsoft.com/en-


us/sql/relational-databases/security/encryption/always-encrypted-database-
engine?view=sql-server-ver15.

Next, let's look at encryption in transit.

Encryption in transit
Another important security concept is encryption in transit. This refers to encrypting
the data that is being sent over a wire or, in other words, any data that is being
moved from one place to another. Examples of data movement could be data
being read by an application, data getting replicated to a different zone, or data
being downloaded from the cloud. Safeguarding the data during transfer is as
important as keeping it safe while storing.

Encryption in transit is usually accomplished via two protocols, Secure Sockets


Layer (SSL) or Transport Layer Security (TLS). SSL support is being
discontinued for some Azure services, so TLS is the preferred network protocol to
encrypt data during transit.

Let's learn how Azure Storage and Synapse SQL pools provide encryption in
transit.

Enabling encryption in transit for Azure Storage

Let's look at how to enable TLS in Azure Storage.

You can go to the Blob or ADLS Gen2 storage home page and select
the Configuration tab under Settings. On the configuration page, you will be able
to configure the minimum TLS version. The recommendation is to go with TLS
version 1.2. Here is a screenshot of the TLS version page.
Figure 12.4 – Enabling TLS in Azure Storage

This is how we can enable TLS for Azure Storage. Next, let's look at how to
configure TLS in a Synapse SQL pool.

Enabling encryption in transit for Azure Synapse SQL

Azure Synapse SQL automatically secures data in transit using TLS protocols. In


fact, Synapse SQL enforces encryption of all the connections irrespective of the
setting of or in the connection string. So, we don't need to do any additional
configurations from our side.EncryptTrustServerCertificate

You can learn more about information protection in Azure Synapse SQL and other
Azure SQL variants
here: https://docs.microsoft.com/en-us/azure/azure-sql/database/security-overview.

Apart from encryption, the other ways to secure data while in transit is to set up


dedicated Virtual Private Networks (VPNs) or to use Azure ExpressRoute.

You can find more information about VPNs here: https://docs.microsoft.com/en-


us/azure/vpn-gateway/.

ExpressRoute provides a private connection from your on-premises network to


the Azure cloud. It uses connectivity providers for the connection and doesn't use
the public internet. As such, the connections are fast, reliable, and secure.

You can find more about Azure ExpressRoute here: https://docs.microsoft.com/en-


us/azure/expressroute/.

Let's look next at data auditing strategies.


Designing and implementing a data
auditing strategy
This was the second requirement of our example IAC requirements – to keep track
of the activities on the data store for compliance purposes. Data auditing is the
process of keeping track of the activities that were performed on a service. This is
usually done via logs and metrics. Let's look at how Azure Storage supports data
auditing.

Storage auditing
Azure Storage supports audit logging via Storage Analytics logging. This is now
called classic monitoring. There is a newer version of logging available
under Azure Monitor. Azure Monitor storage support was in preview mode at the
time of writing this book. Let's look at both ways of enabling audit logging. Storage
Analytics logging can be enabled as shown in the following screenshot:

Using a classic diagnostic setting


Figure 12.5 – Enabling metrics logging for auditing in the Azure storage

Once enabled, the logs will get stored in a container called under your storage
account. You can use any data explorer or data processing tools to view and
analyze the data under this folder.$logs

Important Note

It might take up to an hour for the logs to appear under the container. Storage
Analytics doesn't immediately flush the logs. It does it at regular intervals or when it
has enough data to flush the data to the blob. $logs

You can learn more about Azure Storage Analytics logging


here: https://docs.microsoft.com/en-us/azure/storage/common/storage-analytics-
logging.

Next, let's look at how to achieve this using Azure Monitor.

Using Azure Monitor

Azure Monitor is Azure's full-stack monitoring service. It is enabled by default for


most Azure services. It collects certain default metrics and logs for every service
and can be configured to collect more detailed logs and metrics as required. In the
case of Azure Storage, Azure Monitor starts collecting metrics and logs once we
enable Diagnostic settings on the Azure Storage screen in the Azure portal, as
shown in the following screenshot:
Figure 12.6 – Azure Monitoring – Diagnostic settings

Click on the + Add diagnostic setting link to configure the diagnostic setting, as


shown in the following screenshot:
Figure 12.7 – Configuring a diagnostic setting using Azure monitoring

On the Diagnostic setting screen, you can specify which logs and metrics you
want to record and which location/tool to send them to. Azure Monitor will start
recording and sending the logs and metrics from then on to the configured service.
You can also select the destination where you want to send the logs to. Remember
that there will be a cost associated with storing the logs in any of these
destinations, similar to the cost of storing any other data in them.

You can learn more about Azure monitoring for storage


here: https://docs.microsoft.com/en-us/azure/storage/blobs/monitor-blob-storage.

Let's look next at auditing in SQL.

SQL auditing
Azure Synapse SQL provides the option to track all database events and activities
via its Auditing feature. You can easily enable Auditing from the Azure SQL
Auditing tab on the SQL pool portal page. An example is shown in the next
screenshot. It provides multiple storage options, such as Azure Storage, Log
Analytics, and Event Hub as the destination of the audit logs. You can configure
the destination according to your business needs. For example, if you want to do
some real-time analysis of audit logs, then you can send them to Event Hub. If you
want to store it for compliance purposes, you can choose to store it in Azure Blob
storage. If you want to do some ad hoc querying and analysis, then use Log
Analytics. We will learn more about Log Analytics later in this chapter.

Figure 12.8 – Configuring Azure Synapse SQL Auditing

You can learn more about SQL Auditing


here: https://docs.microsoft.com/en-us/azure/azure-sql/database/auditing-
overview.

Let's look next at data masking strategies.

Designing and implementing a data


masking strategy
Data masking is a technique used in SQL technologies to hide sensitive data in
SQL query results from non-privileged users. For example, the credit card info of a
customer might be masked as instead of showing the complete number while
querying a customer table in Synapse SQL. The data itself is not changed in the
tables, but the queries and views modify the data dynamically to mask sensitive
information.XXXX-XXXX-XXXX-1234

This feature helps enforce the following two requirements of IAC:

 Not everyone should have access to all the data – it should be on a need-to-
know basis.

 Maintain customer privacy at all costs.

You can easily create a data mask in Azure Synapse SQL (and in Azure SQL too)
using a feature called Dynamic Data Masking (DDM). The following screenshot
shows how this can be done in Azure Synapse SQL:

Figure 12.9 – Setting up DDM from the Azure portal

From the previous screen, you can click on the + Add mask link to create a new
mask. For example, if you want to create an email mask, you just need to select
the Email option from the drop-down list, as shown in the following screenshot:
Figure 12.10 – Creating an email mask

The previous screenshot also shows other options that you can use, such
as Credit card value, Number, and Custom string.

You can also set up DDM using T-SQL in Azure Synapse SQL, as shown here:

ALTER TABLE dbo.DimCustomer  

ALTER COLUMN emailId ADD MASKED WITH (FUNCTION = 'email()');


CopyExplain
Nota

DDM does not encrypt the column. It only masks the values during queries.

You can learn more about DDM


here: https://docs.microsoft.com/en-us/azure/azure-sql/database/dynamic-data-
masking-overview.

Let's look next at Azure RBAC and ACL policies, which also deal with a similar
requirement of restricting access to data.

Designing and implementing Azure role-


based access control and a POSIX-like
access control list for Data Lake Storage
Gen2
This section also deals with restricting data access to unauthorized users
and satisfies the following requirement of our sample IAC requirements:

Not everyone should have access to all the data. It should be on a need-to-know
basis.

Azure uses and recommends the principle of least privilege, which means


assigning the least possible privilege required to accomplish a task. Let's see how
RBAC and ACLs help to achieve this goal.

Restricting access using Azure RBAC


Azure Role-Based Access Control (Azure RBAC) is an authorization system
that controls who can access what resources in Azure. Azure RBAC works hand in
hand with Azure AAD. Let's try to understand the basics of RBAC before getting
into the details.
RBAC has three components:

 Security principal: This could be any user, group, or managed


identity (service accounts whose life cycle is completely managed by Azure)
created within AAD. You can think of the service principal as the "who" part of
the authorization. It is the entity that we are requesting permission for. It could
be real people or service accounts that are used to run services automatically
without human intervention.
 Role: Think of the examples of admin roles or read-only guest roles that you
have used to log in to any system. An admin role would have had complete
access to create, read, write, delete, and so on, while a guest account might
have just had read-only access. A role basically defines what actions can be
performed by a user. Azure has a huge list of predefined roles, such
as Owner, Contributor, and Reader, with the right list of permissions already
assigned. So, you can just choose to use one of them instead of creating a
new role.
 Scope: Scope refers to all the resources where the role needs to be applied.
Do you want the rules to apply only to a resource group? Only to a container
in storage? Multiple containers? And so on.

In order to define an RBAC rule, we need to define all three of the above and
assign a role and scope to the security principal.

Now, let's look at how to accomplish this for a data lake. From the Azure Storage
home page, select Access Control (IAM). There, you can add role assignments,
as shown in the following screenshot. You can select the role from the Role field,
the security principal from the Assign access to field, and finally, the scope, in this
case, would be the Storage account itself:
Figure 12.11 – Configuring the RBAC role assignment in ADLS Gen2

You can learn more about Azure RBAC


here: https://docs.microsoft.com/en-us/azure/role-based-access-control/.

Let's look next at Access Control Lists (ACLs).

Restricting access using ACLs


While Azure RBAC provides coarse-grained access such as who can read/write
data in an account, ACLs provide more fine-grained access such as who can read
data from a specific directory or a file. RBAC and ACL complement each other to
provide a wide spectrum of access control.

Each directory and file in Azure Storage has an ACL. You can assign any of (or all
of) the read, write, and execute permissions to individual security principals
(users) or groups to provide them with the required access to the file or directory.
ACLs are enabled by default for ADLS Gen2.

Here is how we can assign ACLs in ADLS Gen2. Just right-click on the file or folder
name and select Manage ACL:
Figure 12.12 – Right-click on the files or folders to select Manage ACL

On the Manage ACL screen, you can assign Read, Write, and Execute access to


the principals under Security principal, as shown in the following screenshot:

Figure 12.13 – Configuring the ACL in ADLS Gen2

You can configure the right access level for users according to your requirements.
Let's next see the order in which Azure evaluates RBAC and ACLs.
How does Azure decide between RBAC and ACLs if there are conflicting rules?

Here is a flow chart reproduced from Azure that shows how the authorization
decision is made between RBAC and ACL:

Figure 12.14 – RBAC and ACL evaluation sequence

In case of conflicts, Azure gives precedence to RBAC. So be aware of this priority


rule while designing the security/compliance aspects of your data lake.

Let's next learn about some of the limitations of RBAC and ACLs.

Limitations of RBAC and ACL

Here are some other restrictions on RBAC and ACL that you should be aware of
while designing for security and privacy requirements:

 Azure RBAC allows 2,000 role assignments per subscription.

 ACL allows up to 32 ACL entries per file and directory. This number is a bit
restricting, so ensure that you don't end up adding too many individual users;
instead, create groups and add only groups to ACLs.
You can learn more about ACLs
here: https://docs.microsoft.com/en-us/azure/storage/blobs/data-lake-storage-
access-control.

Azure also supports two other authentication methods, called Shared


Key authorization and Shared Access Signature (SAS) authorization. Shared
Key authorization involves sharing an Access key, which basically gives admin-like
access to the resource to anyone possessing the key. SASs are slightly better
because you can define what actions are allowed with the SAS key.

If you use Shared Key or SAS authorization methods, they will override both RBAC
and ACLs. The recommendation is to use AAD RBAC and ACLs wherever
possible. We will learn more about SAS keys later in this chapter.

Let's next learn about row- and column-level security in Azure Synapse SQL. Since
this also deals with restricting access to data, I've grouped it together with the
RBAC and ACL sections.

Designing and implementing row-level


and column-level security
Azure Synapse SQL (and Azure SQL) provide some very useful fine-grained
security at the level of rows and columns in a table. Let's learn how to use these
features for restricting data access, starting with row-level security.

Designing row-level security


Row-level security restricts access to certain table rows to unauthorized users. On
a high level, you can think of this as similar to using conditions in a statement.
Row-level security is achieved by creating security policies. We will look at an
example of how to create such a rule in the next few pages. These rules reside in
the database itself. Hence, irrespective of how the data is accessed, either via
queries, views, or any other methods, the data access restriction will be
enforced.WHERESELECT
Let's look at an example using our IAC scenario again. Let's imagine that the IAC
company is trying to launch their service at a bunch of new locations, but they want
to keep the details under wrap as they don't want the news to be leaked. So, they
define two sets of users, one called that has access to all the rows and one
called that doesn't have access to all the rows. Let's see how to implement this
example in Azure Synapse SQL. Start a Synapse dedicated pool and open an
editor from the Synapse workspace:HiPriv_UserLowPriv_Users

1. Create a new schema to store our row access policy:


CREATE SCHEMA Security;  
CopyExplain
2. Create a T-SQL function that has the logic to decide who has access to the
pre-launch data. In this case, we can assume that all the are the pre-launch
locations:tripId >= 900
3. CREATE FUNCTION Security.tvf_securitypredicate(@tripId AS int)  

4.     RETURNS TABLE  

5. WITH SCHEMABINDING  

6. AS  RETURN SELECT 1 AS tvf_securitypredicate_result

WHERE  @tripId < 900 OR USER_NAME() = 'HiPriv_User';  
CopyExplain
7. Create a security policy using the previously defined function:
8. CREATE SECURITY POLICY PrivFilter 

9. ADD FILTER PREDICATE Security.tvf_securitypredicate(tripId)

ON dbo.TripTable WITH (STATE = ON);
CopyExplain
10. Now, test it out with :HiPriv_User
11. EXECUTE AS USER = 'HiPriv_User';

SELECT * from dbo.TripTable
CopyExplain
12. When executed as , all the rows, including the pre-launch rows with , show up,
as shown in the following screenshot:HiPriv_UserID >= 900
Figure 12.15 – All rows including pre-launch show up

6. Now, let's test it out with :LowPriv_User


7. EXECUTE AS USER = ‹LowPriv_User›;

SELECT * from dbo.TripTable
CopyExplain
8. When executed as , the pre-launch lines are hidden, as shown in the following
screenshot:LowPriv_User

Figure 12.16 – Row-level security blocking the pre-launch location rows

I hope that you've got a good idea of the row-level security concept. Now, let's look
next at column-level security.

Designing column-level security


Column-level security is similar to the data masking feature that we saw earlier in
this chapter in the Designing and implementing a data masking strategy section.
But instead of just masking the values of the column, here we restrict the column
access completely to unauthorized users. In the case of column-level security also,
the rules reside in the database itself. Hence, irrespective of how the data is
accessed – say, via queries, views, or any other method – the data access
restriction will be enforced.

Here is an example of how to implement column restrictions.

Let's consider our IAC example, the dimension table. Here is the definition of the
table:DimCustomer

CREATE TABLE dbo.DimCustomer

    [customerId] INT NOT NULL,

    [name] VARCHAR(40) NOT NULL,

    [emailId] VARCHAR(40),

    [phoneNum] VARCHAR(40),

    [city] VARCHAR(40)

)
CopyExplain

In order to restrict access, you need to use the command, as shown here:GRANT

GRANT SELECT ON dbo.DimCustomer (customerId, name, city) TO LowPriv_User;


CopyExplain

Here, we just give access to the , , and columns. will not have access to


the or columns. If you run the following query as , you will get an
error: LowPriv_UsercustomerIdnamecityLowPriv_UseremailIdphoneNumLowPriv_User

SELECT * FROM Customer;


-- The SELECT permission was denied on the column 'emailId' of the object 'DimCustomer', database

'DedicatedSmall', schema 'dbo'. The SELECT permission was denied on the column 'phoneNum' of

the object 'DimCustomer', database 'DedicatedSmall', schema 'dbo'.


CopyExplain

The row and column restriction features are particularly useful when only a very
small subset of the data in the table is sensitive. This avoids the need to split the
table and store the sensitive data separately.

You can learn more about column-level security


here: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/column-level-security.

Let's look next at data retention policies.

Designing and implementing a data


retention policy
The last requirement for IAC was to securely delete the data so that it doesn't get
into the hands of any malicious users.

Older data should be safely deleted after a period of time.

This section on data retention and the next section on data purging explain some
of the techniques that can be used to achieve regular and secure cleanup of data.

In Chapter 2, Designing a Data Storage Structure, under the Designing a data


archiving solution section, we learned about data life cycle management. We can
use the same service to design our data retention policies too. The data life cycle
management screen has options to either move data to Cool or Archive tiers or
delete the blob itself. Let's look at a screenshot from Chapter 2, Designing a Data
Storage Structure, again for convenience:
Figure 12.17 – Configuring data life cycle management

Based on our requirements, we can configure entire batches of data to be deleted


after a specified time.

You can learn more about data life cycle management in Azure Data Lake Storage
here: https://docs.microsoft.com/en-us/azure/storage/blobs/lifecycle-management-
overview.

Let's look next at the other options available to purge data from data lake stores
and SQL-based stores.
Designing to purge data based on
business requirements
Data purging is another overlapping concept with data retention. Data purging
refers to the process of safely deleting data as per business requirements. Let's
look at the options available in Azure Data Lake Storage and Azure Synapse SQL.

Purging data in Azure Data Lake Storage Gen2


There are two ways in which we can achieve scheduled data deletion or data
purging. One is the same as data retention, using life cycle management in Azure
Storage. The second technique is to use Azure Data Factory. Whenever we delete
data in Azure, it ensures that the storage locations are overwritten so that the
deleted data cannot be retrieved by a malicious user. You can refer to Microsoft's
data protection policy
here: https://docs.microsoft.com/en-us/azure/security/fundamentals/protection-
customer-data.

We can periodically or conditionally delete files from Azure Storage using


the Delete Activity in ADF. We have already seen the Delete activity as part of
the Regressing to a previous stage section in Chapter 9, Designing and
Developing a Batch Processing Solution. Let's look at it again here with a different
example. Here, we have set up the Delete activity to delete all files older than 30
days:
Figure 12.18 – ADF Delete options

In the End time (UTC) section, we have added the following line to select all files
older than 30 days – . This takes care of deleting all data in the configured folder
that is older than 30 days.@{adddays(pipeline().TriggerTime, -30)}

You can learn more about the ADF Delete activity


here: https://azure.microsoft.com/en-in/blog/clean-up-files-by-built-in-delete-
activity-in-azure-data-factory/.

Let's look next at how to purge data in SQL.

Purging data in Azure Synapse SQL


Purging in Synapse SQL is done using the command. Here is an example of how
that can be done where is a table name:TRUNCATEdbo.DimCustomer

TRUNCATE TABLE dbo.DimCustomer;


CopyExplain

Let's next look at how to create and manage keys, secrets, and managed
identities.
Managing identities, keys, and secrets
across different data platform
technologies
There are mainly two technologies used in Azure for managing identities, keys,
secrets, certificates, and basically anything confidential. They are Azure Active
Directory (AAD) and Azure Key Vault. We looked briefly into Azure Key Vault
earlier in this chapter in the Encryption at rest in Azure Storage section. Let's look
into both of these services in detail here.

Azure Active Directory


AAD is Azure's identity and access management service. It supports managing
users, groups, service principals, and so on. You can think of service principals
as the service accounts used to run applications automatically. These
service principals are also called AAD applications.

Let's now see an example of creating users in AAD:

1. From the Azure portal, search for AAD or Azure Active Directory, and select
that service.
2. Once inside, you can click on the Users tab under the Manage category, and
then select the + Add link, as shown in the following screenshot:
Figure 12.19 – Creating a new user in AAD

3. That opens up the New user screen, where you can add the details of the
user and click on the Create button to create a new user, as shown in the
following screenshot:
Figure 12.20 – New user creation screen in AAD

4. To manage users, you can go to the Users tab where you should be able to


see the list of users under your AAD tenant. You can select users and perform
operations such as edit, delete, and so on.

Creating groups and apps is similar to creating new users, so we will not be going
into the details of it. Next, let's look at another important concept that services and
resources (such as VMs, SQL databases, Synapse SQL, and so on) in Azure use
to authenticate themselves to AAD.

Managed identities
Azure AAD supports another important feature called managed identities. These
are identities that are assigned to instances of Azure services such as VMs,
Synapse, SQL databases, and so on. The life cycle of these identities is
automatically managed by AAD; hence, they are called managed identities. For
example, when we create a new Synapse workspace, it has a managed identity
automatically created in AAD, and when the workspace is deleted, the managed
identity is automatically deleted. This managed identity can be used by the Azure
Synapse instance to authenticate itself with AAD, instead of the application owners
having to store secrets inside the application or having separate code sections to
authenticate each and every service to AAD. You can find the managed identity ID
on your application overview page. An example for Synapse is shown in the
following screenshot:

Figure 12.21 – A managed identity for Synapse

You can learn more about AAD


here: https://docs.microsoft.com/en-us/azure/active-directory/.

Next, let's learn about storing keys, secrets, and certificates securely using Azure
Key Vault.

Azure Key Vault


Azure Key Vault is another very commonly used service in Azure that is used to
store keys, secrets, and certificates securely. A key vault is just like a real-world
vault used to store confidential things. Azure Key Vault is a digital version of a vault
that encrypts and decrypts information using 256-bit AES encryption. It provides
the following functionalities:
 Key Management: Helps in creating and managing encryption keys
 Secrets Management: Helps in creating and storing secrets, passwords,
URIs with keys, and so on that can be accessed by authorized applications
and users using Key Vault links
 Certificate Management: Helps to create and manage SSL and TLS
certificates for Azure resources

Key Vault simplifies secret management. It eliminates the need to store secrets in
code. It is a centralized service, so every time we need to change a secret or an
encryption key, we just have to update it in Key Vault. It also supports rotating
certificates and keys without human intervention. If you have any kind of secrets in
your applications, it is highly recommended to use Azure Key Vault.

Let's look at how to generate some keys and secrets using Key Vault:

1. From the Azure portal, search for and select that service.Key Vault
2. Once inside, select the Keys tab and then select the + Generate/Import link,
as shown in the following screenshot:

Figure 12.22 – Creating keys, secrets, and certificates in Key Vault

3. When you click on the +Generate/Import link, you will get the Create a


key screen, as shown in the following screenshot:
Figure 12.23 – Creating new encryption keys in Key Vault

4. Just enter the details and click on Create to create a new encryption key. You
can use this encryption key to encrypt your storage accounts or databases.
5. Similar to keys, you can also create secrets. You just have to select
the Secrets tab on the Azure Key Vault page and click on + Generate/Import;
you will see the following screen:
Figure 12.24 – Creating new secrets in Key Vault

6. Once you enter the details and click on Create, a new secret will get created.

Next, let's see how to use the secrets stored in Key Vault in other services such as
Azure Synapse Analytics.

In order to use Key Vault in Synapse Analytics, we have to first add the Key Vault
itself as one of the linked services. We have already looked at many examples of
adding a linked service, so you should be familiar with the process already. Once
we have Key Vault registered as one of the linked services, anytime we add any
other linked service, we will have the option to use secrets directly from Azure Key
Vault. The following screenshot shows an example of creating a new linked service
to Azure MySQL Database. You can see the option to use an Azure Key
Vault secret instead of manually entering the Connection string details:

Figure 12.25 – Accessing keys from inside Synapse Analytics

Azure Key Vault can be accessed using the command line too:

 You can also set a new password using the CLI, as shown here:
az keyvault secret set --vault-name "<KEYVAULT-NAME>" --name "SamplePassword" --

value "SecretValue"
CopyExplain
 You can access your passwords using the following URL:
https://<KEYVAULT-NAME>.vault.azure.net/secrets/SamplePassword
CopyExplain
 You can view the password using the following:
az keyvault secret show --name " SamplePassword " --vault-name "< KEYVAULT-NAME>" --

query "value"
CopyExplain

You can learn more about Azure Key Vault


here: https://docs.microsoft.com/en-in/azure/key-vault/.

I hope this has given you a fairly good understanding of the components involved
in managing identities, keys, and secrets in Azure.

Let's learn a bit more about the Azure Storage SAS keys that we introduced in the
RBAC section of this chapter as this is important from a certification perspective.

Access keys and Shared Access keys in Azure


Storage
Azure Storage generates two 512-bit storage access keys when we create a new
storage account. These keys can be used to access the data in the storage
accounts. When these keys are used to authenticate access, it Is called
the Shared Access key authentication method.

You can view the access keys from the Storage portal. Select the Security +
networking tab and select the Access Keys option under that.

Access keys are like root passwords. They give complete access to all the
resources in a storage account. So, if we need to give restricted access to
someone or some application, we can either use the Azure RBAC option that we
discussed earlier in this chapter or use a Shared Access Signature (SAS). A SAS
is a URI that grants restricted access for a specific period, to specific IP addresses,
specific permissions, and so on. Unlike access keys, SAS keys will not have
permissions to modify or delete accounts.

There are three types of SAS keys:

 Service SAS: This type of SAS key provides access to just one of the storage
services, such as Blobs, Tables, Files, or Queues. Service SAS keys are
signed using Storage access keys.
 Account SAS: This type of SAS key provides access to multiple storage
services such as Blobs, Tables, Files, and Queues. Account SAS keys provide
access to read, write, and delete operations on multiple services like blob
containers, tables, queues, and files. Account SAS keys are signed using
Storage access keys.
 User Delegation SAS: If a SAS key is signed by AAD, the SAS is called a
User Delegation SAS. This is the SAS approach recommended by Azure. But
this option works only for Blob storage and not other storage options such as
tables, queues, or file services.

Note

Since access keys are used to sign Shared Access keys like service SAS, and
account SAS, these keys will get invalidated when you regenerate new access
keys for storage.

You can learn more about SAS keys and how to generate them
here: https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-
shared-key.

Let's look next at how to use private and public endpoints.

Implementing secure endpoints (private


and public)
A public endpoint refers to the default way of creating Azure services (such as
Azure Storage, Azure Synapse, and Azure SQL), where the service can be
accessed from a public IP address. So, any service that you create in Azure
without configuring a Virtual Network (VNet) would fall under the public endpoint
category.

On the other hand, (as you would have guessed by now), private endpoints are
more secure setups involving private IP addresses. A private endpoint is part of a
bigger service called the Private Link service. The Private Link service
makes your Azure service available only on certain private IP addresses within
your VNets. No one from outside your VNets will even be aware of the existence of
such a service. The private endpoint technically refers to the network interface that
uses the private IP from your VNet, and the Private Link service refers to
the overall service that comprises the private endpoints and the private network
(link) over which the traffic traverses. When you establish a private link to your
Azure service, all the data to that service traverses through Microsoft's backbone
network without being exposed to the public internet.

Let's look at how to create a private link to one of our existing Synapse
workspaces:

1. Create a VNet. From the Azure portal, select Virtual networks and click on


the Create virtual network option. You will get a screen like the one shown in
the following figure. Fill in the details on this screen:
Figure 12.26 – Creating a new VNet

2. On the IP Addresses tab, you will have the ability to specify your IP address


range and subnets, as shown in the following screenshot:
Figure 12.27 – Configuring IP details for the new VNet

3. Fill in the rest of the tabs and click on Review + create to create the new
VNet.
4. Next, we will have to open the Private Link Service page from the Azure
portal. Just search for and you will see the service at the top.Private Link
5. On the Private Link Center page, select the Private endpoints tab and click
on +Add:
Figure 12.28 – Creating a private endpoint from Private Link Center

6. On the next page, you can select in which resource you want the endpoint to
be created:
Figure 12.29 – Configuring the service in which the private endpoint will be created

7. On the Configuration tab, you will be able to provide the VNet details:

Figure 12.30 – Configuring the VNet for the private endpoint

8. Once the preceding details are entered and you have clicked on the Review +
create button on the final screen, the private endpoint will be created.

From now on, the Synapse workspace can be accessed only within the analytics-
vnet that was specified in the example.
You can learn more about private endpoints here: https://docs.microsoft.com/en-
us/azure/private-link/create-private-endpoint-portal.

Now that you know how to create a private endpoint, there is another easy way to
do so using a managed virtual network and managed endpoints. When you
create a Synapse workspace, under the Networking tab, there is a Managed
virtual network option, as shown in the following screenshot:

Figure 12.31 – Creating a managed virtual network while creating a Synapse


workspace
When you enable Managed virtual network, Synapse takes care of creating the
VNet, creating the private endpoints, creating the right firewall rules, creating the
right subnets, and so on. This is a very convenient and less error-prone way to
create private endpoints. A managed private VNet and endpoints are no different
than manually created ones. It is just that the life cycle of managed VNets and
endpoints are taken care of by the host service, which in our case is Synapse.

Let's look next at using access tokens in Azure Databricks.

Implementing resource tokens in Azure


Databricks
Azure Databricks provides access tokens called Personal Access Tokens (PATs)
that can be used to authenticate Azure Databricks APIs.

The following example shows how to create a new Azure Databricks PAT:

1. Select User Settings from the Settings tab.

Figure 12.32 – Accessing User Settings in Azure Databricks

2. Click on the Generate New Token button.


Figure 12.33 – The Generate New Token button in Azure Databricks

3. Fill in the Comment and Lifetime fields required for the token:

Figure 12.34 – Creating a new Azure Databricks PAT

Nota

When you click on Generate, it will pop up a screen with the token. You will have
to copy and store it safely at that time. You will not be able to copy that token again
once that screen is closed. If you lose the token, you will have to delete it and
generate a new one.

4. You can also create a PAT using APIs, as shown here. For example, the
following request is for a token that will be valid for 1 day (86,400 seconds):
5. curl --netrc --request POST \

6. https://<databricks-instance>/api/2.0/token/create \

--data '{ "comment": "ADB PAT token", "lifetime_seconds": 86400 }'


CopyExplain
7. Once you have a PAT, you can use it in the APIs, as shown in the following
code block:
8. export DATABRICKS_TOKEN=<INSERT YOUR TOKEN>

9. curl -X GET --header "Authorization: Bearer $DATABRICKS_TOKEN"  

https://<ADB-INSTANCE>.azuredatabricks.net/api/2.0/clusters/list
CopyExplain

Nota

The maximum number of PATs per Azure Databricks workspace is 600.

You can learn more about PATs


here: https://docs.microsoft.com/en-us/azure/databricks/administration-guide/
access-control/tokens.

Similar to the PATs of Azure Databricks, regular AAD tokens can also be used for
authorization. If you are interested, you can read about it
here: https://docs.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/
service-prin-aad-token.

Let's look next at how to handle sensitive information within Spark DataFrames.

Loading a DataFrame with sensitive


information
Earlier in this chapter, we learned about techniques such as data masking, and
row- and column-level security for Azure Synapse SQL. Spark, at the time of
writing this book, didn't have such techniques to handle sensitive information. In
this section, we will look at an example of how to best emulate handling sensitive
information such as Personally Identifiable Information (PII) using encryption
and decryption:

1. Let's create a simple table that contains PII information such as social
security numbers (SSNs) using PySpark:
2. from pyspark.sql.types import StructType,StructField, StringType, IntegerType

3. cols = StructType([ \

4.     StructField("Name",StringType(),True), \

5.     StructField("SSN",StringType(),True), \

6.     StructField("email",StringType(),True)

7.   ])

8. data = [("Adam Smith","111-11-1111","james@james.com"),

9.     ("Brenda Harman","222-22-2222","brenda@brenda.com"),

10.     ("Carmen Pinto","333-33-3333", "carmen@carmen.com")

11.   ]

12. piidf = spark.createDataFrame(data=data,schema=cols)

display(piidf)
CopyExplain

The output will be something like the following:

Figure 12.35 – Sample table with PII

2. Next, let's import the Fernet encryption library, which provides the ability to
encrypt and decrypt text. You can download the Fernet library
from https://cryptography.io/en/latest/fernet/:
3. from cryptography.fernet import Fernet

encryptionKey = Fernet.generate_key()
CopyExplain
4. Define the User Defined Function (UDF) :encrypt
5. def encryptUdf(plaintext, KEY):
6.     from cryptography.fernet import Fernet

7.     f = Fernet(KEY)

8.     encryptedtext = f.encrypt(bytes(plaintext, 'utf-8'))

9.     return str(encryptedtext.decode('ascii'))

encrypt = udf(encryptUdf, StringType())


CopyExplain
10. Define the UDF :decrypt
11. def decryptUdf(encryptedtext, KEY):

12.     from cryptography.fernet import Fernet

13.     f = Fernet(KEY)

14.     plaintext=f.decrypt( encryptedtext.encode()).decode()

15.     return plaintext

decrypt = udf(decryptUdf, StringType())


CopyExplain
16. Encrypt the column DataFrame:SSN
17. df = piidf.withColumn("SSN", encrypt("SSN", lit(encryptionKey)))

display(encrypteddf)
CopyExplain

The output will now be encrypted.

Figure 12.36 – Output with PII information encrypted

6. Now, we can go ahead and save it as a table:


df.write.format("delta").mode("overwrite").option("overwriteSchema",

"true").saveAsTable("PIIEncryptedTable")
CopyExplain
7. Alternatively, you can also write the encrypted file to Parquet, as shown here:
encrypted.write.mode("overwrite").parquet("abfss://path/to/store")
CopyExplain
8. From now on, only whoever has the encryption key will be able to decrypt and
see the PII information. If you have the encryption key, you could decrypt the
column, as shown here:
9. decrypted = encrypteddf.withColumn("SSN", decrypt("SSN",lit(encryptionKey)))

display(decrypted)
CopyExplain

Figure 12.37 – Decrypted table with PII again

I hope you've now got an idea of how to perform column-level encryption and
decryption using DataFrames. This technique would work fine with both Synapse
Spark and Databricks Spark.

Next, let's see how to write encrypted data into tables and files.

Writing encrypted data to tables or


Parquet files
We actually just saw how to write encrypted data into tables and Parquet files in
the previous example. Here it is again, writing to tables:

df.write.format("delta").mode("overwrite").option("overwriteSchema",

"true").saveAsTable("PIIEncryptedTable")
CopyExplain
Here it is writing to Parquet files:

encrypted.write.mode("overwrite").parquet("abfss://path/to/store")
CopyExplain

Let's look next at some guidelines for managing sensitive information.

Designing for data privacy and managing


sensitive information
Any organization that handles sensitive information is usually bound by its country
or state laws and other compliance regulations to keep the data secure and
confidential. Aside from legal reasons, keeping sensitive data protected is very
important for the reputation of an organization and to reduce the risk of identity
theft for its customers. Azure security standards recommend the following
techniques to keep sensitive data safe:

 Identifying and classifying sensitive data – The very first step is to analyze
and identify all the sensitive data in your data stores. Some might be
straightforward, such as SQL tables or structured files, and some might be not
so straightforward, such as PII data being logged in log files. Azure also
provides tools that can help with the identification and classification of data.
For example, the Synapse SQL portal provides a feature for Data Discovery
and Classification, which automatically suggests sensitive columns. Here is
a sample screenshot of the Data Discovery and Classification page:

Figure 12.38 – Data Discovery and Classification


 Protecting the sensitive data – Once we have cataloged all the sensitive
data in our data stores, the next step is to take the necessary steps to protect
it. This includes all the techniques we discussed in this chapter and in the
storage chapters, such as separating the sensitive data into different
accounts, partitions, or folders, restricting access using RBAC and ACLs,
encrypting data at rest, encrypting data in transit, data masking, and row- and
column-level security.
 Monitoring and auditing the consumption of sensitive data – The best
security policy is to not trust anyone, not even the folks who officially have
access to the sensitive data. So, adding strong monitoring capabilities and
enabling audit trails helps in actively and passively tracking down any
malicious data access.

Let's also briefly look at the other services available in Azure to help with security
and threat management.

Microsoft Defender
In order to further strengthen your Azure application's security and threat
management ability, Azure provides a service called Microsoft Defender.
Microsoft Defender provides the tools and services required to continuously
monitor, alert, and mitigate threats to Azure services. Microsoft Defender is natively
integrated into most Azure services, so it can be enabled easily without requiring
major changes to your applications.

Microsoft Defender for Storage

Microsoft Defender for Storage can help identify threats such as anonymous
access, malicious content, compromised credentials, privilege abuse, and so on.

You can learn more about Microsoft Defender for Storage


here: https://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-
storage-introduction.

Microsoft Defender for SQL


Microsoft Defender for SQL can help identify threats such as SQL injection, brute-
force attacks, and privilege abuse.

You can learn more about Microsoft Defender for SQL


here: https://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-sql-
introduction.

That brings us to the end of this section. You can find more information about
handling sensitive information and data protection guidelines at the following links:

 https://docs.microsoft.com/en-us/security/benchmark/azure/security-control-
data-protection
 https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-
v2-data-protection

Resumo
With that, we have come to the end of this chapter. This chapter is one of the
lengthiest chapters but luckily not so complicated. We started with designing the
security requirements of our IAC example and then used that as our guide to
explore the various security and compliance topics. We learned about encryption at
rest and transit, enabling auditing for Azure Data Lake Storage and Synapse SQL,
implementing data masking, RBAC and ACL rules, row- and column-level security,
and had a recap on data retention and purging. After that, we continued with topics
such as AAD and Key Vault to manage keys, secrets, and certificates, learned
about secure endpoints, and details of tokens and encryption in Spark. Finally, we
wrapped it up with concepts to be followed to design data privacy. You have now
covered more or less all the important topics in handling security and privacy. You
should now be able to design and implement a complete security and privacy
solution on top of Azure Data Lake.

We will be exploring monitoring and optimization techniques for data storage and
data processing in the next chapter.
Chapter 13: Monitoring Data Storage and
Data Processing
Welcome to the next chapter. We are now in the final leg of our certification
training. This is the last section of the certification: Monitoring and Optimizing Data
Storage and Data Processing. This section contains two chapters—the current
one, Monitoring Data Storage and Data Processing, and the next
chapter, Optimizing and Troubleshooting Data Storage and Data Processing. As
this chapter's title suggests, we will be focusing on the monitoring aspect of data
storage and pipelines. Once you complete this chapter, you should be able to set
up monitoring for any of your Azure data services, set up custom logs, process
logs using tools such as Azure Log Analytics, and understand how to read
Spark directed acyclic graphs (DAGs). As with the previous chapters, I've taken
the liberty of reordering the topic sequence to make reading more comfortable,
without too many context switches.

Neste capítulo, abordaremos os seguintes tópicos:

 Implementing logging used by Azure Monitor

 Configuring monitoring services

 Understanding custom logging options

 Interpreting Azure Monitor metrics and logs

 Measuring the performance of data movement

 Monitoring data pipeline performance

 Monitoring and updating statistics about data across a system

 Measuring query performance

 Interpreting a Spark DAG

 Monitoring cluster performance

 Scheduling and monitoring pipeline tests


Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 An active Azure Data Factory (ADF) workspace

Vamos começar!

Implementing logging used by Azure


Monitor
Azure Monitor is the service we use to monitor infrastructure, services,
and applications. Azure Monitor records two types of data: metrics and logs.
Metrics are numerical values that describe an entity or an aspect of a system at
different instances of time—for example, the number of gigabytes (GBs) of data
stored in a storage account at any point in time, the current number of active
pipelines in ADF, and so on. Metrics are stored in time-series databases and can
be easily aggregated for alerting, reporting, and auditing purposes.

Logs, on the other hand, are usually text details of what is happening in the
system. Unlike metrics, which are recorded at regular intervals, logs are usually
event-driven. For example, a user logging in to a system, a web app receiving
a REpresentational State Transfer (REST) request, and triggering a pipeline in
ADF could all generate logs.

Since Azure Monitor is an independent service, it can aggregate logs from multiple
different services and multiple instances of the same service in Azure to give a
global perspective of what is happening with all our Azure services.

Here is an architecture diagram reproduced from the Azure documentation that


shows the core components of Azure Monitor and the sources and destinations for
the metrics and logs data:
Figure 13.1 – Azure Monitor architecture

Let's look at a simple example of how to add Activity logs into Azure Monitor. In


order to get started, we need to understand a sub-service of Azure Monitor
called Log Analytics workspaces. A Log Analytics workspace is a component of
Azure Monitor that specializes in processing and exploring log messages. You can
access Log Analytics from the Logs tab of any Azure service or the Logs tab
of Azure Monitor's menu. Log Analytics supports a powerful query language
called Kusto Query Language (KQL) that can be used to perform analysis on log
data. We will be seeing some examples of KQL in this chapter.

Nota

Log Analytics is one of the options to store logs, and it might incur additional
charges based on the storage cost and the number of Kusto queries run. You can
also choose to store logs on regular Azure storage options such as Blob and Data
Lake or use services such as Event Hubs to do real-time processing of logs.

Let's look at the steps required to log data to a Log Analytics workspace.

1. First, we need to create a new Log Analytics workspace. Just search for in the
Azure portal and click on the result. Click the + Create button on the Log
Analytics home page. You should see a screen like the one shown next. Fill in
the details such as the Resource group, Name, and Region fields for the Log
Analytics instance, and then click on Review + Create to create a new Log
Analytics workspace:Log Analytics workspaces

Figure 13.2 – Creating a Log Analytics workspace

2. Next, select the Azure Monitor service from the Azure portal and click on


the Activity log tab, as illustrated in the following screenshot:
Figure 13.3 – Azure Monitor Activity log screen

3. Click on the Diagnostics settings button and select all the logs that you want
to send to the Log Analytics workspace (the workspace you created in Step 1),
as illustrated in the following screenshot:
Figure 13.4 – Diagnostic screen setting

4. After a few minutes, you will see an table created in the Log Analytics
workspace, as shown in the following screenshot: AzureActivity
Figure 13.5 – AzureActivity table in the Log Analytics workspace

5. From now on, all the Activity logs will start getting populated into this table.
You can query the table using KQL to gain insights into the log. AzureActivity

You can learn more about sending logs to a Log Analytics workspace


here: https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/quick-
collect-activity-log-portal

Next, let's look at how to configure monitoring for Azure resources.

Configuring monitoring services


Azure Monitor is enabled as soon as we create an Azure resource. By default, the
basic metrics and logs are recorded without requiring any configuration changes
from the user side, but we can perform additional configurations such as sending
the logs to Log Analytics, as we saw in the previous section. We can configure
monitoring at multiple levels, as outlined here:

 Application monitoring—Metrics and logs about the applications that you


have written on top of Azure services.
 Operating system (OS) monitoring—OS-level metrics and logs, such as
CPU usage, memory usage, disk usage, and so on.
 Azure resource monitoring—Metrics and logs from Azure services such as
Azure Storage, Synapse Analytics, Event Hubs, and more.
 Subscription-level monitoring—Metrics and logs of Azure subscriptions,
such as how many people are using a particular account, what is the account
usage, and so on.
 Tenant-level monitoring—Metrics and logs of tenant-level services such
as Azure Active Directory (Azure AD).

For resource, subscription-level, and tenant-level monitoring, the data is mostly


already generated and we just need to enable the diagnostic setting, as shown
in Figure 13.4, to move that data into any of the following three log destinations:

 Log Analytics workspace

 Event Hubs

 Storage account

But for applications and guest OS monitoring, we will have to install the Azure


Monitor agent (AMA) or the Log Analytics agent to start collecting metrics and
logs. The AMA or Azure Monitor agent can be installed in multiple ways. Here is
an easy way to install it via virtual machine (VM) extensions on a Linux server.
You can log in to the Azure command-line interface (CLI) and run the following
command:

az vm extension set \

  --resource-group <YOUR_RESOURCE_GROUP> \

  --vm-name <VM_NAME> \

  --name OmsAgentForLinux \

  --publisher Microsoft.EnterpriseCloud.Monitoring \

  --protected-settings '{"workspaceKey":"<YOUR_WORKSPACE_KEY>"}' \

  --settings '{"workspaceId":"<YOUR_WORKSPACE_ID>"}'
CopyExplain
For other ways to install monitoring clients, please refer to the following
link: https://docs.microsoft.com/en-us/azure/azure-monitor/agents/log-analytics-
agent#installation-options.

Let's now focus on the options available for monitoring Azure resources, as this is
important from a certification perspective. Let's take the example of Azure storage.

Metrics such as Ingress, Egress, Blob Capacity, and so on that indicate the


status of operations within Azure Storage is directly available in the Metrics tab of
Azure Storage. You can filter, create new graphs, and create new alerts using all
the metrics available on this page, as shown in the following screenshot:

Figure 13.6 – Configuring metrics for Azure Storage

But if you need to find the status of the storage service itself, such as
the availability of the Blob storage account, then we will have to look at Azure
Monitor. From Azure Monitor, select Storage accounts. You should be able to see
details such as overall Transactions, Transactions Timeline, and so on, as
shown in the following screenshot:
Figure 13.7 – Storage metrics from Azure Monitor

If you click on any of the storage account links and select the Insights tab, it
shows details for Failures, Performance, Availability, and Capacity, as shown in
the following screenshot:
Figure 13.8 – Storage availability details from Azure Monitor

This is how you can use the monitoring features available within the service and
with Azure Monitor to get a complete picture of the health of your service.

Let's next learn about the custom logging options available in Azure Monitor.

Understanding custom logging options


The Custom logs option in Azure Monitor helps to collect text-based logs that are
not part of the standard logs collected by Azure Monitor, such as the system logs,
event logs in Windows, and similar ones in Linux. In order to configure custom
logs, the host machine must have the Log Analytics agent or the newer AMA
installed on it. We just saw how to install the agents in the previous section.

Once we have ensured that the agents are in place, it is a very easy process to set
up custom logs. Here are the steps:

1. In the Log Analytics workspace, select the Custom logs section and click on


the + Add custom log option, as illustrated in the following screenshot:

Figure 13.9 – Setting up a new custom log using Log Analytics

2. In the wizard that follows, upload a sample log file so that the tool can parse it
and understand the log format. Here is an example of a sample log file:
Figure 13.10 – Sample log file

3. Browse to the location of the sample file and upload it, as shown in the
following screenshot:

Figure 13.11 – Uploading a sample log file to the custom log wizard

4. Click on Next, and on the next screen, you will see your sample log lines
displayed, as shown in the following screenshot:
Figure 13.12 – Sample log lines being displayed in the wizard

5. In the next tab, enter the OS type and the path of the log files, as illustrated in
the following screenshot:

Figure 13.13 – Configuring the log paths

6. In the Details tab, enter a Custom log name value and a description for your


custom log, as shown in the following screenshot, and click Next:

Figure 13.14 – Adding a name and description to your custom log


7. Finally, in the Review + Create tab, review the entries, and click on
the Create button to create a custom log. It's as easy as that.

Note that custom logs have the following restrictions:

 Only the following pre-defined set of timestamp formats are allowed:

YYYY-MM-DD HH:MM:SS

M/D/YYYY HH:MM:SS AM/PM

Mon DD, YYYY HH:MM:SS

yyMMdd HH:mm:ss

ddMMyy HH:mm:ss

MMM d hh:mm:ss

dd/MMM/yyyy:HH:mm:ss zzz

yyyy-MM-ddTHH:mm:ssK

 No log rotations are allowed.

 Only American Standard Code for Information Interchange (ASCII)


or Unicode Transformation Format 8 (UTF-8) support is provided.
 Time zone conversion is not available for Linux.

You can learn more about custom logs


here: https://docs.microsoft.com/en-us/azure/azure-monitor/agents/data-sources-
custom-logs.

Let's next learn how to interpret Azure Monitor metrics and logs.

Interpreting Azure Monitor metrics and


logs
As we have seen in the introduction to Azure Monitoring, metrics and logs form the
two main sources of data for monitoring. Let's explore how to view, interpret, and
experiment with these two types of monitoring data.

Interpreting Azure Monitor metrics


The metrics data collected from Azure resources is usually displayed on the
overview page of the resource itself, and more details are available under
the Metrics tab. Here is an example again of how it looks for a storage account:

Figure 13.15 – Metrics data for a storage account

For each of the metrics, you can aggregate based on , , , and . The tool also
provides the flexibility to overlay with additional metrics using the Add
metric option, filter out unwanted data using the Add filter option, and so on. You
can access the data for up to 30 days using this metrics explorer. SumAvgMinMax

Let's next see how to interpret logs.

Interpreting Azure Monitor logs


We already learned how to send logs to Log Analytics. Let's now explore how to
read and experiment with logs in Log Analytics. Once you start sending logs to Log
Analytics, you will be able to see the tables for the Azure resource you configured.
In the following screenshot, you will see and tables. These tables will get populated
with logs continuously:AzureActivityStorageBlobLogs

Figure 13.16 – Log Analytics tables

Once we have the log data in the tables, we can use the KQL query language
provided by Azure Monitor to query the tables, as we do in Structured Query
Language (SQL). KQL queries can be directly typed into the query block, as
shown in the following screenshot:
Figure 13.17 – Kusto query example

A Kusto query consists of a sequence of statements that can be delimited by


semicolons. You start with a source of data such as a table and then use pipes ()
to transform the data from one step to another. For example, consider the previous
screenshot. We start with the table—just specifying the name of the table will list
the contents of the table. We then pipe that data to . Now, the 100 entries are
piped through the next statement, , which filters the rows whose latency is higher
than 20 milliseconds (ms). We then sort it in descending order and print out a
table that contains three columns: , , and , for how long the operation took.|
StorageBlobLogstake 100where ServerLatencyMs >
20TimeGeneratedOperationNameDurationMs

As you see, Kusto—or KQL—is a very intuitive language that is a mix of SQL and
Linux pipes (). Once you get a hang of it, you can generate very powerful insights
by using log data in Log Analytics.|
You can learn more about KQL here: https://docs.microsoft.com/en-us/azure/data-
explorer/kusto/query/.

Now that we have learned about configuring and interpreting metrics and logs for
Azure services, let's explore how to measure the performance of data movements
within such services. We will learn how to check the performance of data
movements while using ADF.

Measuring the performance of data


movement
ADF provides a rich set of performance metrics under its Monitoring tab. In the
following example, we have a sample Copy Data activity as part of a pipeline
called FetchDataFromBlob, which copies data from Blob storage into Azure Data
Lake Storage Gen2 (ADLS Gen2). If you click on the Pipeline runs tab under
the Monitoring tab, you will see the details of each of the pipelines. If you click on
any of the steps, you will see diagnostic details:
Figure 13.18 – Data movement performance details

This is how you can monitor the performance of data movement. You can learn
more about Copy Data monitoring
here: https://docs.microsoft.com/en-us/azure/data-factory/copy-activity-monitoring.

Let's next look at how to monitor overall pipeline performance.

Monitoring data pipeline performance


Similar to the data movement metrics we saw in the previous section, ADF
provides metrics for overall pipelines too. In the Pipeline runs page under
the Monitoring tab, if you hover over the pipeline runs, a small Consumption icon
appears, as shown in the following screenshot:
Figure 13.19 – Consumption icon in the Pipeline runs screen

If you click on that icon, ADF shows the pipeline consumption details. Here is a
sample screen:

Figure 13.20 – Pipeline resource consumption details screen

You can also get additional metrics about each of the runs from the Gantt chart
section. You can change the view from List to Gantt, as shown in the following
screenshot:
Figure 13.21 – Additional pipeline details in the Gantt chart page

Nota

ADF only maintains pipeline execution details and metrics for 45 days. If you need
to analyze the pipeline data for more than 45 days, you will have to send the data
to Log Analytics and then use Kusto queries to get the performance details.

This is how we can keep track of pipeline performance. Let's next see how to
monitor and update statistics about data.

Monitoring and updating statistics about


data across a system
Statistics is an important concept in query optimization. Generating statistics is the
process of collecting metadata about your data—such as the number of rows, the
size of tables, and so on—which can be used as additional inputs by the SQL
engine to optimize query plans. For example, if two tables have to be joined and
one table is very small, the SQL engine can use this statistical information to pick a
query plan that works best for such highly skewed tables. The Synapse SQL pool
engine uses something known as cost-based optimizers (CBOs). These
optimizers choose the least expensive query plan from a set of query plans that
can be generated for a given SQL script.

Let's look at how to create statistics for both Synapse dedicated and serverless
pools.

Creating statistics for Synapse dedicated pools


You can enable statistics in Synapse SQL dedicated pools using the following
command:

ALTER DATABASE [DW_NAME] SET AUTO_CREATE_STATISTICS ON


CopyExplain

Once is , any , , , , , or statements will automatically trigger the creation of statistics


for the columns involved in the query, if not already
present. AUTO_CREATE_STATISTICSONSELECTINSERT-SELECTCTASUPDATEDELETEEXPLAIN

Nota

Automatic creation of statistics is not available for temporary or external tables.

You can create statistics on demand using the following command:

CREATE STATISTICS [statistics_name]

    ON [schema_name].[table_name]([column_name])

    WITH SAMPLE 40 PERCENT;


CopyExplain

In the preceding example, we are using a 40% sample. If you do not provide a
sample value, the default is 20%. You can also do a full scan instead of sampling
by using the following command:
CREATE STATISTICS [statistics_name]

    ON [schema_name].[table_name]([column_name])

    WITH FULLSCAN;
CopyExplain

Ponta

As a general guideline, for less than 1 billion rows, use default sampling (20%).
With more than 1 billion rows, use sampling of 2 to 10%.

Let's next look at updating existing statistics in Synapse dedicated pools.

Updating statistics for Synapse dedicated pools


Similar to creating statistics, you can also periodically update statistics. You can
use the following command to achieve this:

UPDATE STATISTICS [schema_name].[table_name]([stat_name]);


CopyExplain

It is a good practice to update statistics after every fresh data load.

For more information on statistics in Synapse SQL pools, you can refer to the
following link:
https://docs.microsoft.com/en-us/azure/synapse-analytics/sql/develop-tables-
statistics#statistics-in-dedicated-sql-pool.

Next, let's look at how to create statistics for Synapse serverless pools.

Creating statistics for Synapse serverless pools


The concept of statistics is the same for dedicated and serverless pools. In the
case of serverless pools, the auto-creation of statistics is turned on by default for
Parquet files but not for comma-separated values (CSV) files. Since we deal
with external tables in serverless pools, we will have to create statistics for external
tables. The command for external tables is shown here:
CREATE STATISTICS [statistics_name]

ON { external_table } ( column )

    WITH

        { FULLSCAN

          | [ SAMPLE number PERCENT ] }

        , { NORECOMPUTE }
CopyExplain

Nota

Only single-column statistics are possible on external tables, while others allow
multi-column statistics.

Let's next look at how to update existing statistics for serverless pools.

Updating statistics for Synapse serverless pools


In order to update statistics for Synapse serverless pools, you will have to first drop
the existing statistics and then recreate them. The following command shows how
to drop the old table:

DROP STATISTICS [OLD_STATISTICS_TABLE_NAME]


CopyExplain

And then, we can recreate the statistics afresh by following the commands shown
here:

CREATE STATISTICS [statistics_name]

    on [NEW_STATISTICS_TABLE_NAME] (STATENAME)

    WITH FULLSCAN, NORECOMPUTE


CopyExplain

Nota
Statistics collection might cause a slight performance degradation if statistics are
missing for the columns in a query. But once statistics are generated, future
queries will be much faster.

If you would like to learn more about generating statistics, you can refer to the


following link: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql/
develop-tables-statistics#statistics-in-serverless-sql-pool.

Let's next look at how to measure query performance.

Measuring query performance


Query performance is a very interesting topic in databases and analytical engines
such as Spark and Hive. You will find tons of books and articles written on these
topics. In this section, I'll try to give an overview of how to monitor query
performance in Synapse dedicated SQL pools and Spark. In the next chapter, we
will focus on how to actually optimize the queries. I've provided links for further
reading in each section so that you can learn more about the techniques if you
wish.

For measuring the performance of any SQL-based queries, it is recommended to


set up the Transaction Processing Performance Council H or DS (TPC-
H or TPC-DS) benchmarking suites and run them on a regular basis to identify any
regressions in the platform. TPC-H and TPC-DS are industry-standard
benchmarking test suites. If you are interested in learning more about them, please
follow these links:

 You can learn more about TPC-H here: http://www.tpc.org/tpch/.


 You can learn more about TPC-DS here: http://www.tpc.org/tpcds/.

Let's next look at how we can monitor Synapse SQL pool performance.

Monitoring Synapse SQL pool performance


The Synapse SQL Metrics page itself has quite a lot of metrics that can be easily
used to identify any performance regressions. Here is a sample screenshot of the
Synapse SQL Metrics section:

Figure 13.22 – Query monitoring screen of Synapse SQL pool

The Metrics tab in Synapse SQL provides metrics for Data Warehouse


Unit (DWU) usage, memory usage, and so on, but it doesn't provide details about
query performance or query wait times. We will have to use one of the following
two approaches to get such query performance details.

Querying system tables

Synapse SQL pool provides the following system tables that can be used to


monitor query performance:

 sys.dm_pdw_exec_requests—This contains all current and recently active


requests in Azure Synapse Analytics. It contains details such as , , , , , , and
so
on.total_elapsed_timesubmit_timestart_timeend_timecommandresult_cache_hit
 sys.dm_pdw_waits—This contains details of the wait states in a query,
including locks and waits on transmission queues.
You can find details on all such system tables with monitoring and management
information here:

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-
management-views/sql-and-parallel-data-warehouse-dynamic-management-views

Next, let's look at how to get performance details using a feature called Query
Store.

Using Query Store

Azure SQL and Synapse SQL support a feature called Query Store that can be


used for both query performance monitoring and performance tuning. It is
supported in Synapse SQL pool and other flavors of SQL in Azure. Query Store is
used to store the history of queries, plans, and runtime statistics. This historical
data can then be used to aid in query optimization, identifying query regressions,
monitoring trends in resource utilization such as CPU and memory for queries,
identifying wait time patterns in query plans, and so on.

Query Store is not enabled by default for Synapse SQL pool. You can
enable Query Store using the following Transact-SQL (T-SQL) command:

ALTER DATABASE <database_name> SET QUERY_STORE = ON;


CopyExplain

Query Store in Synapse SQL stores the following three main components:

 Query details—Details such as query parameters, compilation times,


compilation counts, and so on. Here are the specific tables that contain Query
Store query details:

sys.query_store_query

sys.query_store_query_text
 Plan details—Query plan details such as the query identifier (ID), query
hash, query text, and so on. Here is the specific table that contains Query
Store plan details:

sys.query_store_plan

 Runtime statistics—Runtime details of queries such as the time taken, CPU


time, average duration, row counts, and so on. Here are the specific tables
that contain runtime statistics:

sys.query_store_runtime_stats

sys.query_store_runtime_stats_interval

Here is a sample of the table so that you have an idea of how it


looks:sys.query_store_runtime_stats

Figure 13.23 – Sample Query Store runtime statistics

Wait statistics are not yet available for Azure Synapse SQL, as of writing this book.
However, they are available in other Azure SQL flavors, such as Azure SQL
Database.

You can learn more about Query


Store here: https://docs.microsoft.com/en-us/sql/relational-databases/
performance/monitoring-performance-by-using-the-query-store.

Let's next look at the options available for monitoring the performance of Spark.
Spark query performance monitoring
Spark performance monitoring can be done directly via the Spark user
interface (UI). The Spark UI, along with the Spark History server, provides job-
specific and stage-specific metrics that can be used to determine if jobs are
slowing down compared to previous runs. The techniques we explored in Chapter
9, Designing and Developing a Batch Processing Solution, under the Debugging
Spark jobs by using the Spark UI section, will be the same for analyzing
performance regression in Spark jobs. Since we have already covered the details
in that chapter, we'll not repeat them here. Please glance through Chapter
9, Designing and Developing a Batch Processing Solution, if you have any doubts
regarding using the Spark UI.

Once slow queries are identified via the Spark UI, we can use query optimization
techniques to speed up queries. We will explore these techniques in the next
chapter.

In the meantime, let's explore another topic that is related to performance tuning:
interpreting Spark DAGs.

Interpreting a Spark DAG


A DAG is just a regular graph with nodes and edges but with no cycles or loops. In
order to understand a Spark DAG, we first have to understand where a DAG
comes into the picture during the execution of a Spark job.

When a user submits a Spark job, the Spark driver first identifies all the tasks
involved in accomplishing the job. It then figures out which of these tasks can be
run in parallel and which tasks depend on other tasks. Based on this information, it
converts the Spark job into a graph of tasks. The nodes at the same level indicate
jobs that can be run in parallel, and the nodes at different levels indicate tasks that
need to be run after the previous nodes. This graph is acyclic, as denoted by A in
DAG. This DAG is then converted into a physical execution plan. In the physical
execution plan, nodes that are at the same level are segregated into stages. Once
all the tasks and stages are complete, the Spark job is termed as completed.
Let's look at what a DAG looks like. You can access a Spark DAG from the Spark
UI. Just click on any of the job links and then click on the DAG Visualization link.

Here is a DAG for a simple word count problem:

Figure 13.24 – DAG with multiple stages

In the first stage, we see that the word count has three steps and a reduce step in
the next stage. Ignore the stage numbers, as Spark assigns consecutive numbers
for all jobs that are run in that Spark session. So, if you have run any other job
before this job, the number gets sequentially incremented. Here is some
further information about each task:

 The task corresponds to the reading of the file from the storage. textFile
 The task corresponds to the splitting of the words.flatMap
 The task corresponds to the formation of (, ) pairs.mapword1
 The task corresponds to the aggregation of all the (word, 1) pairs together to
get the sum of each distinct word.reduceByKey

You can get more details about each step by clicking on the Stage boxes. Here is
an example of a detailed view of Stage 12 from the previous screenshot:

Figure 13.25 – Detailed view of the stage

The main advantage of learning to read Spark DAGs is that they help you identify
bottlenecks in your Spark queries. You can identify how much data movement is
happening between stages (also known as data shuffle), if there are too many
sequential stages, if there are slow stages in the critical path, and so on.
You can learn more about Spark DAGs
here: https://spark.apache.org/docs/3.0.0/web-ui.html.

Now that we have learned a bit about query performance monitoring and analyzing
Spark DAGs, let's also look at how to monitor overall cluster performance.

Monitoring cluster performance


Since services such as Synapse and ADF are platform-as-a-service (PaaS)
services where you will not have explicit control over the clusters, the one place
where we can control each and every aspect of a cluster is the Azure
HDInsight service. In HDInsight, you can create your own Hadoop, Spark, Hive,
HBase, and other clusters and control every aspect of the cluster. You can use Log
Analytics to monitor cluster performance, as with the other examples we saw
earlier in the chapter. You can learn more about using Log Analytics in HDInsight
here: https://docs.microsoft.com/en-us/azure/hdinsight/hdinsight-hadoop-oms-log-
analytics-tutorial.

Apart from the Log Analytics approach, there are four main areas of the HDInsight
portal that help monitor cluster performance. Let's look at them.

Monitoring overall cluster performance


The HDInsight Ambari dashboard is the first place to check for cluster health. If
you see very high heap usage, disk usage, or network latencies, then these might
be indicators of non-optimal cluster usage. Here is a sample screenshot of
the Ambari dashboard:
Figure 13.26 – HDInsight Ambari dashboard home page

But these overall cluster details will not be enough to isolate node-level or query-
level performance issues. For this, we will have to look into the next monitoring
option available, which is a per-node monitor.

Monitoring per-node performance


From the Ambari dashboard home page, if you select the Hosts tab, you will be
able to see the per-host performance level, as illustrated in the following
screenshot:
Figure 13.27 – Per-host metrics in Ambari

If you click on each of the hostnames, it will show even more details of the host, as
shown in the following screenshot:
Figure 13.28 – Ambari per-host metrics page

If you want to drill down deeper to the query level, then we can look at Yet
Another Resource Negotiator (YARN) queues.

Monitoring YARN queue/scheduler performance


From the Resource Manager page in Ambari, select the Application
Queues option. This will show all the applications and metrics related to the
applications. On the left-hand side, you will have the Scheduler link, as illustrated
in the following screenshot. Select that to see the status of the YARN queues:
Figure 13.29 – Checking the YARN queues' status

Based on the color of the queue, you should be able to distinguish if a queue is
underused or overused.

There is one more aspect of clusters that usually results in slower performance,
and that is storage throttling.

Monitoring storage throttling


If you get a error code in your applications, you might be encountering throttling
from the storage. Either check your storage account to increase the limit or try to
distribute your application processing over multiple storage accounts to overcome
this problem.429 Too many requests

You can learn more about throttling


here: https://docs.microsoft.com/en-us/azure/azure-resource-manager/
management/request-limits-and-throttling.

Hope you got a good idea of how to monitor cluster performance. Now, let's look at
how to schedule and monitor ADF pipeline continuous integration/continuous
deployment (CI/CD).

Scheduling and monitoring pipeline tests


In Chapter 11, Managing Batches and Pipelines, we briefly introduced Azure
DevOps for version control. Azure DevOps provides another feature called Azure
Pipelines, which can be used to create CI/CD pipelines to deploy ADF. If you are
not aware of CI/CD, it is a method of continuously testing and deploying
applications to the production environment in an automated manner. In this
section, we will look into how to create, schedule, and monitor a CI/CD pipeline.

Nota

As of writing this book, Azure DevOps Pipelines support for Synapse Pipelines was
not available. It is only available for ADF.

Here are the high-level steps to create a CI/CD pipeline using Azure pipelines:

1. Select Azure DevOps from the Azure portal. On the Azure DevOps page,


select Releases under Pipelines and click the New Pipeline button. This will
take you to a new screen, shown in the following screenshot. Choose
the Empty job option:
Figure 13.30 – Azure pipeline creation wizard

2. Next, click on the Add an artifact option and update your ADF source


repository details, as shown in the following screenshot:

Figure 13.31 – Updating artifact information in Azure Pipelines

3. Once added, click on the View Tasks link on the next page, then click on


the + symbol. From the task list, choose the ARM template deployment task,
as illustrated in the following screenshot:
Figure 13.32 – Choosing Azure Pipeline tasks

4. This will bring up the Azure Resource Manager (ARM)


template configuration page, as shown in the following screenshot:

Figure 13.33 – ARM template and template parameters specification page


5. For the Template textbox, browse to the file named in your folder of
the branch.ARMTemplateForFactory.jsonADFadf_publish
6. For the Template parameters textbox, choose the file in your folder of
the branch.ARMTemplateParametersForFactory.jsonADFadf_publish
7. Once you are done filling up the details, save the page.
8. Finally, click on the Create Release button at the top to create a CI/CD
pipeline.

Now that we have a pipeline to deploy CI/CD, it can be scheduled in multiple ways.
Some examples are provided here:

 CI triggers—To trigger a pipeline when a user pushes a change to


the branchgit
 Pull request (PR) triggers—When a PR is raised or changes are submitted
to the PR
 Scheduled triggers—Time-based scheduling
 Pipeline completion triggers—Triggering based on the completion of
previous pipelines

You can learn more about implementing triggers


here: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/triggers?
view=azure-devops.

Once we have the triggers set up, the pipelines continue to get tested and
deployed. We can monitor the progress from the Releases tab of Azure DevOps.
Here is a sample image of the Pipelines screen with a summary of the pipelines
that were run:
Figure 13.34 – Release pipelines CI/CD monitoring

Azure DevOps and Pipelines are a huge topic of their own and we will not be able
to do them justice in a small section here, so I'm providing follow-up links to
understand more about ADF CI/CD, Azure pipelines, and adding tests to pipelines.

You can learn more about ADF CI/CD


here: https://docs.microsoft.com/en-us/azure/data-factory/continuous-integration-
delivery.

Resumo
This chapter introduced a lot of new technologies and techniques, and I hope you
got a grasp of them. Even though the number of technologies involved is high, the
weightage of this chapter with respect to the certification is relatively low, so you
may have noticed that I've kept the topics slightly at a higher level and have
provided further links for you to read more on the topics.

In this chapter, we started by introducing Azure Monitor and Log Analytics. We


learned how to send log data to Log Analytics, how to define custom logging
options, and how to interpret metrics and logs data. After that, we focused on
measuring the performance of data movements, pipelines, SQL queries, and Spark
queries. We also learned how to interpret Spark DAGs, before moving on to
monitoring cluster performance and cluster pipeline tests. You should now be able
to set up a monitoring solution for your data pipelines and be able to tell if your
data movement, pipeline setups, cluster setups, and query runs are performing
optimally.

In the next chapter, we will be focusing on query optimization and troubleshooting


techniques.

Chapter 14: Optimizing and


Troubleshooting Data Storage and Data
Processing
Welcome to the final chapter in the Monitoring and Optimizing Data Storage and
Data Processing section of the syllabus. The only chapter left after this is
the revision and sample questions for the certification. Congratulations on reaching
this far; you are now just a hop away from acquiring your certification.

In this chapter, we will be focusing on the optimization and troubleshooting


techniques for data storage and data processing technologies. We will start with
the topics for optimizing Spark and Synapse SQL queries using techniques such
as compacting small files, handling UDFs, data skews, shuffles, indexing, cache
management, and more. We will also look into techniques for troubleshooting
Spark and Synapse pipelines and general guidelines for optimizing any analytical
pipeline. Once you complete this chapter, you will have the knowledge to debug
performance issues or troubleshoot failures in pipelines and Spark jobs.

We will be covering the following topics in this chapter:

 Compacting small files

 Rewriting user-defined functions (UDFs)
 Handling skews in data

 Handling data spills

 Tuning shuffle partitions

 Finding shuffling in a pipeline

 Optimizing resource management

 Tuning queries by using indexers

 Tuning queries by using cache

 Otimização de pipelines para fins analíticos ou transacionais

 Optimizing pipelines for descriptive versus analytical workloads

 Troubleshooting a failed Spark job

 Troubleshooting a failed pipeline run

Requisitos técnicos
Para este capítulo, você precisará do seguinte:

 Uma conta do Azure (gratuita ou paga)

 An active Azure Data Factory or Synapse workspace

 An active Azure Databricks workspace

Vamos começar!

Compacting small files


Small files are the nightmares of big data processing systems. Analytical engines
such as Spark, Synapse SQL, and Hive, and cloud storage systems such as Blob
and ADLS Gen2, are all inherently optimized for big files. Hence, to make our
data pipelines efficient, it is better to merge or compact the small files into bigger
ones. This can be achieved in Azure using Azure Data Factory and Synapse
Pipelines. Let's look at an example using Azure Data Factory to concatenate a
bunch of small CSV files in a directory into one big file. The steps for Synapse
pipelines will be very similar:

1. From the Azure Data Factory portal, select the Copy Data activity as shown in
the following screenshot. In the Source tab, either choose an existing source
dataset or create a new one, pointing to the data storage where the small files
are present. Next, choose the Wildcard file path option for File Path type. In
the Wildcard Paths field, provide a folder path ending with a . This will ensure
that the Copy data activity considers all the files in that folder. In the following
screenshot, all the small files are present in the folder
named .*sandbox/driver/in

Figure 14.1 – Specifying the source folder using wildcards

2. Next, in the Sink tab, select your destination dataset, and, for Copy behavior,


select the Merge files option, as shown in the following screenshot:
Figure 14.2 – Selecting the Merge files copy behavior in Copy Activity of ADF

Now, if you run this pipeline, the files in the source folder (CSV files in our case)
will get merged into a file called in the destination folder that is defined in
the dataset.Output.csvDestinationCSV

You can learn more about the merge option of Copy Activity in ADF
here: https://docs.microsoft.com/en-us/azure/data-factory/connector-file-system?
tabs=data-factory#copy-activity-properties.

Another way to compact small files is the incremental copy method that we have
already explored in Chapter 4, Designing the Serving Layer, under the Designing
for incremental loading section. In this option, we incrementally update tables with
small incoming changes. This would also qualify as a compaction option as we are
incrementally merging small files into a big one via SQL tables.

There is a third way of compacting small files using Azure Databricks


Spark and Synapse Spark. Spark provides a feature called bin packing, via its
specialized storage layer called Delta Lake (note the spelling, not Data Lake).

A Delta Lake is an open source storage layer that runs on top of Data Lakes. It
enhances the Data Lake to support features including the following:
 ACID Transactions: Similar to what is available in databases and data
warehouses, Delta Lake enables ACID transactions on top of Data Lakes.
 Unified Batch, Interactive, and Streaming System: Tables defined in Delta
Lakes can serve as the source for batch processing systems, interactive
systems such as notebooks, and streaming systems.
 Updates and Deletes: This feature supports updates, deletes, and merges to
tables. This enables automatic support for Slowly Changing
Dimensions (SCDs), streaming upserts, and any other operations that
require the ability to update or merge data.

A Delta Lake engine is enabled by default in Azure Databricks and Synapse Spark.
So, all you need to do is just attach your Spark notebook to any Databricks or
Synapse Spark cluster and run the Delta commands. Let's look at some sample
commands of how to read, write, and create tables in Delta Lake:

 We can write to Azure Blob storage in format as shown. in the following code
refers to the Azure storage protocol: Azure Blob File System
[Secure]:deltaabfss
df.write.mode("overwrite").format("delta").save("abfss://path/to/delta/files")
CopyExplain
 Load data from the delta file, as shown here:
Val df: DataFrame = spark.read.format("delta").load(abfss://path/to/delta/files)
CopyExplain
 Create a table using delta, as shown here:
Spark.sql("CREATE TABLE CUSTOMER USING DELTA LOCATION

"abfss://path/to/delta/files")
CopyExplain

As you may have noticed, working with Delta Lake is very similar to working with
file formats such as Parquet, JSON, or CSV.

You can learn more about Delta Lake


here: https://docs.microsoft.com/en-us/azure/databricks/delta/.
Now let's look at how to enable bin packing. Bin packing is the feature provided by
Delta Lake to compact small files into bigger ones to improve the performance of
read queries. We can run bin packing on a folder using the command, as shown in
the following code block.OPTIMIZE

Spark.sql("OPTIMIZE delta.' abfss://path/to/delta/files'")


CopyExplain

This will merge the small files in the folder into optimal large files.

The third option is to enable Optimize by default while creating the tables using the
following properties:

 delta.autoOptimize.optimizeWrite = true
 delta.autoOptimize.autoCompact = true

Here is an example of how to use the properties while creating a table:optimize

CREATE TABLE Customer (

id INT,

name STRING,

location STRING

) TBLPROPERTIES (

delta.autoOptimize.optimizeWrite = true,

delta.autoOptimize.autoCompact = true

)
CopyExplain

You can learn more about Azure Databricks bin packing


here: https://docs.microsoft.com/en-us/azure/databricks/delta/optimizations/file-
mgmt.

Now you know three different ways to compact small files. Next, let's look at using
user-defined functions.
Rewriting user-defined functions (UDFs)
User-defined functions are custom functions that can be defined in databases
and in certain analytical and streaming engines such as Spark and Azure Stream
Analytics. An example of a UDF could be a custom function to check whether a
given value is a valid email address.

The DP-203 syllabus just mentions the topic as Rewriting user-defined functions. In
a literal sense, this is just dropping a UDF and recreating a new one, as we do for
SQL or Spark tables. However, I believe the syllabus committee might have
referred to rewriting normal repetitive scripts as UDFs to make them efficient from
a development perspective. Note that UDFs can also decrease runtime
performance if not designed correctly. Let's look at the ways to create UDFs in
SQL, Spark, and Streaming.

Writing UDFs in Synapse SQL Pool


You can create a user-defined function in Synapse SQL using the command in
Synapse SQL. Here is an example of using the command to create a simple email
validation UDF. The script checks for the email pattern and, if not valid, returns the
string :CREATE FUNCTIONCREATE FUNCTION"Not Available"

CREATE FUNCTION dbo.isValidEmail(@EMAIL VARCHAR(100))

RETURNS VARCHAR(100) AS

BEGIN     

  DECLARE @returnValue AS VARCHAR(100)

  DECLARE @EmailText VARCHAR(100)

  SET @EmailText= isnull(@EMAIL,'')

  SET @returnValue = CASE WHEN @EmailText NOT LIKE '_%@_%._%' THEN 'Not Available'

                          ELSE @EmailText

                      end

  RETURN @returnValue
END
CopyExplain

Now that we have the UDF, let's see how to use it in a query. Let's say you have a
sample table with some valid and invalid email IDs.

Figure 14.3 – Sample table with valid and invalid email IDs

We want to mark the rows with invalid email IDs as Not Available. We can
accomplish this using the following query.
Figure 14.4 – Using UDFs in a query

As expected, the rows with invalid emails got substituted with the Not


Available string.

You can learn more about UDFs in Synapse SQL


here: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-function-sql-
data-warehouse.

Next, let's look at how to write UDFs in Spark.

Writing UDFs in Spark


Spark also supports the UDF feature. In Spark, UDFs are just like any regular
functions. Here is a simple example of registering a UDF in Spark:
Figure 14.5 – Simple Spark UDF example

The sample script just doubles any values given to it. You can define UDFs to
reduce the repetition of code.

You can learn more about Spark UDFs


here: https://spark.apache.org/docs/latest/sql-ref-functions-udf-scalar.html.

Next, let's look at writing UDFs in Azure Stream Analytics.

Writing UDFs in Stream Analytics


Azure Stream Analytics supports simple UDFs via JavaScript. The UDFs are
stateless and can only return single (scalar) values. Unlike SQL and Spark
examples, in Stream Analytics, we have to register the UDF from the portal before
using it. Let's see an example:

1. Here is a UDF definition for extracting from an input JSON blob:customer.id


2. function main(arg) {

3. var customer = JSON.parse(arg);  

4. return customer.id;
}
CopyExplain
5. Next, we need to register the UDF. From the Stream Analytics job page,
select Functions under Job topology. Click on the + Add link and
select Javascript UDF, as shown in the following screenshot:

Figure 14.6 – Adding UDFs in Azure Stream Analytics

3. Once you click on the Javascript UDF option, this will reveal a screen as


shown in the following screenshot, where you can fill in the UDF code and
provide a name for the UDF in the Function alias field. Click on Save to
register the new UDF.
Figure 14.7 – Defining the UDF in the ASA portal

4. Once the UDF is registered, you can call it in your streaming queries, as


shown here:
5. SELECT UDF.getID(input) AS Id

6. INTO Stream_output

FROM Stream_input
CopyExplain

You can learn more about the Stream Analytics UDF


here: https://docs.microsoft.com/en-us/azure/stream-analytics/functions-overview.

Now you know how to define UDFs in SQL, Spark, and Streaming. Let's next look
at handling data skews.

Handling skews in data


A data skew refers to an extreme, uneven distribution of data in a dataset. Let's
take an example of the number of trips per month of our Imaginary Airport
Cab (IAC) example. Let's assume the data distribution as shown in the following
graph:
Figure 14.8 – An example of skewed data

As you can see from the graph, the trip numbers for November and December are
quite high compared to the other months. Such an uneven distribution of data is
referred to as a data skew. Now, if we were to distribute the monthly data to
individual compute nodes, the nodes that are processing the data for November
and December are going to take a lot more time than the ones processing the
other months. And if we were generating an annual report, then all the other stages
would have to wait for the November and December stages to complete. Such wait
times are inefficient for job performance. To make the processing more efficient,
we will have to find a way to assign similar amounts of processing data to each of
the compute nodes. We will explore a few options recommended by Azure for
handling such data skews.

Skews can be fixed either at the storage level or the compute level. Based on
where we fix the issue, there are different options available.

Fixing skews at the storage level


Here are a few techniques for fixing skews at the storage level:
 Find a better distribution/partition strategy that would balance the compute
time evenly. In our example of the monthly trip count, we could explore
partitioning the data into smaller chunks at the weekly level or try to partition
along a different dimension, such as ZIP codes altogether, and see whether
that helps.

 Add a second distribution key. If the primary key is not splitting the data
evenly, and if the option of moving to a new distribution key is not possible,
you could add a secondary partition key. For example, after the data is split
into months, you can further split them into, say, states of the country within
each month. That way, if you are in the USA, you get 50 more splits, which
could be more evenly distributed.

 Randomize the data and use the round-robin technique to distribute the data
evenly into partitions. If you are not able to find an optimal distribution key,
then you can resort to round-robin distribution. This will ensure that the data is
evenly distributed.

Note that it might not always be possible to recreate tables or distributions. So,
some pre-planning is very important when we first decide on the partition strategy.
However, if we end up in a situation where the partitioning strategies are not
helping, we might still have one more option left to improve our skew handling. This
option is to trust our compute engine to produce an intelligent query plan that is
aware of the data skew. Let's look at how to achieve that next.

Fixing skews at the compute level


Here are a few techniques for fixing skews at the compute level:

 Improving the query plan by enabling statistics. We have already seen how to
enable statistics in Chapter 13, Monitoring Data Storage and Data
Processing, in the Monitoring and updating statistics about data across a
system section. Once we enable statistics, query engines such as the
Synapse SQL engine, which uses a cost-based optimizer, will utilize statistics
to generate the most optimal plan based on the cost associated with each
plan. The optimizer can identify data skews and automatically apply the
appropriate optimizations in place to handle skew.
 Ignore the outlier data if not significant. This is probably the simplest of the
options, but might not be applicable to all situations. If the data that is skewed
is not very important, then you can safely ignore it.

While we are on the topic of handling skews at the compute level, Synapse Spark
has a very helpful feature that helps identify data skews in each stage of the Spark
job. If you go to the Apache Spark applications tab under the Monitoring section
of a Synapse workspace, you can see the skew details. See the following
screenshot:

Figure 14.9 – Synapse Spark notifying data skews in Spark stages

This Synapse Spark feature makes it very easy for anyone to identify skews in their
datasets.

Now you know the basic techniques for handling data skews. Let's next look at
handling data spills.
Handling data spills
Data spill refers to the process where a compute engine such as SQL or Spark,
while executing a query, is unable to hold the required data in memory and writes
(spills) to disk. This results in increased query execution time due to the expensive
disk reads and writes. Spills can occur for any of the following reasons:

 The data partition size is too big.

 The compute resource size is small, especially the memory.

 The exploded data size during merges, unions, and so on exceeds the
memory limits of the compute node.

Solutions for handling data spills would be as follows:

 Increase the compute capacity, especially the memory if possible. This will
incur higher costs, but is the easiest of the options.

 Reduce the data partition sizes, and repartition if necessary. This is more
effort-intensive as repartitioning takes time and effort. If you are not able to
afford the higher compute resources, then reducing the data partition sizes is
the best option.

 Remove skews in data. Sometimes, it is the data profile that causes the spills.
If the data is skewed, it might cause spills in the partitions with the higher data
size. We already looked at the options for handling data skews in the previous
section. You could try to use those options.

These are the general techniques for handling spills. However, to fix data spills, we
need to first identify the spills. Let's see how to identify spills in Synapse SQL and
Spark.

Identifying data spills in Synapse SQL


The primary indicator in Synapse SQL that indicates excessive data
spills is TempDB running out of space. If you notice your Synapse SQL queries
failing due to TempDB issues, it might be an indicator of a data spill.

Azure provides the following query to monitor memory usage and TempDB usage
for Synapse SQL queries. As the query is big and will not be easy for anyone to
read and reproduce from a textbook, I'm just providing the links here:

 Query to monitor SQL query memory usage: https://docs.microsoft.com/en-


us/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-manage-
monitor#monitor-memory
 Query to monitor SQL query TempDB usage: https://docs.microsoft.com/en-
us/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-manage-
monitor#monitor-tempdb

Next, let's look at how to identify spills in Spark.

Identifying data spills in Spark


Identifying spills in Spark is relatively straightforward as Spark publishes metrics for
spills. You can check the spills in the Tasks summary screen from Spark UI.

Figure 14.10 – Identifying Spark spills from the Tasks summary metrics

The last column Spill (Disk) indicates the bytes of data written to disk. That is how
we can identify data spills in Spark. Next, let's look at a Spark technique to tune
shuffle partitions.

Tuning shuffle partitions


Spark uses a technique called shuffle to move data between its executors or
nodes while performing operations such as , , , and . The shuffle operation is very
expensive as it involves the movement of data between nodes. Hence, it is usually
preferable to reduce the amount of shuffle involved in a Spark query. The number
of partition splits that Spark performs while shuffling data is determined by the
following configuration:joinuniongroupbyreduceby

spark.conf.set("spark.sql.shuffle.partitions",200)
CopyExplain

200 is the default value and you can tune it to a number that suits your query the
best. If you have too much data and too few partitions, this might result in longer
tasks. But, on the other hand, if you have too little data and too many shuffle
partitions, the overhead of shuffle tasks will degrade performance. So, you will
have to run your query multiple times with different shuffle partition numbers to
arrive at an optimum number.

You can learn more about Spark performance tuning and shuffle partitions
here: https://spark.apache.org/docs/latest/sql-performance-tuning.html.

Next, let's look at how to identify shuffles in pipelines in order to tune the queries.

Finding shuffling in a pipeline


As we learned in the previous section, shuffling data is a very expensive operation
and we should try to reduce it as much as possible. In this section, we will learn
how to identify shuffles in the query execution path for both Synapse SQL and
Spark.

Identifying shuffles in a SQL query plan


To identify shuffles, print the query plan using the statement. Here is an
example.EXPLAIN

Consider a Synapse SQL table, , as shown in the following screenshot: DimDriver


Figure 14.11 – Sample DimDriver table

Here is a sample statement:EXPLAIN

EXPLAIN WITH_RECOMMENDATIONS

SELECT

        [gender], SUM([salary]) as Totalsalary

    FROM

       dbo.DimDriver

    GROUP BY

        [gender]
CopyExplain

This will generate a plan similar to the one shown in the following screenshot. The
query prints an XML plan. I've copied and pasted the plan into a text editor to make
it easier to read the XML.
Figure 14.12 – Sample query plan from Synapse SQL

In the query plan, look for the keyword SHUFFLE_MOVE to identify the shuffle


stages. The shuffle move section will have the cost details, the number of rows
involved, the exact query causing the shuffle, and more. You can use this
information to rewrite your queries to avoid shuffling.

Ponta

Read a query plan from the bottom up to understand the plan easily.

Next, let's learn to identify shuffle stages in Spark.

Identifying shuffles in a Spark query plan


Similar to SQL, we can use the command to print the plans in Spark. Here is a
simple example to generate two sets of numbers, partition them, and then join
them. This will cause lot of data movement: EXPLAIN

val jump2Numbers = spark.range(0, 100000,2)

val jump5Numbers = spark.range(0, 200000, 5)

val ds1 = jump2Numbers.repartition(3)


val ds2 = jump5Numbers.repartition(5)

val joined = ds1.join(ds2)

joined.explain
CopyExplain

The request will print a plan similar to the sample shown as follows:joined.explain

== Physical Plan ==

BroadcastNestedLoopJoin BuildRight, Inner

:- Exchange RoundRobinPartitioning(3), [id=#216]

:  +- *(1) Range (0, 100000, step=2, splits=4)

+- BroadcastExchange IdentityBroadcastMode, [id=#219]

   +- Exchange RoundRobinPartitioning(5), [id=#218]

      +- *(2) Range (0, 200000, step=5, splits=4)


CopyExplain

Just search for the keyword to identify the shuffle stages.Exchange

Alternatively, you can identify the shuffle stage from the Spark DAG. In the
previous chapter, we saw how to view the Spark DAG from the Spark UI screen. In
the DAG, look for sections named Exchange. These are the shuffle sections. Here
is an example Spark DAG containing two Exchange stages:
Figure 14.13 – Exchange stages (Shuffle stages) in a Spark job

If there are very expensive shuffle sections, consider enabling the statistics and


checking whether the engine generates a better plan. If not, you will have to rewrite
the query to reduce the shuffles as much as possible.

Next, let's look at optimizing resource management for cloud-based analytic


pipelines.

Optimizing resource management


Optimizing resource management in this context refers to how to reduce your
billing expenses while using Azure analytic services. Here are some of the general
techniques that can help.

Optimizing Synapse SQL pools


Here are a few suggestions for Synapse dedicated SQL pools:
 Since the storage and compute are decoupled, you can pause your SQL pool
compute when not in use. This will not impact your data but will save you
some costs.

 Use the right size of compute units. In the SQL pool, the compute units are
defined in terms of Data Warehouse Units (DWUs). You can start with the
smallest DWU and then gradually increase to higher DWUs to strike the right
balance between cost and performance.
 Manually scale out or scale in the compute resources based on the load. You
can also automate the scale-out and in using Azure Functions.

You can learn more about resource management optimizations for the SQL pool
here: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/sql-data-warehouse-manage-compute-overview.

Optimizing Spark
Here are a few suggestions for Spark in both Synapse Spark and Azure Databricks
Spark:

 Choose autoscale options in Azure Databricks or Synapse Spark while


setting up the cluster. This will eliminate the need to manage the resources
manually.
 Select the auto-terminate option in Azure Databricks and Synapse Spark so
that the cluster automatically shuts down if not used for a configured period of
time.
 You can choose spot instances where available to reduce the overall cluster
cost. These are nodes that are cheap but might get pulled out if there are
higher priority jobs that need the nodes.
 Choose the right type of cluster nodes based on memory-intensive, CPU-
intensive, or network-intensive jobs. Always select nodes that have more
memory than the maximum memory required by your jobs.

These are some of the ways to optimize your resource usage. Next, let's look at
how to tune queries using indexers.
Tuning queries by using indexers
Indexing is another common optimization technology used in database systems,
data warehouses, and analytical engines such as Spark. Let's look at the indexing
options and tuning guidelines for both Synapse SQL and Spark.

Indexing in Synapse SQL


If you remember, we learned about the different types of indexing in Chapter
5, Implementing Physical Data Storage Structures, in the Implementing different
table geometries with Azure Synapse Analytics pools section. I'll recap the different
types of indexers we have along with tips for tuning Synapse SQL here again.

There are three primary types of indexing available in Synapse SQL:

 Clustered Columnstore Index: This is the default index option for Synapse


SQL. If you don't specify any indexing options, the table will automatically get
indexed using this method. Use this index for large tables > 100 million rows.
It provides very high levels of data compression and good overall
performance.
 Clustered Index: This type of indexing is better if you have very specific filter
conditions that return only a few rows, for example, if you have a clause that
returns only 100 rows from a million rows. Typically, this type of indexing is
good for < 100 million rows.WHERE
 Heap Index: This index is suitable for temporary staging tables to quickly load
data. They are also good for small lookup tables and tables with transient
data.

Ponta

If the index performance degrades over time due to incremental loads or


schema drift, try to rebuild your indexes.

You can also build a secondary non-clustered index on top of your clustered
index tables to speed up filtering.
You can learn more about indexing in Synapse SQL
here: https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/sql-data-warehouse-tables-index#index-types.

Next, let's look at the indexing options available for Spark.

Indexing in the Synapse Spark pool using


Hyperspace
Spark doesn't have any inbuilt indexing options as of the time of writing this book,
although there is an external indexing system developed by Microsoft. Microsoft
has introduced a project called Hyperspace that helps to create indexes that can
be seamlessly integrated into Spark to speed up query performance. Hyperspace
supports common data formats such as CSV, JSON, and Parquet.

Hyperspace provides a simple set of APIs that can be used to create and manage
the indexes. Let's now look at an example of how to use Hyperspace within Spark.
In this example, we load two tables, one containing trips data and another
containing driver data. We then run a join query to see how Hyperspace indexing
kicks in. Let's look at the steps involved:

1. Load your data into a DataFrame:


2. val tripsParquetPath = "abfss://path/to/trips/parquet/files"

3. val driverParquetPath = "abfss://path/to/driver/parquet/files"

4. val tripsDF: DataFrame = spark.read.parquet(tripsParquetPath)

val driverDF: DataFrame = spark.read.parquet(driverParquetPath)


CopyExplain
5. Create the Hyperspace index:
6. import com.microsoft.hyperspace._

7. import com.microsoft.hyperspace.index._

8. val hs: Hyperspace = Hyperspace()

9. hs.createIndex(tripsDF, IndexConfig("TripIndex", indexedColumns = Seq("driverId"),

includedColumns = Seq("tripId")))
hs.createIndex(driverDF, IndexConfig("DriverIndex", indexedColumns = Seq("driverId"),

includedColumns = Seq("name")))
CopyExplain
10. Enable the index and reload the DataFrames from the same file location
again:Hyperspace
11. spark.enableHyperspace

12. val tripIndexDF: DataFrame = spark.read.parquet(tripsParquetPath)

val driverIndexDF: DataFrame = spark.read.parquet(driverParquetPath)


CopyExplain
13. Run a query with :join
val filterJoin: DataFrame = tripIndexDF.join( driverIndexDF, tripIndexDF("driverId") ===

driverIndexDF("driverId")).select( tripIndexDF("tripId"), driverIndexDF("name"))


CopyExplain
14. Check how the Hyperspace index was included in your query plan by using
the command:explain
15. spark.conf.set("spark.hyperspace.explain.displayMode", "html")

hs.explain(filterJoin)(displayHTML(_))
CopyExplain
16. Here is a sample of what a query plan with the Hyperspace index would look
like:
Figure 14.14 – Query plan using Hyperspace indexes

Notice that is reading the Hyperspace index file instead of the original Parquet
file.FileScan

That is how easy it is to use Hyperspace within Spark. You can learn more about
Hyperspace indexing for Spark
here: https://docs.microsoft.com/en-us/azure/synapse-analytics/spark/apache-
spark-performance-hyperspace.

Next, let's look at how to tune queries using cache.

Tuning queries by using cache


Caching is a well-known method for improving read performance in databases.
Synapse SQL supports a feature called Result set caching. As the name implies,
this enables the results to be cached and reused if the query doesn't change. Once
result set caching is enabled, the subsequent query executions directly fetch the
results from the cache instead of recomputing the results. The result set cache is
only used under the following conditions:

 The query being considered is an exact match.

 There are no changes to the underlying data or schema.

 The user has the right set of permissions to the tables referenced in the query.

You can enable result set caching at the database level in Synapse SQL using the
following SQL statement:

ALTER DATABASE [database_name]

SET RESULT_SET_CACHING ON;


CopyExplain

You can also turn result set caching on from within a session by using the following
command:

SET RESULT_SET_CACHING { ON | OFF };


CopyExplain

Nota

The maximum size of the result set cache is 1 TB per database. Synapse SQL
automatically evicts the old data when the maximum size is reached or if the
results are invalidated due to data or schema changes.

You can learn more about result set caching here: https://docs.microsoft.com/en-


us/azure/synapse-analytics/sql-data-warehouse/performance-tuning-result-set-
caching.

Similar to Synapse SQL, Synapse Spark and Azure Databricks Spark also support
caching, but these are at much smaller scopes like caching a RDD or a Dataframe.
Spark provides methods including and , which can be used to cache intermediate
results of RDDs, DataFrames, or datasets. Here is a simple example to cache the
inputs of a DataFrame created from a CSV file:cache()persist()
df = spark.read.csv("path/to/csv/file")

cached_df = df.cache()
CopyExplain

Once you cache the DataFrame, the data is kept in memory and offers you faster
query performance. You can learn more about Spark caching options
here: https://docs.microsoft.com/en-us/azure/synapse-analytics/spark/apache-
spark-performance#use-the-cache.

Let's next look at how to optimize pipelines for both analytical and transactional
use cases.

Otimização de pipelines para fins


analíticos ou transacionais
You have surely heard the terms OLAP and OLTP if you have been working in the
data domain. Cloud data systems can be broadly classified as either Online
Transaction Processing (OLTP) or Online Analytical
Processing (OLAP) systems. Let's understand each of these at a high level.

OLTP systems
OLTP systems, as the name suggests, are built to efficiently process, store, and
query transactions. They usually have transaction data flowing into a central ACID-
compliant database. The databases contain normalized data that adheres to strict
schemas. The data sizes are usually smaller, in the range of gigabytes or
terabytes. Predominantly RDBMS-based systems, such as Azure SQL and
MySQL, are used for the main database.

OLAP systems
On the other hand, OLAP systems are usually big data systems that typically have
a warehouse or key value-based store as the central technology to perform
analytical processing. The tasks could be data exploration, generating insights
from historical data, predicting outcomes, and so on. The data in an OLAP system
arrives from various sources that don't usually adhere to any schemas or formats.
They usually contain large amounts of data in the range of terabytes, petabytes,
and above. The storage technology used is usually column-based storage such as
Azure Synapse SQL Pool, HBase, and CosmosDB Analytical storage, which have
better read performance.

We can optimize the pipelines for either OLAP or OLTP, but how do we optimize
for both? Enter Hybrid Transactional Analytical Processing (HTAP) systems.
These are a new breed of data systems that can handle both transactional and
analytical processing. They combine row- and column-based storage to provide a
hybrid functionality. These systems remove the requirement for maintaining two
sets of pipelines, one for transactional processing and the other for analytical
processing. Having the flexibility to perform both transactional and analytical
systems simultaneously opens up a new realm of opportunities, such as real-time
recommendations during transactions, real-time leaderboards, and the ability to
perform ad hoc queries without impacting the transaction systems.

Let's now look at how to build an HTAP system using Azure technologies.

Implementing HTAP using Synapse Link and


CosmosDB
HTAP is accomplished in Azure using Azure Synapse and Azure
CosmosDB via Azure Synapse Link. We already know about Azure Synapse, so
let's look into CosmosDB and Synapse Link here.

Introducing CosmosDB

CosmosDB is a fully managed globally distributed NoSQL database that supports
various API formats, including SQL, MongoDB, Cassandra, Gremlin, and Key-
Values. It is extremely fast and seamlessly scales across geographies. You can
enable multi-region writes across the globe with just a few simple clicks.
CosmosDB is suitable for use cases such as retail platforms for order processing,
cataloging, gaming applications that need low latency with the ability to handle
spurts in traffic, telemetry, and logging applications to generate quick insights.

CosmosDB internally stores the operational data in a row-based transactional


store, which is good for OLTP workloads. However, it also provides support to
enable a secondary column-based analytical store that is persisted separately from
the transaction store, which is good for analytical workloads. So, it provides the
best of both the OLTP and OLAP environments. Hence, CosmosDB is perfectly
suited for the HTAP workloads. Since the row store and column store are separate
from each other, there is no performance impact on running transactional
workloads and analytical workloads simultaneously. The data from the
transactional store is automatically synced to the columnar store in almost real
time.

Introducing Azure Synapse Link

Synapse Link, as the name suggests, links Synapse and CosmosDB to provide
cloud-native HTAP capability. We can use any of the Synapse compute engines,
be it Synapse Serverless SQL Pool or the Spark pool, to access the CosmosDB
operational data and run analytics without impacting the transactional processing
on Cosmos DB. This is significant because it completely eliminates the need for
ETL jobs, which were required earlier. Prior to the availability of Synapse Link, we
had to run ETL pipelines to get the transactional data into an analytical store such
as a data warehouse before we could run any analysis or BI on the data. Now, we
can directly query the data from the CosmosDB analytical store for BI.

Here is the Synapse link architecture reproduced from the Azure documentation:


Figure 14.15 – Azure Synapse Link for CosmosDB architecture

Nota

Accessing the Azure Cosmos DB analytics store with Azure Synapse Dedicated
SQL pool was not supported as of the time of writing this book. Only the Serverless
SQL pool was supported.

Let's now look at the steps to create a Synapse link and set up an HTAP system:

1. Let's first create a CosmosDB instance. Search for in the Azure portal and
select it. In the CosmosDB portal, select the + Create button to create a new
CosmosDB instance, as shown:CosmosDB

Figure 14.16 – Creating a new CosmosDB instance


2. When you click + Create, it will show the different API options available in
CosmosDB. Select Core SQL. Once this is selected, you will see a screen as
shown in the following screenshot. Just complete the details,
including Resource Group, Account Name, Location, and other required
fields and click on Review + create to create the new CosmosDB instance.
Figure 14.17 – CosmosDB create screen

3. Once you create the CosmosDB instance, it will prompt you to create a
container and add a sample dataset. Go ahead and add them.
4. Now, go to the Azure Synapse Link tab under Integrations. Click on
the Enable button to enable Synapse Link, as shown in the following
screenshot:

Figure 14.18 – Enabling Synapse Link in CosmosDB

5. Next, go to the Data Explorer tab, click on New Container, and complete the


details in the form that pops up as shown in the following screenshot.
Select On for the Analytical store option at the bottom of the screen. This
should set up the CosmosDB for Synapse link.
Figure 14.19 – Configuring a new container with Analytical store on

6. Now, we have to set up Synapse to talk to CosmosDB. We have to first set up


a linked service to CosmosDB from the Synapse workspace. From the
Synapse portal, go to the Manage tab and then select Linked Services. Click
on the + New button and select Azure CosmosDB (SQL API), as shown in
the following screenshot:
Figure 14.20 – Creating a linked service to Cosmos DB

7. On the screen that will pop up (not shown here), complete the details of the
CosmosDB that we created earlier and create the linked service.
8. When you click on the newly created linked service, it should show the details
of the CosmosDB linked service along with the Connection string details, as
shown in the following screenshot:
Figure 14.21 – CosmosDB linked service details

9. Now the Synapse link setup is complete. Go to the Synapse workspace, select


the Data tab, and you should now be able to see an Azure Cosmos DB entry
there. We can explore the data in CosmosDB by clicking on the container
names under the Azure Cosmos DB entry and selecting Load to DataFrame,
as shown in the following screenshot:

Figure 14.22 – Loading CosmosDB data using the Synapse link

10. You can query the CosmosDB data from the Spark notebook using OLAP, as
shown:
11. df = spark.read.format("cosmos.olap")\

12.     .option("spark.synapse.linkedService", "<Linked Service Name>")\

13.     .option("spark.cosmos.container", "<CosmosDB Container Name>")\

    .load()
CopyExplain

For OLTP queries, change to instead of .formatcosmos.oltpcosmos.olap

11. Now you know how to implement an HTAP system and query from it.

You can learn more about HTAP and the Azure Synapse link
here: https://docs.microsoft.com/en-us/azure/cosmos-db/synapse-link.
Let's next look at how to optimize pipelines for descriptive and analytics workloads.

Optimizing pipelines for descriptive


versus analytical workloads
Data analytics is categorized into four different types:

 Descriptive Analytics: The type of analytics that deals with the analysis of


what happened and when it happened. Most BI reports, such as sales reports
and trip reports, that display current and historical data points fall under this
category. The analytics tasks would usually be counts, aggregates, filters, and
so on.
 Diagnostic Analytics: This type of analytics also does the why part, along
with the what and when. Examples include Root Cause Analysis (RCA).
Apart from identifying what happened, we also delve deeper into the logs or
metrics to identify why something happened. For example, you could be
looking at why a certain cab route is having a dip in revenue, or why a
particular type of VM is failing sooner than others by looking into the load on
those machines.
 Predictive Analytics: As the name suggests, this type of analytics refers to
the prediction of what will happen. This is usually associated with machine
learning. We use historical datasets and trends to predict what could happen
next. This could be for predicting sales during holiday seasons, predicting the
peak hour rush for cabs, and so on.
 Prescriptive Analytics: This final type of analytics is the most advanced
version, where, based on predictions, the system also recommends remediate
action. For example, based on the peak sales prediction, the system might
recommend stocking up more on certain retail items or, based on the peak
hour rush, recommend moving more cabs to a particular region.

The topic of this section says optimizing pipelines for descriptive versus analytical,
but in essence, all the previously listed categories are just different types of
analytical workloads. I'm taking an educated guess that the syllabus committee
might have meant optimizing a data warehouse-centric system versus a data
pipeline-based system that can feed data into other services, such as machine
learning.

Descriptive analytics almost always includes a data warehouse system such as a


Synapse SQL pool to host the final data that can be served to BI tools. And
analytics in a generic sense usually involves big data analytical compute engines
such as Spark, Hive, and Flink to process large amounts of data from a variety of
sources. The data generated would then be used by various systems, including BI,
machine learning, and ad hoc queries. So, let's look at the optimization techniques
for pipelines involving data warehouses such as Synapse SQL and technologies
such as Spark.

Common optimizations for descriptive and


analytical pipelines
The optimization techniques we have learned throughout this book will all be
applicable to both descriptive and general analytical pipelines. For example, the
following techniques are common irrespective of SQL Pool-centric (descriptive) or
Spark-centric (analytical) approaches.

Optimizations at the storage level:

 Divide the data clearly into zones: Raw, Transformation, and Serving zones.

 Define a good directory structure, organized around dates.

 Partition data based on access to different directories and different storage


tiers.

 Choose the right data format – Parquet with a Snappy comparison works well
for Spark.

 Configure the data life cycle, purging old data or moving it to archive tiers.

Optimizations at the compute level:

 Use caching.
 Use indexing when available.

 Handle data spills.

 Handle data skews.

 Tune your queries by reading the query plans.

Next, let's look at the specific optimizations for descriptive and analytical pipelines.

Specific optimizations for descriptive and analytical


pipelines
For Synapse SQL, consider the following optimizations:

 Maintain statistics to improve performance while using Synapse SQL's cost-


based optimizer.

 Use PolyBase to load data faster.

 Use hash distribution for large tables.

 Use temporary heap tables for transient data.

 Do not over-partition as Synapse SQL already partitions the data into 60 sub-
partitions.

 Minimize transaction sizes.

 Reduce query result sizes.

 Use the Result set cache if necessary.

 Use the smallest possible column size.

 Use a larger resource class (larger memory size) to improve query


performance.

 Use a smaller resource class (smaller memory size) to increase concurrency.

You can learn more about optimizing a Synapse SQL pipeline here:


 https://docs.microsoft.com/en-us/azure/synapse-analytics/sql/best-practices-
dedicated-sql-pool.
 https://docs.microsoft.com/en-us/azure/synapse-analytics/sql-data-
warehouse/cheat-sheet#index-your-table.

And for Spark, consider the following optimizations:

 Choose the right data abstraction – DataFrames and datasets usually work
better than RDDs.

 Choose the right data format – Parquet with a Snappy compression usually
works fine for the majority of Spark use cases.

 Use cache – either the inbuilt ones in Spark, such as and , or external caching
libraries..cache().persist()
 Use indexers – use Hyperspace to speed up queries.

 Tune your queries – reduce shuffles in the query plan, choose the right kind of
merges, and so on.

 Optimize job execution – choosing the right container sizes so that the jobs
don't run out of memory. This can usually be done by observing the logs for
the details of previous runs.

You can learn more about optimizing Spark pipelines


here: https://docs.microsoft.com/en-us/azure/synapse-analytics/spark/apache-
spark-performance.

Let's next look at how to troubleshoot a failed Spark job.

Troubleshooting a failed Spark job


There are two aspects to troubleshooting a failed Spark job in a cloud environment:
environmental issues and job issues. Let's look at both of these factors in detail.

Debugging environmental issues


Here are some of the steps involved in checking environmental issues:

1. Check the health of Azure services in the region where your Spark clusters
are running by using this link: https://status.azure.com/en-us/status.
2. Next, check whether your Spark cluster itself is fine. You can do this for your
HDInsight clusters by checking the Ambari home page. We saw how to check
Ambari for the status in Chapter 13, Monitoring Data Storage and Data
Processing, in the Monitoring overall cluster performance section. Here is the
Ambari screen home page again for your reference:

Figure 14.23 – Ambari home page showing the status of the cluster

3. Check to see whether any service is down or whether any of the resources are
running hot with metrics, such as a very high CPU or very high memory
usage.

Next, let's look at how to debug job issues.


Debugging job issues
If the cloud environment and the Spark clusters are healthy, we have to next check
for job-specific issues. There are three main log files you need to check for any job-
related issues:

 Driver Logs: You can access the driver log from the Compute tab, as shown,
in Azure Databricks:

Figure 14.24 – Driver Logs location

 Tasks logs: You can access the task logs from the Stages tab of Spark UI.


Figure 14.25 – Task log location in the Spark UI

 Executors log: The executor logs are also available from both the Stages tab,


as shown in the preceding screenshot, and from the Executors tab, as shown
in the following screenshot:

Figure 14.26 – Executor log location in the Spark UI


Start with the driver log, and then proceed to the task logs, followed by the
executor logs, to identify any errors or warnings that might be causing the job to
fail.

You can learn more about debugging Spark jobs


here: https://docs.microsoft.com/en-us/azure/hdinsight/spark/apache-troubleshoot-
spark.

Next, let's look at how to troubleshoot a failed pipeline run.

Troubleshooting a failed pipeline run


Azure Data Factory and Synapse pipelines provide detailed error messages when
pipelines fail. Here are three easy steps to debugging a failed pipeline:

 Check Datasets: Click on Linked Services and then click on the Test


connection link to ensure that the linked services are working fine and that
nothing has changed on the source. Here is an example of how to use Test
connection on the Edit linked service page.
Figure 14.27 – Using Test connection for linked services

 Use data previews to check your transformations: Turn the Data flow


debug mode on and check the data previews for each of your pipeline
activities, starting from the data source. This will help narrow down the issue.
Here is an example of how to use Data preview:

Figure 14.28 – Using the Data preview option to see whether the data is getting
populated correctly

 If the issues persist, run the pipeline and click on the error message tag to see
what the error code is. Here is an example:
Figure 14.29 – Troubleshooting from the pipeline monitoring page in ADF

The following troubleshooting guide has the details of all the error codes and
recommendations on how to fix the
issues: https://docs.microsoft.com/en-us/azure/data-factory/data-factory-
troubleshoot-guide.

Here is an example of a sample error code and recommendation from the Azure
Data Factory troubleshooting guide:

Error code: 2105

Message: An invalid json is provided for property '%propertyName;'. Encountered an error while

trying to parse: '%message;'.

Cause: The value for the property is invalid or isn't in the expected format.

Recommendation: Refer to the documentation for the property and verify that the value provided

includes the correct format and type.


CopyExplain

Debugging is a skill that comes with practice. Use the guidelines in this chapter as
a starting point and practice with as many examples as possible to become an
expert.

With that, we have come to the end of this chapter.

Resumo
Like the last chapter, this chapter also introduced a lot of new concepts. Some of
these concepts will take a long time to master, such as Spark
debugging, optimizing shuffle partitions, and identifying and reducing data
spills. These topics could be separate books on their own. I've tried my best to
give you an overview of these topics with follow-up links. Please go through the
links to learn more about them.

Let's recap what we learned in this chapter. We started with data compaction as
small files are very inefficient in big data analytics. We then learned about UDFs,
and how to handle data skews and data spills in both SQL and Spark. We then
explored shuffle partitions in Spark. We learned about using indexers and cache to
speed up our query performance. We also learned about HTAP, which was a new
concept that merges OLAP and OLTP processing. We then explored the general
resource management tips for descriptive and analytical platforms. And finally, we
wrapped things up by looking at the guidelines for debugging Spark jobs and
pipeline failures.

You should now know the different optimizations and query tuning techniques. This
should help you with both certification and becoming a good Azure data engineer.

You have now completed all the topics listed in the syllabus for DP-203
certification. Congratulations to you for your persistence in reaching the end!

The next chapter will cover sample questions to help you prepare for the exam.
Chapter 15: Sample Questions with
Solutions
This is the last chapter of the book – hurray! This chapter will provide sample
questions and tips for attending the DP-203 certification. Once you complete this
chapter, you should be familiar with the types of questions that appear in the
certification along with some techniques for handling them. After you have read this
chapter, I'd recommend you go back and read all the important concepts again and
look carefully at the notes, tips, and Further reading sections provided in the
previous chapters.

This chapter will cover the following topics:

 Exploring the question formats

 Sample questions from the Design and Implement Data Storage section


 Sample questions from the Design and Develop Data Processing section
 Sample questions from the Design and Implement Data Security section
 Sample questions from the Monitor and Optimize Data Storage and Data
Processing section

Vamos começar!

Exploring the question formats


Azure certification teams regularly update their questions and question formats, so
there is no fixed pattern, but the following types of questions are common:

 Case study-based questions

 Scenario-based questions

 Direct questions

 Ordering sequence questions


 Code segment questions

There could be about 40-60 questions and the questions are usually distributed
according to the weightage given to the topics in the syllabus.

 Design and Implement Data Storage (40-45%)

 Design and Develop Data Processing (25-30%)

 Design and Implement Data Security (10-15%)

 Monitor and Optimize Data Storage and Data Processing (10-15%)

The sequence of the questions will be random. Let's look at an example for each of
the common types of questions.

Case study-based questions


Let's start with a data lake case study question.

Case study – data lake


In a case study question, a use case will be described in detail with multiple inputs
such as business requirements and technical requirements. You will have to
carefully read the question and understand the requirements before answering the
question.

Nota

In the actual exam, the title of the question will NOT have a category such as Data
Lake. I've just added it here so that it is easy for you to locate the questions
directly from the table of contents. This is true for all the question headings in this
chapter.

Background
Let's assume you are a data architect in a retail company that has both online and
bricks and mortar outlets all over the world. You have been asked to design their
data processing solution. The leadership team wants to see a unified dashboard of
daily, monthly, and yearly revenue reports in a graphical format, from across all
their geographic locations and the online store.

The company has analysts who are SQL experts.

For simplicity, let's assume that the retail outlets are in friendly countries, so there
is no limitation in terms of moving data across the countries.

Technical details

The online transaction data gets collected into Azure SQL instances that are
geographically spread out. The overall size is about 10 GB per day.

The bricks and mortar point of sale transactions are getting collected in local
country-specific SQL Server databases with different schemas. The size is about
20 GB per day.

The store details are stored as JSON files in Azure Data Lake Gen2.

The inventory data is available as CSV files in Azure Data Lake Gen2. The size is
about 500 MB per day.

Ponta

The trick is to identify key terminologies such as file formats, streaming, or batching
(based on the frequency of reports), the size of the data, security restrictions – if
any, and technologies to be used, such as SQL in this case (as the analysts are
SQL experts). Once we have all this data, the decision-making process becomes a
bit simpler.

Question 1

Choose the right storage solution to collect and store all the different types of data.
[Options: Azure Synapse SQL pool, Azure Data Lake Gen2, Azure Files, Event
Hubs]

Solution

Azure Data Lake Gen2

Explanation

 ADLS Gen2 can handle multiple different types of formats and can store
petabytes of data. Hence, it would suit our use case.

 Azure Synapse SQL pool is for storing processed data in SQL tables.

 Azure Files are file sharing storage services that can be accessed via Server


Message Block (SMB) or Network File System (NFS) protocols. They are
used to share application settings, as extended on-premises file servers, and
so on.
 Event Hubs is used for streaming real-time events and not an actual analytical
data store.

Question 2

Choose the mechanism to copy data over into your common storage.

[Choices: PolyBase, Azure Data Factory, Azure Databricks, Azure Stream


Analytics]

Solution

Azure Data Factory

Explanation

 ADF provides connectors to read data from a huge variety of sources, both on


the cloud and on-premises. Hence, it will be a good fit for this situation.

 PolyBase is mostly used for converting data from different formats to standard
SQL table formats and copying them into Synapse SQL pool.
 Azure Databricks can be used for batch and Spark stream processing, not for
storing large volumes of data.

 Azure Stream Analytics is used for stream processing, not for storing large
volumes of data.

Question 3

Choose storage to store the daily, monthly, and yearly data for the analysts to
query and generate reports using SQL.

[Choices: Azure Databricks, Azure Queues, Synapse SQL pool, Azure Data
Factory]

Solution

Synapse SQL pool

Explanation

 Synapse SQL pool is a data warehouse solution that perfectly fits the
requirements for storing data to generate reports and find insights. The daily,
monthly, and yearly data is usually the data that is cleaned, filtered, joined,
aggregated from various sources, and stored in pre-defined schemas for easy
analysis. Since Synapse SQL pools are natively SQL-based, it works well for
analysts of the company who are SQL experts.

 Azure Databricks is used for batch and stream processing, not for storing
large volumes of data. Hence, it wouldn't fit the bill for our use case.

 Azure Queues storage is a messaging service that can hold millions of


messages and that can be processed asynchronously. Hence, it wouldn't fit
the bill for our use case.

 Azure Data Factory is used to copy/move data, do basic transformations, and


orchestrate pipelines. It cannot be used for storing data.

Ponta
If you find terminologies that you are not aware of, use the principle of
negation to find the most suitable answer. In this case, if you didn't know what
Azure Queues does, you can try to establish whether any of the other options
is a good solution and then go with it. Or, if you are not sure, try to eliminate
the obviously wrong answers and take an educated guess.

Question 4

Visualize the insights generated in a graphical format.

[Choices: Azure Data Factory, Synapse Serverless SQL pool, Power BI, Azure
Databricks]

Solution

Power BI

Explanation

 Power BI can generate insights from various sources of data, such as


Synapse SQL pools, Azure Stream Analytics, Azure SQL, and Cosmos DB. It
provides a very rich set of tools to graphically display the data.

 ADF provides connectors to read data from a huge variety of sources and
orchestration support. Hence, it will not be a good fit for this situation.

 Synapse SQL pool is a data warehouse solution that can be used to process
data and store it, to be used by business intelligence tools such as Power BI.

 Azure Databricks can be used for visualizing data patterns, but not usually for
generating and visualizing graphical insights.

These were examples of case study-based questions. Let's next look at scenario-
based questions.

Scenario-based questions
In a scenario-based question, you will be presented with a scenario and asked to
derive a solution to the problem in the scenario. Let's look at an example.

Shared access signature


You are the security engineer for a company. One of the developers has
mistakenly checked in the storage access key as part of a test file into a Git
repository. You are planning to immediately regenerate new access keys. Which of
the following existing authorization keys will have to be regenerated? [Select all
applicable answers]

1. AAD security groups


2. User delegation shared access signature keys
3. Account shared access signature keys
4. Service shared access signature keys

Solution

1. Account shared access signature keys


2. Service shared access signature keys

Explanation

 Both account shared access signature keys and service shared access
signature keys are signed using the storage access keys. So, if the access
keys are regenerated, it will invalidate the account shared access
signature (SAS) and service SAS keys.
 AAD security groups are independent of the storage access keys, and so will
not be impacted.

 User delegation shared access signature keys are signed using AAD
credentials, so they will also not be impacted.

Let's next look at direct questions.


Direct questions
These are just simple direct questions. Let's look at an example.

ADF transformation
You are designing the data processing pipeline for a cab company using Azure
Data Factory. The company has two fleets of cars: electric and gas. You have to
branch the pipeline based on the type of car. Which transformation would you use?

[Options: Join, Split, Conditional Split, New Branch]

Solution

Conditional Split

Explanation

 Conditional Split – This is used to split the input data into multiple streams
based on a condition. In our use case, the condition could be the type of car.
 Join – Used to merge two inputs into one based on a condition, so will not
work for our use case.Join
 Split – There is no such transformation in ADF.
 New Branch – To replicate the current source as is to perform a different set
of transformations on the same source of data. Hence, this will also not work
for our use case.

These are usually straightforward questions and there might not be any twists.
Let's next look at an ordering sequence question.

Ordering sequence questions


In this type of question, you will be given a bunch of statements in a random order.
You will have to choose the right set of instructions and arrange them in the right
sequential order. Let's look at an example.

ASA setup steps


You have been appointed as a technical consultant for the Department of Motor
Vehicles (DMV). You have been asked to analyze the data coming in from sensors
on roads to identify traffic congestion in real time and display it on a graphical
dashboard. Since the DMV doesn't have many technical people, they expect the
solution to be code-free or with minimal code. You have decided to go ahead with
Event Hubs, ASA, and a Power BI-based solution.

Here are the options you have to set up the system. Arrange the five actions that
you should perform in the right sequence.

 A – Configure Power BI as the output for the ASA job.

 B – Start the ASA job.

 C – Build the Power BI dashboard to visualize the traffic data on a map.

 D – Configure Azure Blob storage to store the data coming in from the
sensors.

 E – Build the ASA query to aggregate the data based on locality.

 F – Copy the aggregated data into Synapse SQL pool.

 G – Configure Event Hubs as the input for the ASA job.

Solution

 G – Configure Event Hubs as the input for the ASA job.

 A – Configure Power BI as the output for the ASA job.

 E – Build the ASA query to aggregate the data based on locality.

 B – Start the ASA job.


 C – Build the Power BI dashboard to visualize the traffic data on a map.

Explanation

The incorrect options are as follows:

 D – Configure Azure Blob storage to store the data coming in from the
sensors.

We don't need to configure Blob storage as Event Hubs can stream the data
directly to ASA. There was no requirement to store the events for any long-term
processing.

 F – Copy the aggregated data into Synapse SQL pool.

ASA can directly publish the data to Power BI. Hence, we don't need the Synapse
SQL pool in between.

Ponta

Ordering questions are tricky because unless you have tried the process yourself,
you might not remember the sequence in which you will have to perform the tasks.
So, do try out the concepts hands-on at least once before your certification.

Let's next look at coding questions.

Code segment questions


In code questions, you might be asked to fill in the missing sections of the code or
to identify the right set of the code from multiple choices. Let's look at an example.

Column security
Let's assume that you have a table with sensitive information in it. You want to hide
the Social Security Number (SSN) details from . Here is the table
definition:CustomerLowPrivUser
CREATE TABLE Customer

   CustomerID VARCHAR (20),

   Name VARCHAR (200),

   SSN VARCHAR (9) NOT NULL,

   Phone VARCHAR (12) NULL,

);
CopyExplain

Complete the following code snippet:

GRANT ___________ Customer (CustomerID, Name, Phone) TO LowPrivUser';


CopyExplain

[ Options: , , , ALTER ONSELECT ONMASK ONENCRYPT ON]

Solution

SELECT ON

Explanation

 SELECT ON – Gives permission to run the queries only on , , and , which is
what is required in this use case.SELECTCustomerIDNamePhone
 ALTER ON – Gives permission to change the table itself – this is not what is
asked in the question.
 MASK ON – Invalid syntax; there is no syntax called .MASK ON
 ENCRYPT ON – Invalid syntax; there is no syntax called .ENCRYPT ON

Ponta

Coding questions also need practice. So please try out simple code snippets
from the book and Azure websites before your certification.
The preceding five examples cover the most common types of questions in Azure
certification.

Nota

During the exam, except possibly for the case study questions, the title of the
question will not specify whether it is a scenario, direct, ordering-based, or code-
based problem. Once you read the question, it will usually be obvious to you.

Let's now look at a few more sample questions from each of the sections in the
syllabus, starting with data storage.

Sample questions from the Design and


Implement Data Storage section
Let's look at a random mix of questions from data storage-related topics.

Case study – data lake


The case study questions will have a detailed description of the case followed by
the questions.

Background

You have been hired to build a ticket scanning system for a country's railways
department. Millions of passengers will be traveling on the trains every day. It has
been observed that some passengers misuse their tickets by sharing them with
others or using them for more rides than allowed. The railway officers want a real-
time system to track such fraud occurrences.

Technical details

 A ticket is considered fraudulent it if is used more than 10 times a day.


 Build a real-time alerting system to generate alerts whenever such fraud
happens.

 Generate a monthly fraud report of the number of incidents and the train
stations where it happens.

You need to build a data pipeline. Recommend the services that can be used to
build such a fraud detection system.

Question 1

You recommend the following components to be used:

 Azure Blob storage to consume the data

 Azure Stream Analytics to process the fraud alerts

 Power BI to display the monthly report

[Options: Correct/ Incorrect]

Solution

Incorrect

Explanation

We cannot use Azure Blob storage to consume real-time data. It is used to store
different formats of data for analytical processing or long-term storage.

Question 2

You recommend a system to use:

 IOT Hub to consume the data

 Azure Stream Analytics to process the fraud alerts

 Azure Databricks to store the monthly data and generate the reports

 Power BI to display the monthly report


[Options: Correct/ Incorrect]

Solution

Incorrect

Explanation

We cannot use Azure Databricks to store the monthly data. It is not a storage


service; it is a compute service.

Question 3

You recommend a system to use:

 IOT Hub to consume the data

 Azure Stream Analytics to process the fraud alerts

 Azure Synapse SQL pool to store the monthly data and generate the reports

 Power BI to display the monthly report

[Options: Correct/ Incorrect]

Solution

Correct

Explanation

IOT Hub can be used to consume real-time data and feed it to Azure Stream
Analytics. Stream Analytics can perform real-time fraud detection and store the
aggregated results in Synapse SQL pool. Synapse SQL pool can store petabytes
of data for longer durations to generate reports. Power BI can graphically display
both the real-time alerts and monthly reports. So, this is the right set of options.

Let's look at a data visualization question next.

Data visualization
You have data from various data sources in JSON and CSV formats that has been
copied over into Azure Data Lake Gen2. You need to graphically visualize the data.
What tool would you use?

 Power BI

 Azure Databricks/Synapse Spark

 Azure Data Factory

 Azure Storage Explorer

Solution

Azure Databricks/Synapse Spark

Explanation

 Azure Databricks Spark or Synapse Spark provides graphing options that can


be used to sample and visualize data.

 Power BI is not used to visualize raw data. It is used to visualize insights


derived from processed data.

 Azure Data Factory provides options to preview the data, but not many options
for graphically visualizing it.

 Storage Explorer helps explore the filesystem but doesn't have the ability to
visualize the data graphically.

Ponta

Look for the nuances in the question. The moment we see graphically


visualize, we tend to select Power BI. But Azure Databricks Spark has built-in
graphing tools that can help visualize the data.

Power BI is used to build and display insights from processed data.

Let's look at a data partition question next.


Data partitioning
You have a table as follows in Azure SQL:

CREATE TABLE Books {

   BookID VARCHAR(20) NOT NULL,

   CategoryID VARCHAR (20) NOT NULL,

   BookName VARCHAR (100),

   AuthorID VARCHAR (20),

   ISBN VARCHAR (40)

}
CopyExplain

Assume there are 100 million entries in this table. has about 25 entries and 60% of
the books align to about 20 categories. You need to optimize the performance of
this table for queries that aggregate on . What partitioning technique would you use
and what key would you choose?CategoryIDCategoryID

 Vertical partitioning with CategoryID


 Horizontal partitioning with BookID
 Vertical partitioning with BookID
 Horizontal partitioning with CategoryID

Solution

Horizontal partitioning with CategoryID

Explanation

 Horizontal partitioning with is the right choice as we need to horizontally


partition (shard) the data based on , which has a fairly good distribution. This
can speed up the processing by distributing the data evenly across the
partitions.CategoryIDcategoryID
 Vertical partitioning with – Splitting the table vertically will not optimize as we
will have to scan through the entire database to aggregate the categories.
Vertical partitioning is effective when we need to speed up queries only based
on a few columns.CategoryID
 Horizontal partitioning with – Horizontal partitioning (sharding) is fine, but the
key we are looking to optimize is the categories. So will not create the optimal
partitions.BookIDBookID
 Vertical partitioning with – For the same reason as vertical partitioning with ,
vertical partitions will not be efficient as we need to access all the
rows.BookIDCategoryID

Let's look at a Synapse SQL pool design question next.

Synapse SQL pool table design – 1


You are the architect of a cab company. You are designing the schema to store trip
information. You have a large fact table that has a billion rows. You have
dimension tables in the range of 500–600 MB and you have daily car health data in
the range of 50 GB. The car health data needs to be loaded into a staging table as
quickly as possible. What distributions would you choose for each of these types of
data?

 A – Fact table

 B – Dimension tables

 C – Staging table

[Options: Round Robin, Hash, Replicated]

Solution

 A – Fact table – Hash

 B – Dimension tables – Replicated

 C – Staging table – Round Robin


Explanation

 Replicated – Use replication to copy small tables to all the nodes so that the
processing is much faster without much network traffic.
 Hash – Use hash distribution for fact tables that contain millions or billions of
rows/are several GBs in size. For small tables, hash distribution will not be
very performant.
 Round Robin – Use round robin for staging tables where you want to quickly
load the data.

Let's look at another Synapse SQL pool design question next.

Synapse SQL pool table design – 2


You are a data engineer for an online bookstore. The bookstore processes
hundreds of millions of transactions every month. It has a Catalog table of about
100 MB. Choose the optimal distribution for the Catalog table and complete the
following script:

CREATE TABLE Catalogue (

   BookID VARCHAR 50,

   BookName VARCHAR 100,

   ISBN: VARCHAR 100,

   FORMAT: VARCHAR 20

) WITH

   CLUSTERED COLUMNSTORE INDEX,

   DISTRIBUTION = ___________

)
CopyExplain

[Options: , , , ROUND-ROBINREPLICATEHASHPARTITION]

Solution
Replicate

Explanation

 Replicate distribution copies the data to all the compute nodes. Hence, the
processing will be much faster in the case of smaller tables.

 Hash – Use hash distribution for fact tables that contain millions of rows or are
several GBs in size. For small tables, hash distribution will not be very
performant.
 Round Robin – Use round robin for staging tables where you want to quickly
load the data.
 Partition – This is used for data partitioning, which is not our use case.

Let's look at a slowly changing dimension question next.

Slowly changing dimensions


Identify the type of SCD by looking at this table definition:

CREATE TABLE DimCustomer (

   SurrogateID IDENTITY,

   CustomerID VARCHAR(20),

   Name VARCHAR(100),

   Email VARCHAR(100),

   StartDate DATE,

   EndDate DATE,

   IsActive INT

)
CopyExplain

[Options: SCD Type 1, SCD Type 2, SCD Type 3]


Solution

SCD Type 2

Explanation

SCD Type 2 keeps track of all the previous records using the , , and, optionally,
an or a field.StartDateEndDateIsActiveVersionNumber

Let's look at a storage tier-based question next.

Storage tiers
You are a data engineer working with an ad serving company. There are three
types of data the company wants to store in Azure Blob storage. Select the storage
tiers that you should recommend for each of the following scenarios.

 A – Auditing data for the last 5 years for yearly financial reporting

 B – Data to generate monthly customer expenditure reports

 C – Media files to be displayed in online ads

[Options: Hot, Cold, Archive]

Solution

A – Archive

B – Cold

C – Hot

Explanation
 Auditing data is accessed rarely and the use case says yearly financial
reporting. So, this is a good candidate for the archive tier. The archive tier
requires the data to be stored for at least 180 days.

 Monthly customer expenditure data is not used frequently, so it is a good


candidate for cold storage. Cold storage requires the data to be stored for at
least 30 days.

 Media files to be displayed in ads will be used every time the ad is displayed.
Hence, this needs to be on the hot tier.

Let's look at a disaster recovery question next.

Disaster recovery
You work in a stock trading company that stores most of its data on ADLS Gen2
and the company wants to ensure that the business continues uninterrupted even
when an entire data center goes down. Select the disaster recovery option(s) that
you should choose for such a requirement:

 Geo-Redundant Storage (GRS)
 Zone-Redundant Storage (ZRS)
 Geo-Zone-Redundant Storage (GZRS)
 Locally Redundant Storage (LRS)
 Geo-Replication

Solution

 Geo-Redundant Storage (GRS) or Geo-Zone-Redundant Storage (GZRS)

Explanation

 Both Geo-Redundant Storage (GRS) and Geo-Zone-Redundant


Storage (GZRS) can ensure that the data will be available even if entire data
centers or regions go down. The difference between GRS and GZRS is that in
GRS, the data is synchronously copied three times within the primary region
using the LRS technique, but in GZRS, the data is synchronously copied three
times within the primary region using ZRS. With GRS and GZRS, the data in
the secondary region will not be available for simultaneous read or write
access. If you need simultaneous read access in the secondary regions, you
could use the Read-Access – Geo-Redundant Storage (RA-GRS) or Read-
Access Geo-Zone-Redundant Storage (RA-GZRS) options.
 LRS – LRS provides only local redundancy, but doesn't guarantee data
availability if entire data centers or regions go down.

 ZRS – ZRS provides zone-level redundancy but doesn't hold up if the entire


data center or region goes down.

 Geo-replication – This is an Azure SQL replication feature that replicates the


entire SQL server to another region and provides read-only access in the
secondary region.

Tip

If you notice any options that you are not aware of, don't panic. Just look at
the ones you are aware of and check whether any of those could be the
answer. For example, in the preceding question, if you had not read about
geo-replication, it would have still been okay because the answer was among
the choices that you already knew.

Synapse SQL external tables


Fill in the missing code segment to read Parquet data from an ADLS Gen2 location
into Synapse Serverless SQL:

IF NOT EXISTS (SELECT * FROM sys.external_file_formats

WHERE name = 'SynapseParquetFormat')

    CREATE ____________ [SynapseParquetFormat]

    WITH (FORMAT_TYPE = PARQUET)

IF NOT EXISTS (SELECT * FROM sys.external_data_sources


WHERE name = 'sample_acct')

    CREATE _____________ [sample_acct]

    WITH (

        LOCATION   = 'https://sample_acct.dfs.core.windows.net/users',

    )

CREATE ______________ TripsExtTable (

    [TripID] varchar(50),

    [DriverID] varchar(50),

    . . .

    )

    WITH (

    LOCATION = 'path/to/*.parquet',

    DATA_SOURCE = [sample_acct],

    FILE_FORMAT = [SynapseParquetFormat]

    )

GO
CopyExplain

[Options: , , , , , TABLEEXTERNAL TABLEEXTERNAL FILE FORMATEXTERNAL DATA


SOURCEVIEWFUNCTION]

You can reuse the options provided above for more than one blank if needed.

Solution

EXTERNAL FILE FORMAT, , EXTERNAL DATA SOURCEEXTERNAL TABLE

Explanation

 The correct keywords are , , and in the order in which they appear in the
question.EXTERNAL FILE FORMATEXTERNAL DATA SOURCEEXTERNAL TABLE
 You cannot use as this is not an internal table. We are reading external
Parquet data as an external table.TABLE
 You cannot use as views are logical projections of existing tables. VIEW
 You cannot use as this is not a UDF.FUNCTION

Let's next look at some sample questions from the data processing section.

Sample questions from the Design and


Develop Data Processing section
This section focuses on the data processing section of the syllabus. Let's start with
a data lake-based question.

Data lake design


You are working in a marketing firm. The firm provides social media sentiment
analysis to its customers. It captures data from various social media websites,
Twitter feeds, product reviews, and other online forums.

Technical requirements:

 The input data includes files in CSV, JSON, image, video, and plain text
formats.

 The data is expected to have inconsistencies such as duplicate entries and


missing fields.

 The overall data size would be about 5 petabytes every month.

 The engineering team are experts in Scala and Python and would like a
Notebook experience.

 Engineers must be able to visualize the data for debugging purposes.

 The reports have to be generated on a daily basis.


 The reports should have charts with the ability to filter and sort data directly in
the reports.

You need to build a data pipeline to accomplish the preceding requirements. What
are the components you would select for the following zones of your data lake?

Landing zone:

[Options: Azure Data Lake Gen2, Azure Blob storage, Azure Synapse SQL, Azure
Data Factory]

Transformation zone:

[Options: Synapse SQL pool, Azure Databricks Spark, Azure Stream Analytics]

Serving zone:

[Options: Synapse SQL pool, Azure Data Lake Gen2, Azure Stream Analytics]

Reporting:

[Azure Databricks Spark, Power BI, the Azure portal]

Solution

 Landing zone: Azure Blob storage


 Transformation zone: Azure Databricks Spark
 Serving zone: Synapse SQL pool
 Reporting: Power BI

Explanation

Landing zone:

 Since the input contains a wide variety of data formats, including images and
videos, it is better to store them in Azure Blob storage.
 Azure Data Lake Gen2 provides a hierarchical namespace and is usually a
good storage choice for data lakes. But since this use case includes images
and videos, it is not recommended here.

 Synapse SQL pool is a data warehouse solution that can be used to process
data and store it to be used by business intelligence tools such as Power BI.

 Azure Data Factory provides connectors to read data from a huge variety of
sources and orchestration support. Hence, it will not be a good fit for this
situation.

Transformation zone:

 Since the requirement includes cleaning up the incoming data, visualizing the


data, and transforming the different formats into a standard schema that can
be consumed by reports, Azure Databricks would fit the bill. Azure Databricks
also supports Notebooks with Scala and Python support.

 Synapse SQL pool can be used to store the processed data generated by
Azure Databricks, but would not be a good fit for Scala and Python support.

 Azure Stream Analytics is used for real-time processing. Hence, it will not
work for our use case.

Serving zone:

 Synapse SQL pool, being a data warehouse that can support petabytes of


data, would be a perfect choice here.

 Azure Data Lake Gen2 provides a hierarchical namespace and is usually a


good storage choice for data lake landing zones, but not for the serving zone.
Serving zones need to be able to serve the results quickly to BI systems, so
usually SQL-based or key-value-based services work the best.

 Azure Stream Analytics is used for real-time data processing. Hence, it will not
work for our use case.

Reporting:
 Power BI is a graphical business intelligence tool that can help visualize data
insights. It provides a rich set of graphs and data filtering, aggregating, and
sorting options.

 The Azure portal is the starting page for all Azure services. It is the control
center for all services that provides options for creating, deleting, managing,
and monitoring the services.

Let's next look at an ASA windowed aggregates question.

ASA windows
You are working for a credit card company. You have been asked to design a
system to detect credit card transaction fraud. One of the scenarios is to check
whether a credit card has been used more than 3 times within the last 10 mins.
The system is already configured to use Azure Event Hubs and Azure Stream
Analytics. You have decided to use the windowed aggregation feature of ASA.
Which of the following solutions would work? (Select one or more)

 A – Use a tumbling window with a size of 10 mins and check whether the
count for the same credit card > 3.

 B – Use a sliding window with a size of 10 mins and check whether the count
for the same credit card > 3.

 C – Use a hopping window with a size of 10 mins and a hop of 3 mins and
check whether the count for the same credit card > 3.

 D – Use a session window with a size of 10 mins and check whether the count
for the same credit card > 3.

Solution

B – Sliding Window

Explanation
 A sliding window has a fixed size, but the window moves forward only when
events are either added or removed. Otherwise, it won't emit any results. This
will work perfectly as the window is of a fixed size and is moving after
considering each and every event in progressive windows of 10 mins. This is a
typical use case for a sliding window: For every 10 seconds, alert if an event
appears more than 5 times.
 A tumbling window calculates the number of events in fixed-size non-
overlapping windows, so it might miss out on counting the events across
window boundaries. Here's a typical use case: Find the number of events
grouped by card number, in 10-second-wide tumbling windows.
 A hopping window calculates the count of events at every X interval, for the
previous Y window width duration. If the overlap window is not big enough,
this will also miss counting the events across window boundaries. Here's a
typical use case: Every 10 seconds, fetch the transaction count for the last 20
seconds.
 Session windows don't have fixed sizes. We need to specify a maximum
window size and a timeout duration for session windows. The session window
tries to grab as many events as possible within the max window size. Since
this is not a fixed-size window, it will not work for our use case. Here's a
typical use case: Find the number of trips that occur within 5 seconds of each
other.

Let's next look at a Spark transformation question.

Spark transformation
You work for a cab company that is storing trip data in Parquet format and fare
data in CSV format. You are required to generate a report to list all the trips
aggregated using the field. The report should contain all fields from both files. City

Trip file format (Parquet):

tripId, driverId, City, StartTime, EndTime

Fare file format (CSV):


tripId, Fare

Fill in the blanks of the following code snippet to achieve the preceding objective:

%%scala

val fromcsv = spark.read.options(Map("inferSchema"->"true","header"->"true"))

.csv("abfss://path/to/csv/*")

val fromparquet = spark.read.options(Map("inferSchema"->"true"))

.parquet("abfss:// abfss://path/to/parquet/*")

val joinDF = fromcsv.________(fromparquet,fromcsv("tripId") ===

fromparquet("tripId"),"inner")._________("City")
CopyExplain

[Options: , , , joinorderByselectgroupBy]

Solution

Join, groupBy

Explanation

 join() – To join two tables based on the provided conditions


 groupBy() – Used to aggregate values based on some column values, such
as in this caseCity
 select() – To select the data from a subset of columns
 orderBy() – To sort the rows by a particular column

Let's next look at an ADF integration runtime-based question.

ADF – integration runtimes


You are working as a data engineer for a tax consulting firm. The firm processes
thousands of tax forms for its customers every day. Your firm is growing and has
decided to move to the cloud, but they want to be in a hybrid mode as they already
have invested in a good set of on-premises servers for data processing. You plan
to use ADF to copy data over nightly. Which of the following integration runtimes
would you suggest?

 A – Azure integration runtime

 B – Self-Hosted integration runtime

 C – Azure – SSIS integration runtime

Solution

B – Self-Hosted Integration Runtime: Since this is an on-premises to the cloud


use case, the self-hosted integration would be ideal. Also, since they have their
local compute available, it would become much easier to set up the IR on the local
servers.

Explanation

Azure Integration Runtime – This is the default option and supports connecting


data stores and compute services across public endpoints. Use this option to copy
data between Azure-hosted services.

Self-Hosted Integration Runtime – Use the self-hosted IR when you need to


copy data between on-premises clusters and Azure services. You will need
machines or VMs on the on-premises private network to install a self-hosted
integration runtime.

Azure – SSIS Integration Runtime – The SSIS IRs are used for SQL Server


Integration Services (SSIS) lift and shift use cases.

Let's next look at a question on ADF triggers.

ADF triggers
Choose the right kind of trigger for your ADF pipelines:

 A – Trigger when a file gets deleted in Azure Blob storage


 B – To handle custom events in Event Grid

 C – Trigger a pipeline every Monday and Wednesday at 9:00 A.M. EST

 D – Trigger a pipeline daily at 9:00 A.M. EST but wait for the previous run to
complete

[Options: Storage event trigger, Custom event trigger, Tumbling window trigger,
Schedule trigger]

Solution

 A – Storage event trigger

 B – Custom event trigger

 C – Schedule trigger

 D – Tumbling window trigger

Explanation

 Schedule trigger – These are triggers that get fired on fixed schedules. You
specify the start date, recurrence, and end date, and ADF takes care of firing
the pipeline at the mentioned date and time.
 Tumbling window trigger – These are stateful scheduled triggers that are
aware of the previous pipeline runs and offer retry capabilities.
 Storage event trigger – These are triggers that get fired on Blob storage
events such as creating or deleting a file.
 Custom trigger – These are triggers that work on custom events mainly for
Event Grid.

Let's next look at a question from the data security section.

Sample questions from the Design and


Implement Data Security section
This section contains sample questions from the data security section of the
syllabus. Let's start with a Synapse SQL encryption-based question.

TDE/Always Encrypted
You have configured active geo-replication on an Azure Synapse SQL instance.
You are worried that the data might be accessible from the replicated instances or
backup files and need to safeguard it. Which security solution do you configure?

 Enable Always Encrypted

 Enable Transport Layer Security (TLS)


 Enable Transparent Data Encryption (TDE)
 Enable row-level security

Solution

Enable Transparent Data Encryption (TDE)

Explanation

 TDE encrypts the complete database, including offline access files such as


backup files and log files.

 Always Encrypted is used to encrypt specific columns of database tables, not


the complete database or the offline files.

 TLS is for encrypting data in motion. It doesn't deal with encrypting databases.

 Row-level security is for hiding selected rows from non-privileged database


users. It doesn't encrypt the database itself.

Let's next look at an Azure SQL/Synapse SQL auditing question.

Auditing Azure SQL/Synapse SQL


You work for a financial institution that stores all transactions in an Azure SQL
database. You are required to keep track of all the delete activities on the SQL
server. Which of the following activities should you perform? (Select one or more
correct options)

 Create alerts using Azure SQL Metrics.

 Enable auditing.

 Configure Log Analytics as the destination for the audit logs.

 Build custom metrics for delete events.

Solution

 Enable auditing.

 Configure Log Analytics as the destination for the audit logs.

Explanation

 Enabling auditing will track all the events in the database, including delete
activities.

 Configuring the destination as Log Analytics or Storage (Blob) will suffice the


requirement to keep track of the activities. Log Analytics provides the
advantage of Kusto queries, which can be run to analyze the audit logs. In the
case of Blob storage, we will have to write custom code to analyze the audit
logs.

 Building custom metrics is not required as the audit function will automatically
keep track of all deletions.

 Creating alerts is not required as the requirement is to only keep track of the
delete activities, not to alert.

Let's next look at a Dynamic Data Masking (DDM) question.

Dynamic data masking


You need to partially mask the numbers of an SSN column. Only the last four digits
should be visible. Which of the following solutions would work?

 A – ALTER TABLE [dbo].[Customer] ALTER COLUMN SSN ADD MASKED WITH FUNCTION
='PARTIAL(4, "xxx-xx-", 4)');
 B – ALTER TABLE [dbo].[Customer] ALTER COLUMN SSN ADD MASKED WITH FUNCTION
= 'PARTIAL(4, "xxx-xx-", 0)');
 C – ALTER TABLE [dbo].[Customer] ALTER COLUMN SSN ADD MASKED WITH (FUNCTION
= 'PARTIAL(0,"xxx-xx-", 4)');
 D – ALTER TABLE [dbo].[Customer] ALTER COLUMN SSN ADD MASKED WITH FUNCTION
= 'PARTIAL("xxx-xx-")');

Solution

C – ALTER TABLE [dbo].[Customer] ALTER COLUMN SSN ADD MASKED WITH FUNCTION
='PARTIAL(0, 'xxx-xx-', 4)');

Explanation

The syntax for partial masking is .partial(prefix,[padding],suffix)

Let's next look at an RBAC-based question.

RBAC – POSIX
Let's assume that you are part of the engineering AAD security group in your
company. The sales team has a directory with the following details:

Figure 15.1 – Sample sales directory with owner and permission information

Will you be able to read the files under the directory?/Sales

Solution
No

Explanation

In POSIX representation, there are numbers to indicate the permissions for , ,


and .OwnerOwner GroupOthers

In our question, the 740 would expand into:

Owner:
7 (Read – 4, Write – 2, Execute – 1. Total: 4+2+1 = 7) // Can Read, Write,
and Execute

Owner Group: 4 (Read – 4, Write – 0, Execute – 0. Total: 4+0+0 = 4) // Can Read,


but not Write or Execute

Others: 0 (Read – 0, Write – 0, Execute – 0. Total: 0+0+0 = 0) // Cannot Read,


Write, or Execute

So, the answer to the question would be No. Since you are part of the engineering
security group, you would fall under the category, which doesn't have any
permissions.Other

Let's next look at a row-level security question.

Row-level security
You are building a learning management system and you want to ensure that a
teacher can see only the students in their class with any queries. Here is
the table:SELECTSTUDENT

CREATE TABLE StudentTable {

  StudentId VARCHAR (20),

  StudentName VARCHAR(40),

  TeacherName sysname,

  Grade VARCHAR (3)


}
CopyExplain

Fill in the missing sections of the following row-level security script:

1. Step 1:
2. CREATE ______ Security.TeacherPredicate (@TeacherName AS sysname)

3. RETURNS TABLE

4. AS RETURN SELECT 1

WHERE @TeacherName = USER_NAME()


CopyExplain

[Options: , , FUNCTIONTABLEVIEW]

2. Step 2:
3. CREATE ___________ PrivFilter

4. ADD FILTER PREDICATE Security.TeacherPredicate (TeacherName)

ON StudentTable WITH (STATE = ON);


CopyExplain

[Options: , , SECURITY POLICYTABLEVIEW]

Solution

 Step 1: FUNCTION
 Step 2: SECURITY POLICY

Explanation

 Step 1: You must create a that can be applied as a , not a or a .FUNCTIONFILTER
PREDICATETABLEVIEW
 Step 2: You must create a that can be applied on the table, not a or
a .SECURITY POLICYTABLEVIEW
Let's next look at a few sample questions from the monitoring and optimization
section.

Sample questions from the Monitor and


Optimize Data Storage and Data
Processing section
This section contains sample questions from the monitoring and optimization
section of the syllabus. Let's start with a Blob storage monitoring question.

Blob storage monitoring


You have been hired as an external consultant to evaluate Azure Blob storage.
Your team has been using Blob storage for a month now. You want to find the
usage and availability of the Blob storage.

Question 1:

You can find the Blob storage usage from the Storage Metrics tab.

[Options: Yes/No]

Question 2:

You can find the Blob availability metrics from the Storage Metrics tab.

[Options: Yes/No]

Question 3:

You can find the Blob availability metrics from the Azure Monitor -> Storage
Accounts –> Insights tab.

[Options: Yes/No]
Solution

1. Question 1: Yes
2. Question 2: No
3. Question 3: Yes

Explanation

You can find the Blob storage usage from the Metrics tab on the Storage portal
page. But it doesn't have the store availability metrics. To look at the availability,
you will have to go to Azure Monitor and click on the Insights tab under Storage
accounts.

T-SQL optimization
You are running a few T-SQL queries and realize that the queries are taking much
longer than before. You want to analyze why the queries are taking longer. Which
of the following solutions will work? (Select one or more).

 A – Create a diagnostic setting for Synapse SQL pool to send the and logs to


Log Analytics and analyze the diagnostics table using Kusto to get the details
of the running query and the query waits.ExecRequestsWaits
 B – Run a T-SQL query against the and table to get the details of the running
query and the query waits.sys.dm_pdw_exec_requestssys.dm_pdw_waits
 C – Go to the Synapse SQL Metrics dashboard and look at the query
execution and query wait metrics.

Solution

Explanation

The diagnostic setting for Synapse SQL pool didn't provide the options for and as
of writing this book.ExecRequestsWaits
sys.dm_pdw_exec_requests – Contains all the current and recently active requests in
Azure Synapse Analytics.

sys.dm_pdw_waits –Contains details of the wait states in a query, including locks


and waits on transmission queues.

The SQL Metrics dashboard doesn't provide the query performance details.

Let's next look at an ADF monitoring question.

Monitoramento de ADF
There are two sub-questions for this question. Select all the statements that apply.

Question 1:

How would you monitor ADF pipeline performance for the last month?

 A – Use the ADF pipeline activity dashboard.


 B – Create a diagnostic setting, route the pipeline data to Log Analytics, and
use Kusto to analyze the performance data.

[Options: A, B]

Question 2:

How would you monitor ADF pipeline performance for the last 3 months?

 A – Use the ADF pipeline activity dashboard.


 B – Create a diagnostic setting, route the pipeline data to Log Analytics, and
use Kusto to analyze the performance data.

[Options: A, B]

Solution

Question 1:
A and B

Question 2:

Only A

Explanation

The ADF activity dashboard only keeps 45 days of data. Beyond that, we need to
use Azure Monitoring and Log Analytics.

Let's next look at an ASA alert-related question.

Setting up alerts in ASA


Select the four steps required to set up an alert to fire if SU % goes above 80%.
Arrange the steps in the right order:

 A – Configure diagnostic settings.

 B – Define the actions to be done when the alert is triggered.

 C – Select the signal as SU % utilization.

 D – Redirect logs to Log Analytics and use Kusto to check for Threshold >
80%

 E – Select the scope as your Azure Stream Analytics job.

 F – Set the alert logic as Threshold value %.Greater Than80

Solution

E, C, F, B

Explanation

The steps involved in setting up an ASA alert for SU % utilization are as follows:


 Select the scope as your Azure Stream Analytics job.

 Select the signal as SU % utilization.

 Set the alert logic as Threshold value %.Greater Than80


 Define the actions to be done when the alert is triggered.

Diagnostic settings and Log Analytics are not required. The required SU %
utilization metric is already available as part of ASA metrics.

That was the last of our sample questions!

Resumo
With that, we have come to the end of the book. I hope you enjoyed reading it as
much as I enjoyed writing it. The questions provided in this chapter are just
samples but should give you a good idea of how the questions will be in the
certification exam. One last piece of advice before you take the test: please try and
get familiar with all the concepts hands-on. The Azure certification tests look for
practical experience, so do try to create the resources, run sample jobs, set up
alerts, tune your queries, and so on, to boost your confidence levels.

Wishing you all the very best for your certification!

Why subscribe?
 Spend less time learning and more time coding with practical eBooks and
Videos from over 4,000 industry professionals

 Improve your learning with Skill Plans built especially for you

 Get a free eBook or video every month

 Fully searchable for easy access to vital information

 Copy and paste, print, and bookmark content


Did you know that Packt offers eBook versions of every book published, with PDF
and ePub files available? You can upgrade to the eBook version at packt.com and
as a print book customer, you are entitled to a discount on the eBook copy. Get in
touch with us at customercare@packtpub.com for more details.

At www.packt.com, you can also read a collection of free technical articles, sign up
for a range of free newsletters, and receive exclusive discounts and offers on Packt
books and eBooks.

Você também pode gostar