Como criamos (recriamos!) o Intune transformando-o no principal serviço de nuvem escalado globalmente

Não costumamos fazer isso aqui na Microsoft, mas hoje gostaríamos de compartilhar uma postagem (abaixo) que foi escrito apenas para uso interno.

Vamos esclarecer a primeira questão: “Mas por que vocês estão divulgando essas informações?”

Simplesmente porque quando vejo os clientes passando por transformações digitais excepcionais, muitas vezes escuto que as equipes de TI (e os líderes) sofrem para escalar sua infraestrutura ou seus aplicativos, não apenas na nuvem, mas também em termos da demanda exigida pela nuvem durante esse processo.

Eu entendo completamente esse sentimento, pois já passei por isso antes.

Meu objetivo com esta postagem é compartilhar como construímos nosso serviço de nuvem global; e espero que algumas destas informações possam servir como uma estratégia para que vocês mesmo criem algo.

Arquitetamos o Intune da nuvem e para a nuvem, e acabamos construindo o principal serviço de mobilidade no mundo e o único com uma escala real de nuvem.

Essa arquitetura é a melhor forma de capacitar nossos clientes para que atinjam seus objetivos, protejam seus dados e sua propriedade intelectual; tudo isso sem esbarrar em limites de produtividade e escala.

É uma experiência rara trabalhar em algo começando do zero (literalmente: Arquivo-Novo) e então você chega ao ponto de operar e otimizar aquilo que criou para um serviço de nuvem de grande escala que atende bilhões de transações todos os dias.

Trabalhar no Intune é uma dessas oportunidades raras e compensadoras.

O que mais chama a minha atenção nesta postagem é a genialidade dos engenheiros que fizeram esse trabalho. Não há outra forma de dizer.  Ao observar hoje o mercado massivo (e em constante crescimento) do gerenciamento móvel, vemos que o Intune é um serviço de nuvem real exclusivo. Outras soluções dizem ter um modelo de nuvem, mas, no fundo, elas simplesmente não forma construídas como um serviço de nuvem.

O time de engenharia do Intune tornou-se uma das equipes da Microsoft que está sempre buscando e sendo solicitada a apresentar as maneiras de como prosseguir nossa jornada em direção ao serviço de nuvem de grande escala. Quando começamos o Intune, o Azure era apenas uma hipótese aos olhos de alguns engenheiros excêntricos, por isso, a arquitetura inicial não foi construída no Azure. À medida que fomos observando um aumento real no uso do Intune em 2015, soubemos que tínhamos que refazer a arquitetura para torná-lo um serviço moderno do Azure construído em uma arquitetura de microsserviço baseada em nuvem.

E essa acabou sendo uma decisão monumental.

Olhando para trás, fica óbvio saber por que essa decisão foi tão importante:  como o serviço é escalado para dezenas e centenas de milhões e bilhões de dispositivos e aplicativos, uma arquitetura baseada em nuvem é a única forma de proporcionar a confiabilidade, a escala e a qualidade que você espera. Além disso, sem uma arquitetura baseada em nuvem, nossas equipes de engenharia não poderiam atender às necessidades de nossos clientes com a rapidez necessária.

Desde que fizemos essa mudança, inúmeros clientes já comentaram sobre as alterações que eles têm observado no que se refere à confiabilidade e ao desempenho, assim como a rapidez com que estamos fornecendo essas inovações.

Tudo isso é possível por causa da arquitetura.  A arquitetura realmente, realmente importa.

Essa perspectiva quanto a essa arquitetura ocorreu após muitas horas examinando outras soluções antes de decidirmos reconstruir o Intune. Antes de começarmos o trabalho no Intune, analisamos e avaliamos intensamente diversas soluções concorrentes para ver se deveríamos comprar alguma delas. Mas nenhuma foi considerada um serviço de nuvem, nenhuma. Todos esses eram produtos cliente/servidor local, hospedados em um data center e chamados de serviço de nuvem.

Esse não era o caminho para a hiperescala.

Uma maneira fácil de saber se um modelo é cliente-servidor ou um serviço de nuvem é verificar se tem um número de versão. Se for algo como “Produto X v8.3”, você imediatamente saberá que não se trata de um serviço de nuvem.  Não há número de versão em um serviço de nuvem quando ele é atualizado diversas vezes ao longo do dia.

Estou ansioso para ver o futuro do Intune, pois há situações em que somente os serviços de nuvem poderão atuar. Isso significa que a equipe de engenharia do Intune já está oferecendo soluções para problemas que nossos concorrentes ainda nem descobriram, além disso, com a expertise que possuem, a equipe será cada vez mais rápida em antecipar e atender às necessidades dos clientes.

Na qualidade de responsável pela engenharia, é muito empolgante imaginar o que isso significa para os serviços e ferramentas que criaremos para nossos clientes, além da forma como poderemos atendê-los quando nos trouxerem novos projetos e desafios.

Se você ainda não mudou para o Intune, reserve alguns minutos para ler esta postagem e, depois, vamos conversar.

 


 

Jornada do Intune em direção ao Serviço de nuvem amplamente escalonável distribuído globalmente

 

A partir do 2o semestre de 2015, o Intune, que é parte do Enterprise Mobility + Security (EMS), iniciou sua jornada como o negócio com expansão mais rápida na história da Microsoft. Começamos a observar os sinais desse resultado de crescimento rápido dos negócios em um rápido aumento correspondente nas operações de back-end em escala. Ao mesmo tempo, estávamos inovando em diversas áreas de nosso serviço dentro do Intune, no Azure e em outras áreas dependentes. Equilibrar inovação e rápido crescimento em pouco tempo foi um desafio interessante que enfrentamos com o Intune. Tínhamos alguns atenuantes, mas queríamos estar à frente em termos de escala e desempenho, e esse ritmo de crescimento foi como um alerta para acelerarmos o passo em nos tornar um serviço de nuvem escalonável, mais evoluído e distribuído globalmente. Nos meses que se seguiram, começamos a realizar alterações significativas na forma em que realizávamos a arquitetura, a operação e a execução dos serviços.

Esta postagem de blog é uma série organizada em 4 partes que descreverá a jornada dos serviços de nuvem do Intune ao se tornar um dos serviços de nuvem mais evoluído e escalonável em execução no Azure. Atualmente, somos um dos serviços mais evoluídos que operam em grande escala ao mesmo tempo em que continuamente melhoramos os 6 pilares de disponibilidade, confiabilidade, desempenho, escala, segurança e agilidade.

Arquitetura, histórico e nossas rápidas reações para satisfazer o cliente e criar um impacto positivo no crescimento dos negócios.

  1. Medidas e ações proativas para nos preparar para um crescimento imediato.
  2. As ações para desenvolver o serviço de modo a torná-lo altamente disponível e escalonável e ficar no mesmo patamar de outros serviços de grande escala de alta qualidade.
  3. O caminho para se tornar um serviço pioneiro e um exemplo para operações de grande escala em sistemas distribuídos.

Cada uma das postagens irá resumir as aprendizagens, além de explicar os tópicos em detalhes. O primeiro tópico dessa série de quatro está descrito a seguir. Os outros três serão abordados em postagens futuras nos próximos meses.

Histórico e arquitetura

Em 2015, o Intune era composto por uma combinação de serviços que eram executados em máquinas físicas, hospedadas em data centers privados e um conjunto de serviços distribuídos no Azure. Em 2018, todos os serviços do Intune foram movidos para serem executados no Azure. Esta postagem, assim como as futuras, enfocarão apenas os serviços distribuídos que são executados no Azure. A migração dos serviços em execução em máquinas físicas para o Azure é uma jornada diferente e talvez se torne tópico de uma postagem futura no blog. O restante desta seção enfoca o histórico e a arquitetura a partir de 2015.

Visão global da arquitetura

Os serviços de nuvem do Intune são construídos na parte superior do Azure Service Fabric (ASF). Todos os serviços são implantados em um cluster do ASF, consistindo em um grupo de nós de front-end (EF) e de camada intermediária. Os nós de FE são hospedados na SKU A4 (14 GB, 8 núcleos). Os nós de camada intermediária são hospedados na SKU A7 (56 GB, 8 núcleos). Cada cluster é completamente isolado e independente dos demais; eles não podem se acessar mutuamente de nenhuma maneira, uma vez que estão hospedados em assinaturas e data centers completamente diferentes. Há 18 clusters do ASF no mundo, distribuídos em três regiões: América do Norte (AN), Europa (EU) e Pacífico Asiático (PA). Cada cluster do ASF possui um conjunto idêntico de serviços implantados e desempenha uma funcionalidade idêntica. Esses serviços englobam serviços sem estado e com estado particionado. A Figura 1 apresenta a visão global da arquitetura.

Figura 1: Clusters Globais do Intune (também conhecido como Unidade de Escala do Azure, ASU) – visão da arquitetura (2015) SKU (14 GB, 8 núcleos). Os nós de camada intermediária são hospedados na SKU A7 (56 GB, 8 núcleos).

Análise detalhada da arquitetura de cluster

Em cada cluster, temos mais de 5 mil serviços em execução com um conjunto de aproximadamente 80 tipos únicos de microsserviços sem estado e cerca de 40 tipos únicos de microsserviços com estado. Os serviços sem estado executam diversas instâncias em todos os nós de FE roteados pelo balanceador de carga do Azure. Os serviços com estado e outros serviços sem estado de alto valor são executados nos nós de camada intermediária. Os serviços com estado são construídos na arquitetura na memória que construímos localmente como um banco de dados sem SQL (lembre-se de que estamos falando de 2015).

O armazenamento na memória com estado que implementamos é uma combinação de árvores AVL e conjuntos de hash para possibilitar gravações, obtenções, verificações de tabela e pesquisas de índice secundário extremamente rápidas. Esses serviços sem estado são particionados para expansão. Cada partição possui cinco réplicas para controlar a disponibilidade. Um desses cinco atua como a primeira réplica onde todas as solicitações são tratadas. As outras quatro réplicas são secundárias, replicadas da primeira. Alguns dos serviços exigem uma forte consistência para as operações de dados, o que significa que precisamos de um quorum de réplicas para atender às gravações. Nesses cenários, preferimos CP em vez de AP no teorema CAP, ou seja, quando nem um quorum de réplicas está disponível, a gravação falha e, então, perde-se a disponibilidade. Em alguns de nossos cenários não há problema com a consistência eventual, e nos beneficiaríamos do AP em vez do CP, mas, por motivos de simplicidade, nossa arquitetura inicial aguentava uma consistência maciça em todos os serviços. Então, nesse momento, escolhemos o CP.

O ASF realiza um ótimo trabalho em muitos aspectos, e um deles é no empacotamento denso dos serviços no cluster. O número normal de processos em execução em cada nó de camada intermediária varia entre 30 e 50 que hospedam diversas réplicas com estado. Ele também lida muito bem com as complexidades de movimento e failover de réplica de orquestração e de gerenciamento, realizando atualizações sem interrupção em todas as implantações de nosso serviço e balanceando a carga nos clusters. Se ou quando a réplica primária deixar de existir, o ASF promove automaticamente uma réplica secundária para primária, e uma nova réplica secundária é criada para atender a exigência de cinco réplicas. A nova réplica secundária é iniciada e realiza uma transferência completa de dados de memória para a memória, da primária para a secundária. Periodicamente também fazemos um backup de dados em um armazenamento externo, persistente de Blobs/tabelas do Azure com um RPO de 10 minutos para recuperação para os casos em que todas as réplicas são perdidas em um desastre ou em uma perda de partição. A Figura 2 mostra a visão do cluster. A Figura 2 mostra a visão do cluster.

Escala Figura 2: RPO da arquitetura (2015) da unidade de escala do Azure do Intune (ou cluster ou ASU) para recuperação em casos em que todas as réplicas são perdidas em um desastre ou em uma perda de partição. A Figura 2 mostra a visão do cluster.. A Figura 2 mostra a visão do cluster.

Problemas

Conforme mencionado anteriormente, com um rápido crescimento no uso (de cerca de 3 bilhões de transações para 7 bilhões por dia), no final de 2015 e início de 2016, nossos serviços de back-end começaram a apresentar um enorme aumento correspondente no tráfego. Então, começamos a refletir a respeito de soluções táticas para oferecer um alívio imediato de modo a solucionar os problemas consequentes desse crescimento.

Problema 1:

A primeira coisa que percebemos era que precisávamos de telemetria e alertas adequados. A escala em que precisávamos de telemetria também passava por uma rápida inovação na infraestrutura subjacente do Azure naquele momento, e não pudemos aprimorá-la imediatamente em virtude dos tempos de GA etc. Então, de um ponto de vista tático, precisávamos inventar algumas soluções de diagnóstico e de instrumentação muito rapidamente para que pudéssemos obter dados suficientes para iniciar as mitigações. Quando a telemetria correta ficou pronta, começamos a coletar os dados sobre os problemas mais críticos que deveríamos solucionar para proporcionar o alívio mais abrangente.

Os rápidos investimentos em telemetria foram muito compensatórios. Pudemos investigar e determinar soluções táticas e iterá-las rapidamente. Os demais problemas foram orientados por esses investimentos de curto prazo, mas de alto impacto, em telemetria.

Problema 2:

Com a telemetria nos demos conta de que algumas partições estavam lidando com quantidades imensas de dados. Algumas vezes, uma única partição estava armazenando milhões de objetos, e as taxas de transação atingiam os 6 bilhões por dia nos clusters. O aumento de dados implicava aumento na transferência de dados, quando réplicas secundárias precisavam ser criadas para o caso de alguma das réplicas, primárias ou secundárias existentes, deixasse de existir ou precisasse passar por balanceamento de carga. Quanto mais dados, mais tempo levaria para criar a réplica secundária com custos de CPU e memória associados.

Grande parte desse tempo era em virtude da serialização e desserialização dos dados necessários para transferência entre as réplicas durante a recompilação. Estávamos usando o serializador de contrato de dados e, depois de investigações de desempenho de muitos serializadores, acordamos mudar para usar o Avro. O Avro proporcionou uma melhora de CPU e de taxa de transferência de 50% e reduziu significativamente o tempo de recompilação. Por exemplo, para uma transferência de dados de 4GB, as recompilações que estavam levando 35 minutos, passaram a ser concluídas em menos de 20 minutos. Isso não é o ideal, mas estávamos procurando um alívio imediato, e essa solução nos ajudou nesse sentido. Na próxima postagem, vou explicar como reduzimos esse tempo de 20 minutos para segundos.

Problema 3:

O crescimento no uso também acarretou novos padrões de tráfego e pesquisa de algoritmos que não estavam completamente otimizados para lidar com isso de forma eficiente (CPU/memory wise). Projetamos uma pesquisa de índice secundário eficiente com árvores AVL, no entanto, para determinados padrões de pesquisa, conseguimos otimizar ainda mais. Consideramos que as árvores de índice secundário normalmente teriam tamanhos muito menores em comparação à árvore principal que faz as verificações completas de tabela e que deve atender a todas as nossas necessidades. No entanto, quando estávamos observando os problemas de alta utilização de CPU, percebemos um padrão de tráfego que ocasionalmente vinculava a CPU para determinadas pesquisas de índice secundário. As análises mais detalhadas nos mostraram que a paginação e a ordem das pesquisas com milhões de objetos em um índice secundário pode causar um uso extremamente alto da CPU e impactar em todos os serviços em execução naquele nó.

Essa foi uma grande descoberta à qual pudemos reagir imediatamente e projetar um algoritmo alternativo. Para a paginação e a ordem das pesquisas, projetamos e implementamos uma abordagem de heap máximo para substituir a árvore AVL. A complexidade de tempo para inserções e pesquisas é uma ordem de magnitude melhor para o heap máximo. Inserir objetos de 1M reduziu o tempo de 5 segundos para 250 milésimos de segundo, e observamos ordens por (basicamente classificação) melhorias nos objetos de 1M que foram de 5 segundos a 1,5 segundos. Em razão do número de consultas da pesquisa que estavam realizando esses tipos de operações, essa melhoria resultou em uma economia significativa do consumo de CPU e de memória no cluster. economia significativa do consumo de CPU e memória no cluster.

Problema 4:

A grande maioria de todo o impacto do crescimento foi observada quando estávamos realizando as implantações e atualizações. Todos esses problemas aumentaram quando os nós de FE e de camada intermediária foram reinicializados pelo Azure como parte do agendamento de aplicação de patch do sistema operacional. Esses nós eram domínios de atualização (UD) reinicializados pelos UD de maneira sequencial, com um limite rigoroso de 20 minutos para cada UD ficar completamente funcional antes de passar para a próxima atualização de UD.

Havia duas categorias para os problemas que surgiram com as atualizações:

  • A contagem de réplica para serviços com estado era igual ao número de UDs (ambas eram 5). Então, quando um UD estava sendo atualizado, o ASF tinha de mover todas as réplicas daquele UD para um dos outros quatro e, ao mesmo tempo, manter várias restrições como a distribuição adequada de réplicas de modo a manter posicionamentos de domínios de falha, não deixar primárias e secundárias nos mesmos nós e muitas outras. Dessa forma, era necessária uma quantidade razoável de movimentos de réplicas e densidade durante as atualizações. Com base no problema 2 acima, sabíamos que algumas recompilações poderiam levar até 20 minutos, o que significava que as réplicas secundárias poderiam não ser completamente lidas antes do próximo UD ser atualizado. O resultado final disso foi a perda de quorum porque não estava ativo um número suficiente de réplicas para atender as gravações durante as atualizações. A Figura 3 mostra o efeito das alterações de densidade de réplica durante as atualizações. O grande aumento de cerca de 350 réplicas para cerca de 1000 réplicas em um de nossos serviços é um exemplo da quantidade de recompilações que estava ocorrendo. Nossa reação imediata foi aumentar a SKU para aliviar os nós, mas a plataforma subjacente não oferecia suporte para a atualização in-loco da SKU.  Sendo assim, precisávamos realizar o failover para um novo cluster, o que significava migração de dados. Como esse pode ser um procedimento bem complexo, descartamos a ideia. Em uma das próximas postagens, vou descrever como superamos essa limitação.
  • As equipes do Intune e do ASF realizaram uma análise profunda do problema e, com a ajuda da equipe do ASF, finalmente decidimos que a configuração ideal era usar 4 réplicas com 5 UDs, de modo que uma UD estivesse sempre disponível para assumir réplicas adicionais e evitar o movimento excessivo de réplicas. Isso deu um estímulo significativo à estabilidade do cluster, e a densidade de réplica de 3x delta durante as atualizações caiu para 50-75%.

 

Figura 3: Contagem de réplicas e impacto na densidade durante as atualizações

 

Por fim, também percebemos que nosso cluster ficaria com melhor balanceamento em termos de contagem de réplica e consumo de memória. Alguns nós eram muito utilizados, enquanto outros estavam quase ociosos. Obviamente, isso colocava uma sobrecarga indevida nos nós já muito carregados quando havia picos no tráfego ou atualizações. Nossa solução foi implementar as métrica de balanceamento de carga, relatórios e configuração em nossos clusters. O impacto dessa ação é melhor mostrado nas Figuras 4 e 5, as linhas azuis indicam o balanceamento após as melhorias. O eixo X é o nome do nó que usamos.

 

Figura 4: Contagens de réplica por nó antes e depois das melhorias de balanceamento de carga.

 

Figura 5: Consumo de memória por nó antes e depois das melhorias de balanceamento de carga.

 

O que aprendemos

  • Há quatro aprendizagens principais que essa experiência nos ensinou as quais acredito serem aplicáveis a qualquer serviço de nuvem de grande escala:
  • Faça a telemetria e alertas para uma das partes mais críticas de seu projeto. Monitore a telemetria e os alertas, itere, e faça o refinamento no ambiente de pré-produção antes de expor o recurso a seus clientes na produção.
  • Conheça suas dependências. Se sua solução de escala não estiver alinhada com a plataforma dependente, todas as opções estão fora de cogitação. Por exemplo, se a sua solução para expansão for aumentar de 10 nós para 500 nós, certifique-se de que a plataforma dependente (Azure ou AWS ou qualquer outra) aguenta esse aumento e o tempo necessário para realizar esse procedimento. Por exemplo, se houver um limite para aumentá-la em alguns nós de cada vez, será necessário ajustar o mecanismo de reação (alertas, etc.) para dar conta desse atraso. De modo semelhante, outro exemplo é escalar verticalmente. Se sua solução de escala vertical é realizar uma atualização da SKU, certifique-se de que a plataforma dependente irá aguentar uma atualização in-loco de uma SKU de baixo desempenho para uma SKU de alto desempenho.
  • Valide continuamente suas hipóteses. Muitos serviços e plataformas de nuvem ainda estão evoluindo, e as suposições que você tinha há apenas alguns meses podem não ser mais válidas em muitos aspectos, inclusive no que se refere ao projeto/arquitetura da plataforma dependente, soluções alternativas otimizadas/melhores disponíveis, recursos preteridos, etc. Isso em parte pode ser feito monitorando os caminhos de código principal no que se refere a alterações nos padrões de tráfego e garantindo que o projeto, os algoritmos, a implementação que você realiza ainda são válidos para uso. Os padrões de uso de tráfego no serviço de nuvem podem e vão mudar, e uma solução que era válida meses atrás, pode não ser mais a ideal e precisar ser revista/substituída por outra mais eficiente.
  • Faça do planejamento de capacidade uma prioridade. Determine como pode fazer uma análise de capacidade preditiva para garantir que você a revise em cadência regular. Isso fará diferença entre ser reativo e pró-ativo quanto aos problemas de escala que impactam o cliente.

Conclusão

A implementação e a distribuição de todas as soluções anteriores até a produção levou cerca de 3-4 meses. Em abril de 2016, os resultados eram bastante animadores. Houve uma grande melhora na estabilidade, na disponibilidade e na confiabilidade de nosso cluster. Isso foi percebido também por nossos clientes que reagiram de forma favorável e fizeram comentários positivos sobre as melhorias que tínhamos feito na confiabilidade e na estabilidade. Esse foi um enorme passo encorajador, mas tivemos todas as aprendizagens anteriores para nos impulsionar para frente a fim de torná-lo ainda melhor com mais aperfeiçoamentos. Nossa jornada em direção a um serviço de nuvem evoluído, distribuído e escalonável começou.

Observe que o conteúdo presente nas postagens do blog descreve características e funcionalidades que podem variar de acordo com o mercado. Para ver todos os detalhes sobre ofertas de produtos específicos para o seu mercado, acesse Microsoft 365, Office 365, Windows 10 ou Enterprise Mobility + Security.
O conteúdo dos links dessas postagens pode não estar disponível em seu idioma local.