Teste de aplicativos orientados a microsserviços

Olá, Habr!



Dando continuidade ao estudo do tópico de microsserviços , decidimos oferecer a tradução de um artigo sobre como testar MOA (aplicativos orientados a microsserviços). Recentemente, já abordamos o tópico de teste , mas no caso de microsserviços, o teste de unidade regular não é suficiente, você também precisa considerar os aspectos relacionados ao CI / CD e outras coisas que serão discutidas neste artigo.







Os microsserviços são um novo estilo de arquitetura de software usado na criação de sistemas distribuídos e estão cada vez mais sendo implementados em empresas que operam na Web, incluindo as maiores delas. Por exemplo, Netflix e Amazon adotaram arquitetura de microsserviço para acelerar significativamente o lançamento de produtos de software. Ao mesmo tempo, os sistemas monolíticos mais antigos não podem escalar a uma velocidade que atenderia aos desafios modernos.



Mas os benefícios que uma arquitetura de microsserviço pode trazer são tão bons quanto as melhores práticas para suportá-la podem ser testadas. Ao projetar testes para validar sistemas de microsserviços, onde a taxa de liberação pode ser descrita como extremamente rápida, é necessário pensamento inovador, tanto no nível micro quanto no macro.



A seguir, exploraremos os três tipos de aplicativos orientados a microsserviços, discutiremos alguns dos desafios que você precisará enfrentar para testá-los e falaremos sobre como os testes são escritos para apreciar plenamente os benefícios dos microsserviços.



Resumidamente sobre microsserviços



Antes de entrarmos em alguns dos meandros do projeto de testes para microsserviços, vamos dar uma olhada no que são microsserviços. Microservice é um componente de software detalhado que recebeu uma definição semântica clara; entretanto, o microsserviço carrega seu próprio conjunto de dados e não depende de outras estruturas e fontes de dados. Cada microsserviço tem seu próprio ciclo de implantação, portanto, após as alterações serem feitas no microsserviço, você pode liberá-lo sem interromper o trabalho de qualquer outro microsserviço no escopo do aplicativo com o qual este microsserviço está sendo executado.



Vantagens dos microsserviços em relação aos aplicativos monolíticos



Além disso, vamos dar uma olhada no que um microsserviço não é. A figura a seguir mostra um exemplo de um aplicativo monolítico típico.







Figura: 1: As arquiteturas de aplicativo monolíticas normalmente têm forte coesão de componentes



Os componentes Clientes, Produtos, Pedidos e (Comentários) podem ser considerados como um conjunto de classes escritas em uma linguagem orientada a objetos, como Java ou C #, onde clientes é uma matriz de objetos correspondentes a clientes, produtos - uma matriz de objetos correspondentes a produtos, etc. O objeto cliente pode usar tanto o objeto cliente quanto o objeto produto. Ou, devido ao fato de que todos os componentes de um aplicativo monolítico acessam o mesmo banco de dados, o objeto pedido pode acessar o banco de dados diretamente e obter todas as informações sobre o produto e o pedido necessários para concluir as tarefas. O acesso direto ao banco de dados não é apenas possível - e o quanto ele contradiz o espírito da programação orientada a objetos com base em um mapeamento objeto-relacional ORM - mas também é usado ativamente, especialmente nas áreas onde há uma grande demanda por recursos prontos na data combinada, não importa a que custo.



O resultado é um sistema fortemente acoplado, às vezes frágil, em que o lançamento de uma nova versão de um aplicativo requer coordenação significativa entre todas as equipes de desenvolvimento envolvidas no desenvolvimento desse sistema. Por causa do forte acoplamento, todo o ciclo de lançamento não pode ser mais rápido do que o trabalho mais lento de renegociar uma dependência. Em outras palavras, se for o momento de atualizar o aplicativo e adicionar um novo recurso por clientes e um novo recurso por produtos, o lançamento não ocorrerá até que esses dois recursos estejam prontos. Se levar um dia para fazer uma atualização do produto e três semanas para fazer uma alteração no cliente, o lançamento ocorrerá no máximo três semanas. Além disso, o que agrava ainda mais a situação, durante a liberação, pode ser necessário não só coordenar o novo código referente a clientes e mercadorias,mas também fazer alterações no esquema do banco de dados, e isso também terá que ser gerenciado durante o processo de liberação.



Liberar alterações em um banco de dados é uma tarefa muito delicada. Sempre existe o risco de efeitos colaterais indesejados ao alterar a estrutura do banco de dados. Lembre-se de que se algum componente puder acessar o banco de dados, ele o acessará e até executará operações nos dados que não estão dentro do escopo deste componente. Essa "manipulação fora da área" pode levar a falhas de outros componentes, e essas falhas podem passar despercebidas até que ocorra um desastre. Às vezes, um perigo potencial pode ser encontrado no código até o lançamento deste código em produção. Infelizmente, isso acontece o tempo todo.

Algumas empresas estão dispostas a tolerar os ciclos de lançamento lentos que são típicos para trabalhar com aplicativos monolíticos. Mas, se estamos falando de uma empresa que fornece suporte para centenas de milhares de usuários e, ao mesmo tempo, deve manter milhares de componentes funcionando, então o ritmo "não mais rápido do que o lançamento do componente mais recente" é inaceitável .



Aplicativos orientados a microsserviços



Em um aplicativo orientado a microsserviços (MOA), cada componente funcional é decomposto nas menores unidades possíveis com uma funcionalidade pronunciada (dentro de limites razoáveis). Nesse caso, cada um desses componentes funcionais é organizado como um microsserviço. Cada empresa tem sua própria bagagem de código legado, bem como uma cultura corporativa que deve ser respeitada, por isso é impossível escrever "notas semelhantes" como exatamente a decomposição deve ser realizada.



Quando se trata de decompor um aplicativo monolítico em MOA, o segredo é lembrar que o melhor é inimigo do bom. Certifique-se de que cada microsserviço seja estruturado de acordo com sua definição semântica, que o microsserviço tenha seus próprios dados e seu próprio ciclo de lançamento. A profundidade da implementação depende do que a empresa pode pagar, com base no tempo disponível, na experiência do funcionário e nos recursos disponíveis. Alguns microsserviços podem ter apenas uma função, outros podem ter muitas funções.

Existem três tipos de MOA : síncrono , assíncrono e híbrido .



Aplicativos orientados a microsserviços síncronos



A Figura 2 mostra um MOA síncrono. A comunicação entre serviços é um princípio de solicitação-resposta típico de interações HTTP na web.







Figura 2: aplicativo orientado a microsserviço com base na comunicação síncrona entre serviços



Cada microsserviço é segmentado por trás do servidor HTTP, o que permite o acesso à lógica deste microsserviço. Um microsserviço específico conhece apenas sua própria área de responsabilidade; ele também pode conhecer a interface para interagir com outro microsserviço, mas não consegue ver a lógica interna de outro serviço. Além disso, o microsserviço conhece apenas seus próprios dados. Os armazenamentos de dados de outros microsserviços não são conhecidos por ele e não estão disponíveis para ele. É impossível "sequestrar" os dados de outro microsserviço acessando diretamente o data warehouse para ele. A única maneira de obter dados do microsserviço e transferir novos dados para ele é interagir com ele por meio da interface pública.



Entre as vantagens dos MOAs síncronos está sua independência. Por exemplo, o microsserviço de clientes mostrado acima pode ser atualizado a qualquer momento que for conveniente. Não há dependências externas que precisam ser ajustadas para isso. Desde que o microsserviço não mude sua interface pública, bem como a estrutura dos dados que pretende consumir da solicitação e retornar como resposta, o risco de quebrar toda a arquitetura MOA é mínimo.



Por sua própria natureza, a arquitetura MOA é tal que mantém sua própria integridade estrutural. Como o microsserviço em si carrega seus próprios dados, seu trabalho não afeta os armazenamentos de dados de outros serviços. Como um microsserviço é representado como um conjunto de URLs HTTP e estruturas de dados relacionadas, construídas com base no princípio de solicitação-resposta, os limites da interface do microsserviço são claramente definidos.



Os MOAs síncronos estão se tornando cada vez mais populares. Muitas interfaces de MOA síncronas são baseadas no paradigma REST, um estilo que existe desde 2000Do ano. Mas, apesar de sua popularidade, o MOA tem uma desvantagem: baixa velocidade. Os consumidores de um microsserviço síncrono nunca funcionarão mais rápido do que este microsserviço pode processar solicitações e respostas. Isso pode ser um grande gargalo, especialmente ao lidar com microsserviços, cujos processos demoram muito para serem executados. Um exemplo é um serviço analítico complexo que consome e processa terabytes de dados. Poucos clientes concordarão em sentar e esperar alguns minutos seguidos até que o serviço seja encerrado. Seria mais conveniente informar ao microsserviço o trabalho que precisa ser feito e ser notificado quando os resultados estiverem prontos.



Em situações como essa, é mais conveniente adotar uma abordagem assíncrona para projetar microsserviços.



Aplicativos orientados a microsserviços assíncronos



A Figura 3 abaixo mostra uma implementação de MOA assíncrona, onde a comunicação serviço a serviço é fornecida pela troca de mensagens entre as partes envolvidas. Normalmente, essa interação é chamada de “dispare e esqueça”.







Figura 3: A arquitetura de MOA assíncrona é baseada em mensagens



Na arquitetura de MOA assíncrona, as mensagens podem ser geradas aleatoriamente ou em resposta a um determinado evento. Por exemplo, quando (conforme mostrado na imagem acima) um pedido é criado no microsserviço Pedidos, esse serviço pode publicar um evento orders_created



e colocá-lo em uma fila de mensagens complementares ., que está ouvindo outro microsserviço, cobrando (não mostrado na figura) e aceitando mensagens recebidas. O microsserviço de faturamento coleta a mensagem de informações do pedido e a processa de uma forma que seja relevante do ponto de vista do faturamento.



A vantagem de uma abordagem assíncrona para projetar aplicativos orientados a microsserviços é que não há gargalos em tal sistema e, portanto, é extremamente eficiente. A desvantagem é que esse sistema é muito difícil de criar e gerenciar.

Para sistemas assíncronos de grande escala como Uber, é normal processar milhares de mensagens por segundo. A depuração de tal sistema é difícil porque seus fluxos de trabalho não têm trajetórias claras. Não se trata de fazer uma ação primeiro e depois fazer outra; a lógica é acionada dependendo da mensagem recebida, ou seja, tudo pode acontecer a qualquer momento.



Isso deve ser mantido em mente ao desenvolver estratégias de teste. Por exemplo, um sistema assíncrono é impraticável, cujo desempenho depende da solicitação e dos tempos de resposta, já que nunca haverá uma correspondência um a um "um pedido um resposta".



Aplicativos híbridos orientados a microsserviços



A abordagem equilibrada para implementar um aplicativo orientado a microsserviços é híbrida. Os serviços são simultaneamente síncronos, ou seja, a comunicação direta solicitação-resposta é suportada entre eles e, ao mesmo tempo, assíncrona; ou seja, algumas das mensagens são geradas em conjunto com ou como resultado de mensagens síncronas.



A Figura 4 ilustra os padrões de comunicação usados ​​em uma abordagem híbrida para aplicativos orientados a microsserviços. O microsserviço de clientes é representado como um URL associado a um servidor HTTP e como uma fila em um agente de mensagens.







Figura 4: Uma abordagem híbrida para projetar aplicativos orientados a microsserviços que usa opções de comunicação síncrona e assíncrona entre serviços e consumidores.

Você pode adicionar um cliente ao microsserviço usando a comunicação de solicitação-resposta HTTP padrão. A solicitação é recebida e processada e, em seguida, uma resposta é gerada. No entanto, antes que uma resposta seja gerada, uma mensagem com informações sobre o novo cliente é publicada na fila de mensagens complementares para que outros serviços interessados ​​possam consumi-la. As informações enviadas para a fila de mensagens podem ser as mesmas geradas na resposta HTTP ou um pouco diferentes, a critério do microsserviço. Tudo depende de como o microsserviço foi desenvolvido e dos acordos de QoS que o microsserviço deve aplicar.



GraphQLÉ uma tecnologia API que suporta comunicação síncrona e assíncrona entre um consumidor e um serviço. Saiba mais sobre esta técnica e assinaturas GraphQL aqui .



A característica mais importante da abordagem híbrida é que ela combina os méritos das outras duas abordagens. Mas há desvantagens associadas, em particular, gargalos potenciais que reduzem o desempenho e a complexidade adicional associada à necessidade de oferecer suporte a dois tipos fundamentalmente diferentes de interfaces usadas pelo microsserviço "dentro" e "fora".



Dificuldades surgem ao projetar testes para microsserviços



Quando se trata de testar esses aplicativos, a primeira coisa a lembrar é que é muito raro um único microsserviço ser compartilhado por vários MOAs. Normalmente, um microsserviço é um dos muitos em um domínio específico de um aplicativo. A virtude de uma abordagem orientada a microsserviços para design de arquitetura de aplicativo é a transferência de código mais rápida de e para a produção. A Netflix, por exemplo, tem mais de 4.000 implantações por dia .) Essa taxa de lançamento simplesmente não é possível em um ambiente de aplicativo monolítico tradicional.



Também deve ser lembrado que o teste de MOA deve ocorrer nos níveis micro e macro.



Teste de nível micro



No nível micro, cada serviço deve ser testado exaustivamente dentro de sua área de responsabilidade. De acordo com algumas interpretações, uma função é considerada um limite de microsserviço.



Vá além do teste de unidade tradicional



É aconselhável prestar atenção especial à função dentro do microsserviço, dada a crescente popularidade do paradigma sem servidor , segundo o qual o microsserviço deve ser apresentado apenas como uma única função. Mas muitos testadores praticantes tendem a se limitar a testes de unidade ao trabalhar com microsserviços. Enquanto um teste de unidade normalmente cobre uma única função que funciona em um ambiente de teste muito limitado, um microsserviço é projetado para servir a um público em toda a web. Portanto, as condições de teste devem ser extremas.



Por exemplo, como parte de um bom teste de micronível, você pode executar cem mil instâncias de um microsserviço ao mesmo tempo e ver como eles se comportam nessa escala. Não é suficiente testar apenas uma função por vez, aplicando um único teste de unidade a ela. É necessário executar tais testes em milhares de instâncias da função ao mesmo tempo, levando em consideração os indicadores do ambiente de hospedagem no qual você terá que trabalhar.



Teste sua unidade de implantação



Além de testar a funcionalidade do microsserviço, você também precisa testar a unidade de implantação na qual o microsserviço é lançado. Normalmente, os microsserviços são implantados como contêineres como parte de uma tecnologia de orquestração, como Kubernetes ou Docker Swarm . Um aspecto importante da orquestração de contêineres é garantir a resiliência de microsserviços a longo prazo.



Acredita-se que os microsserviços podem falhar por vários motivos, tanto devido à falha do host quanto devido a erros no próprio microsserviço. É normal que durante a operação simultânea de milhares de contêineres ocorra algum tipo de mau funcionamento de corrente. A importância do teste é que a saída correta do microsserviço do jogo não é menos importante do que seu funcionamento correto. Os testes de micronível garantem que o microsserviço ganhe vida e morra perfeitamente, em qualquer escala do sistema.



Certifique-se de que absolutamente tudo o que acontece com você está registrado



Os testes também devem garantir que todos os eventos significativos que ocorrem no microsserviço sejam registrados corretamente - e tão importante quanto, essas entradas de registro podem ser compreendidas. No mundo dos microsserviços, o registro é muito importante, especialmente para MOA assíncrono, onde não há execução sequencial de comportamentos. Freqüentemente, apenas os dados de log o ajudarão a compreender o que está acontecendo no aplicativo.



Teste de macro



Se o MOA é síncrono, assíncrono ou híbrido, é mostrado o modo de teste rigoroso. Ao testar microsserviços no nível macro, você precisa garantir que haja dois aspectos a serem satisfatórios: comunicação entre serviços e processos de implantação.



Garantir comunicação interserviços inteligente



Os microsserviços são, por definição, independentes uns dos outros. Eles determinam o que fazer com base nas informações que recebem, portanto, a precisão da comunicação entre serviços é crítica para a operação holística de um aplicativo orientado a microsserviços.



Fornecer comunicação entre serviços significa garantir que as informações certas cheguem aonde precisam ir e para onde vão. Os testes devem ser capazes de rastrear como as mensagens são trocadas e processadas. Isso é verdadeiro para a comunicação de solicitação-resposta HTTP e a troca de mensagens assíncronas propagadas por meio de um intermediário de mensagem. O teste deve ajudar a garantir que os formatos de mensagem sejam suportados para garantir um caminho de sistema positivo., e as mensagens formatadas incorretamente são rejeitadas e com explicações suficientes (e não apenas com um erro de "mensagem inválida").



Teste de integração contínua e implantação contínua



Processos bem organizados de integração contínua e implantação contínua (CI / CD) são essenciais em qualquer paradigma de desenvolvimento de software, mas quando se trata de aplicativos de microsserviços, um processo de CI / CD eficiente, preciso e rápido é essencial. Os MOAs podem ser revisados ​​a uma taxa de centenas de atualizações diárias, portanto, um único microsserviço que está atrasado pode se tornar um gargalo e retardar todo o processo de lançamento.



A melhor maneira de jogar pelo seguro é dar aos testes de pipeline de CI / CD a mesma prioridade que qualquer outro modo de teste de alto nível. Identificar e corrigir problemas como microsserviços de construção lenta devido a artefatos no código, provisionamento lento de tempos de execução onde microsserviços são hospedados e aumento lento de microsserviços já implantados são pré-requisitos para um pipeline de CI / CD saudável. Mesmo se o microsserviço for tão complexo quanto um ônibus, será de pouca utilidade se você não puder implantar e implantar unidades operacionais rapidamente.



Conclusão



Os microsserviços são o verdadeiro curinga. Os aplicativos orientados a microsserviços fornecem a flexibilidade e a velocidade necessárias para trazer novos recursos online quase na velocidade da luz. Grandes empresas que suportam milhões de usuários aprenderam isso hoje, mas a cada dia mais e mais empresas estão adotando esse estilo de arquitetura quando seus aplicativos alcançam a escala de toda a web.



Embora muitas empresas estejam tentando seriamente incorporar o espírito de uma arquitetura orientada a microsserviços em seus processos de desenvolvimento, esses MOAs são frequentemente testados usando práticas originalmente destinadas a aplicativos monolíticos. Esta é uma abordagem míope.

Ao contrário, as empresas devem aprender técnicas de teste modernas projetadas para garantir a independência dos microsserviços e a agilidade dos aplicativos que usam esses microsserviços. Quando as equipes de desenvolvimento e testadores conseguem sincronizar os princípios por trás do projeto de aplicativos de microsserviços, toda a empresa pode confiar muito mais nos pontos fortes dos microsserviços.



All Articles