A adoção de microsserviços na Netflix: lições para o design arquitetural

NGINX | 19 de fevereiro de 2015

Em algumas publicações recentes do blog, explicamos por que acreditamos ser fundamental adotar uma arquitetura de aplicações em quatro camadas na qual as aplicações são desenvolvidas e implantadas como conjuntos de microsserviços. Está cada vez mais claro que, se você continuar usando processos de desenvolvimento e arquiteturas de aplicações que funcionavam perfeitamente há dez anos, simplesmente não conseguirá avançar com rapidez suficiente para atrair e manter o interesse dos usuários de dispositivos móveis, que podem escolher entre um número cada vez maior de aplicativos.

A migração para uma arquitetura de microsserviços cria oportunidades empolgantes no mercado para as empresas. Para arquitetos de sistemas e desenvolvedores, ela oferece um nível sem precedentes de controle e agilidade na criação de experiências web inovadoras para os clientes. Porém, em um ritmo tão acelerado, pode parecer que há pouca margem para erros. No mundo real, não é possível interromper o desenvolvimento e a implantação dos seus aplicativos enquanto você reformula esses processos. Você sabe que seu sucesso futuro depende da transição para uma arquitetura de microsserviços, mas como fazer isso na prática?

Felizmente para nós, vários dos primeiros adeptos de microsserviços agora estão compartilhando generosamente seus conhecimentos dentro do espírito do código aberto, não apenas na forma de código publicado, mas também em apresentações em conferências e posts de blogs. A Netflix é um dos principais exemplos. Como diretor de Engenharia Web e, posteriormente, arquiteto de nuvem, Adrian Cockcroft supervisionou a transição da empresa de um modelo de desenvolvimento tradicional, com 100 engenheiros produzindo um aplicativo monolítico de aluguel de DVDs, para uma arquitetura de microsserviços, com várias equipes pequenas responsáveis pelo desenvolvimento completo de centenas de microsserviços que trabalham em conjunto para transmitir entretenimento digital a milhões de clientes da Netflix todos os dias. Atualmente Technology Fellow na Battery Ventures, Cockcroft é um importante defensor dos microsserviços e das arquiteturas nativas da nuvem, além de integrar o Conselho Consultivo Técnico da NGINX.

Em uma série de duas partes de posts no blog, apresentaremos os principais aprendizados de duas palestras que Cockcroft ministrou no ano passado: uma na primeira conferência anual da NGINX, em outubro, e outra em um encontro sobre microsserviços no Vale do Silício, alguns meses antes. (Também vale muito a pena assistir às gravações completas em vídeo.)

O que é uma arquitetura de microsserviços?

Cockcroft define uma arquitetura de microsserviços como uma arquitetura orientada a serviços composta por elementos fracamente acoplados que têm contextos delimitados.

Baixo acoplamento significa que você pode atualizar os serviços de forma independente; atualizar um serviço não exige alterar nenhum dos outros. Se você tem vários serviços pequenos e especializados, mas ainda precisa atualizá-los em conjunto, eles não são microsserviços, pois não têm baixo acoplamento. Um tipo de acoplamento que as pessoas tendem a ignorar durante a transição para uma arquitetura de microsserviços é o acoplamento de banco de dados, no qual todos os serviços se comunicam com o mesmo banco de dados e a atualização de um serviço exige a alteração do esquema. É necessário dividir o banco de dados e desnormalizá-lo.

O conceito de contextos delimitados vem do livro Domain Driven Design de Eric Evans. Um microsserviço com um contexto corretamente delimitado é autossuficiente para fins de desenvolvimento de software. É possível entender e atualizar o código do microsserviço sem saber nada sobre o funcionamento interno dos demais, pois o microsserviço e seus pares interagem estritamente por meio de APIs e, portanto, não compartilham estruturas de dados, esquemas de banco de dados nem outras representações internas de objetos.

Se você já desenvolveu aplicações para a Internet, então já conhece esses conceitos na prática, ainda que não pelo nome. A maioria dos aplicativos móveis se comunica com diversos serviços de backend para permitir que seus usuários façam coisas como compartilhar conteúdo no Facebook, obter rotas no Google Maps e encontrar restaurantes no Foursquare, tudo dentro do próprio aplicativo. Se o seu aplicativo móvel fosse fortemente acoplado a esses serviços, antes de lançar uma atualização você teria que conversar com todas as equipes de desenvolvimento responsáveis por eles para garantir que suas alterações não causariam nenhum problema.

Ao trabalhar com uma arquitetura de microsserviços, você considera as outras equipes internas de desenvolvimento da mesma forma que considera esses back-ends da Internet: como serviços externos com os quais seu microsserviço interage por meio de APIs. O “contrato” comumente aceito entre microsserviços estabelece que suas APIs sejam estáveis e compatíveis com versões futuras. Assim como é inaceitável que a API do Google Maps mude sem aviso prévio e de uma forma que prejudique seus usuários, sua API pode evoluir, mas deve permanecer compatível com as versões anteriores.

Práticas recomendadas para projetar uma arquitetura de microsserviços

Cockcroft descreve sua função como arquiteto de nuvem na Netflix não como alguém que controla a arquitetura, mas como alguém que descobre e formaliza a arquitetura que surgiu à medida que os engenheiros da Netflix a construíam. A equipe de desenvolvimento da Netflix estabeleceu várias práticas recomendadas para projetar e implementar uma arquitetura de microsserviços.

Crie um armazenamento de dados separado para cada microsserviço

Não use o mesmo armazenamento de dados de back-end para vários microsserviços. O ideal é que a equipe responsável por cada microsserviço escolha o banco de dados mais adequado ao serviço. Além disso, com um único armazenamento de dados, é muito fácil que microsserviços desenvolvidos por equipes diferentes compartilhem estruturas de banco de dados, talvez com o objetivo de reduzir a duplicação de trabalho. Isso acaba criando uma situação em que, se uma equipe atualizar uma estrutura de banco de dados, os outros serviços que também usam essa estrutura precisarão ser alterados.

Separar os dados pode tornar o gerenciamento de dados mais complicado, pois os sistemas de armazenamento separados podem ficar dessincronizados ou inconsistentes com mais facilidade, e as chaves estrangeiras podem mudar inesperadamente. É necessário adicionar uma ferramenta que execute o gerenciamento de dados mestres (MDM) em segundo plano para encontrar e corrigir inconsistências. Por exemplo, ela pode examinar todos os bancos de dados que armazenam IDs de assinantes para verificar se os mesmos IDs existem em todos eles (sem IDs ausentes ou adicionais em nenhum banco de dados). Você pode desenvolver sua própria ferramenta ou comprar uma. Muitos sistemas comerciais de gerenciamento de bancos de dados relacionais (RDBMSs) realizam esses tipos de verificação, mas geralmente impõem requisitos de acoplamento excessivos e, por isso, não são escaláveis.

Mantenha o código em um nível de maturidade semelhante

Mantenha todo o código de um microsserviço em um nível semelhante de maturidade e estabilidade. Em outras palavras, se você precisar adicionar ou reescrever parte do código de um microsserviço implantado que esteja funcionando bem, a melhor abordagem geralmente é criar um novo microsserviço para o código novo ou alterado, mantendo o microsserviço existente em operação. [Editor – Isso às vezes é chamado de princípio da infraestrutura imutável.] Dessa forma, você pode implantar e testar o novo código de maneira iterativa até que ele esteja livre de bugs e seja o mais eficiente possível, sem correr o risco de causar falhas ou degradação de desempenho no microsserviço existente. Quando o novo microsserviço estiver tão estável quanto o original, você poderá reuni-los novamente se, de fato, eles desempenharem juntos uma única função ou se houver outros ganhos de eficiência ao combiná-los. No entanto, segundo a experiência de Cockcroft, é muito mais comum perceber que um microsserviço deve ser dividido por ter ficado grande demais.

Faça uma compilação separada para cada microsserviço

Faça uma compilação separada para cada microsserviço, para que ele possa obter do repositório os arquivos de componentes nas revisões adequadas. Às vezes, isso faz com que vários microsserviços obtenham um conjunto semelhante de arquivos, mas em revisões diferentes. Isso pode dificultar a limpeza da base de código por meio da desativação de versões antigas de arquivos (pois é preciso verificar com mais cuidado se uma revisão não está mais em uso), mas essa é uma contrapartida aceitável diante da facilidade de adicionar novos arquivos à medida que novos microsserviços são criados. A assimetria é intencional: a introdução de um novo microsserviço, arquivo ou função deve ser fácil, não perigosa.

Implante em contêineres

Implantar microsserviços em contêineres é importante porque isso significa que você precisa de apenas uma ferramenta para implantar tudo. Desde que o microsserviço esteja em um contêiner, a ferramenta saberá como implantá-lo. Não importa qual seja o contêiner. Dito isso, o Docker parece ter se tornado rapidamente o padrão de fato para contêineres.

Trate os servidores como sem estado

Trate os servidores, especialmente aqueles que executam código voltado para o cliente, como membros intercambiáveis de um grupo. Todos eles desempenham as mesmas funções, portanto, você não precisa se preocupar com cada um individualmente. Sua única preocupação é garantir que haja servidores suficientes para processar a carga de trabalho necessária, e você pode usar o escalonamento automático para aumentar ou reduzir essa quantidade. Se um deles parar de funcionar, será substituído automaticamente por outro. Evite sistemas “snowflake”, nos quais você depende de servidores individuais para executar funções especializadas.

A analogia de Cockcroft é que você deve pensar nos servidores como gado, não como animais de estimação. Se você tem uma máquina em produção que desempenha uma função especializada, conhece-a pelo nome e todos ficam tristes quando ela para de funcionar, ela é um animal de estimação. Em vez disso, você deve pensar nos servidores como um rebanho de vacas. O que importa é quantos litros de leite você obtém. Se um dia perceber que está obtendo menos leite do que o normal, você identifica quais vacas não estão produzindo bem e as substitui.

A arquitetura de entrega da Netflix é baseada no NGINX

A Netflix é usuária do NGINX Open Source há muito tempo e se tornou a primeira cliente da NGINX, Inc. após sua constituição em 2011. De fato, a Netflix escolheu o NGINX como o núcleo de sua infraestrutura de entrega, a Open Connect, uma das maiores redes de entrega de conteúdo (CDNs) do mundo. Com capacidade para atender a milhares e, às vezes, milhões de solicitações por segundo, o NGINX e o NGINX Plus são soluções ideais para entrega HTTP de alto desempenho e permitem que empresas como a Netflix ofereçam experiências digitais de alta qualidade a milhões de clientes todos os dias.

Gravações de vídeo

Entrega Rápida
nginx.conf 2014, outubro de 2014

Migração para microsserviços, parte 1
Encontro sobre microsserviços do Vale do Silício, agosto de 2014

Migração para microsserviços, parte 2
Encontro de Microsserviços do Vale do Silício, agosto de 2014


Compartilhar
Tags: F5 NGINX, Tech

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.