Mostrando postagens com marcador microserviços. Mostrar todas as postagens
Mostrando postagens com marcador microserviços. Mostrar todas as postagens

quinta-feira, 9 de abril de 2015

Windows Nano Server - A maior evolução para o DevOps Microsoft

O grande gargalo para o uso de sistemas Windows em ambientes de nuvem e para uma boa infraestrutura de DevOps fora do Microsoft Azure é sem dúvida o footprint gigantesco do sistema. Manter uma maquina virtual onde apenas processos de backend precisam ser executados demanda a instalação do sistema operacional completo, incluindo ferramentas gráficas e tudo que as suporta, algo completamente desnecessárias nesse tipo de cenário. 

Atualmente, para preparar uma maquina Windows Server precisamos de cerca de 32GB de espaço em disco, com sorte, o que torna praticamente inviável o uso do sistema em muitos cenários, levando à preferência por ambientes mais leves e modularizados, casos das inúmeras distribuições Linux que temos hoje dominando os ambientes de nuvem e containers.

No entanto, neste último dia 8 de Abril, a Microsoft anunciou o desenvolvimento do Windows Nano Server, uma versão reduzida do sistema operacional, contendo apenas aquilo que é de fato necessário para a execução de uma infraestrutura de nuvem, removendo totalmente sua interface gráfica e demais funcionalidades desnecessárias. Com isso o footprint do sistema caiu expressivos 93%, o que nos leva a crer que poderemos ter uma maquina Windows Nano Server, totalmente viável para a execução de sistemas de backend, com razoáveis 2,3GB de espaço em disco, talvez até menos.

Isso torna viável também o uso do Windows Nano Server com Vagrant e, segundo a Microsoft, até Docker, simplificando absurdamente a criação de ambientes de DevOps para softwares desenvolvidos para a plataforma .NET, principalmente considerando o desenvolvimento do novo .NET Core 5 e ASP.NET 5, também bastante reduzidos em tamanho e muito melhor modularizados, se comparados às versões atuais.

A partir do lançamento desse novo sistema, com pouco investimento, será possível a distribuição e gestão do ciclo de vida de serviços de backend executados sobre a plataforma .NET e Windows em ambientes como o IBM BlueMix, ou Amazon AWS, de forma tão prática quanto é feita hoje para sistemas Java executados sobre uma distribuição Linux.

Essa foi sem dúvida a melhor notícia dos últimos tempos para desenvolvedores .NET e administradores de infraestrutura Windows. Ansioso para ver tudo isso funcionando na prática. Que 2016 chegue logo.

Atualização: Na Build 2015, foi anunciado que o Nano Server tem uma imagem de cerca de 400MB, contra quase 5GB da versão Server Core, a menor disponível atualmente. Além disso, o sistema gasta cerca de 40 segundos para ser instalado, 15 segundos para ser inicializado e ocupa apenas 63MB de memória. Números realmente impressionantes, mesmo em comparação ao atual Server Core.

Vejam mais detalhes em:

sexta-feira, 15 de agosto de 2014

Obtendo sucesso com Arquitetura de Microserviços

Muito tem-se falado em Arquitetura de Microserviços recentemente. Resumidamente, trata-se de um estilo arquitetural em que a lógica da aplicação é dividida em pequenos (micro) serviços os quais podem ser escalados e distribuídos independentemente. Parece simples, mas na prática surgem inúmeras dúvidas sobre como interpretar cada um dos conceitos envolvidos e como implementar cada um deles.
Neste artigo darei algumas dicas baseadas na experiência positiva que tenho tido com a implementação desse estilo nos últimos tempos.

Primeiramente, não se trata de integração de aplicações. Microserviços não é SOA. É muito parecido, mas não tem o mesmo objetivo. Está mais para objetos distribuídos de um mesmo sistema do que para integração de diferentes sistemas, embora os mecanismos usados para a integração entres esses 'objetos' seja muito mais semelhante aos usados em SOA que aos usados em estratégias convencionais de objetos distribuídos, como CORBA, EJBs ou .NET Remoting.

Em segundo lugar, também não se trata de objetos distribuídos tradicionais. Não pense em criar seus objetos de modo que possam ser usados tanto localmente quando de modo distribuídos e deixar alguma infraestrutura de comunicação tomar conta da integração entre eles. Isso é lento e foi o que deu a fama negativa que as tecnologias citadas no paragrafo anterior tem no que se refere a performance.

Se não são aplicações distintas, nem objetos comuns de uma única aplicação sendo integrados, o que são portanto esses microserviços?

Quando iniciei minha experiência com esse estilo arquitetural, o termo Arquitetura de Microserviços ainda não me havia sido apresentado, portanto não precisei me preocupar em seguir uma definição ao pé da letra para poder dizer que era isso o que eu fazia. E isso vale para quem já conhece os termos. Padrões servem para nos apontar o caminho, não para serem seguidos como religiões. Mas voltando ao meu caso, só percebi que o que eu havia construído era aderente a esse estilo depois que já estava quase tudo pronto. Foi um processo bastante natural e como fui guiado pelos mesmo requisitos arquiteturais que levaram à definição do termo Arquitetura de Microserviços, minha implementação já nasceu naturalmente aderente a ele.

A resposta para a última pergunta, no meu caso, veio da metodologia conhecida como Domain-Driven Design (DDD). Embora possa parecer àqueles que a desconhecem que tal metodologia trate apenas de técnicas para organizar objetos de domínio, ela é muito mais que isso. DDD é por si só um estilo arquitetural, o qual define a estrutura de toda a aplicação, não apenas dos objetos de domínio.

Um dos conceitos mais importantes em DDD é o conceito de Serviço de Aplicação. Um Serviço de Aplicação tem a função de coordenar tarefas recebidas de um cliente externo, seja uma IHM ou outra aplicação/serviço, orquestrando a interação entre seus objetos e serviços de domínio, e por fim consolidando o resultado da operação solicitada. As operações executadas por um Serviço de Aplicação devem ter início e fim, sem depender de outros Serviços de Aplicação. E embora um serviço de aplicação possa realizar diferentes funções, cada uma delas deve ser muito bem definida, bem de acordo com o princípio da responsabilidade única, além é claro de estarem de algum modo bem relacionadas.

Dessa forma, uma vez que recebida uma solicitação e um conjunto de dados de entrada, um Serviço de Aplicação irá realizar a função solicitada por completo e produzir um resultado também completo. E isso é exatamente o que precisamos ter em um Microserviço para que ele não nos traga problemas. Na solução a qual me refiro neste artigo, cada função de um Serviço de Aplicação foi implementada como um Microserviço*. Sendo assim, um Serviço de Aplicação não era pra mim uma unidade computacional única, mas sim um agrupamento lógico de Microserviços intimamente relacionados**. Desse modo, cada Microserviço poderia residir em sua própria unidade computacional ou compartilhar uma mesma unidade computacional com demais microserviços que escalassem de maneira semelhante.

No caso de uma aplicação .NET, uma unidade computacional pode ser criada como um Windows Service, por exemplo, enquanto que um Serviço de Aplicação poderia ser composto por uma Class Library contendo os Microserviços que representam suas funções. Já em Java a unidade computacional poderia ser um WAR enquanto que o Serviço de Aplicação poderia ser um simples JAR, apenas para contextualizar.

Mas como seria feito o acesso a esses Microserviços? Para serviços consumidos diretamente por uma página WEB, uma API Web, no formato REST, seria uma boa escolha, no entanto a maior parte dos serviços de um sistema desenvolvido sobre uma Arquitetura de Microserviços só terão interação com outros serviços de backend. Imagine por exemplo uma função de cálculo extremamente complexa e composta por inúmeras etapas. Um primeiro serviço poderia receber a solicitação através de uma página web, via API Web, e então iniciar a primeira etapa do processo de cálculo. Ao concluir essa etapa, o Microserviço que a realizou publicaria o resultado e se colocaria novamente à disposição para o recebimento de outras solicitações. Nesse momento, um segundo Microserviço, responsável pela segunda etapa do cálculo, receberia o resultado publicado pelo primeiro Microserviço e executaria a segunda etapa usando o resultado do primeiro como insumo, por fim publicando o seu resultado para que possa ser usado por um eventual terceiro Microserviço, até que todo o processo de cálculo esteja concluído. Eventualmente a página WEB receberia uma resposta contendo o resultado do cálculo e notificaria o usuário.

Nesse momento chegamos a um ponto extremamente importante. A integração entre Microserviços é quase sempre assíncrona e desacoplada. Um Microserviço deve publicar seu resultado e esquecer dele. Alguém irá recuperá-lo em algum momento e fazer bom uso dele, mas o Microserviço não deve se preocupar com isso, ou aguardar um reconhecimento do Microserviço que porventura dará continuidade a seu trabalho. Microserviços são como aquele colega de trabalho que você um dia teve, que faz a sua parte do trabalho e diz um foda-se para o restante da equipe. E é isso que garante sua alta disponibilidade, sua robustez, e permite que ele seja facilmente substituído caso necessário.

Para alguns casos no entanto, como o caso do primeiro serviço desse nosso exemplo, que recebeu a solicitação da página WEB e deve devolver uma resposta a ela, pode ser necessário aguardar o término do processo por algum tempo, ou considerar que ele falhou. Ou pode-se também iniciar um outro serviço que terá como única função notificar a página WEB quando todo o processo tiver terminado, de modo que o primeiro serviço irá responder à página WEB de imediato, informando apenas que recebeu e encaminhou sua solicitação para que fosse processada. Em todo caso as características marcantes são a assincronia e o desacomplamento.

Okay, mas como realizar esse troca de mensagens entre esses malditos Microserviços? A resposta no meu caso foi o padrão publish-subscribe, implementado através de um Middleware de Mensageria, sobre o padrão AMQP.

Acredito que eu já tenha escrito demais por hoje. Se você chegou até aqui é porque se interessa pelo tema, e estou a disposição para falar mais sobre o assunto. Deixe suas dúvidas ou sugestões no campo de comentários abaixo que procurarei responder, diretamente ou em forma de um novo artigo.

* Atenção ao fato de que me refiro a funções dos Serviços de Aplicação, as quais possuem uma granularidade bastante grande. Modelar funções de Objetos ou Serviços de Domínio como Microserviços seria voltar aos tempos dos objetos distribuídos, e voltar a ter os problemas de desempenho característicos destes.

** E antes de dizer que não é isso que dizem os livros do Evans ou do Vernon, lembrem-se que padrões são guias, não religiões.

Artigos Recomendados:
https://rclayton.silvrback.com/failing-at-microservices
http://highscalability.com/blog/2014/4/8/microservices-not-a-free-lunch.html

quinta-feira, 27 de março de 2014

Arquitetura de Microserviços e DDD

DDD já é velho conhecido de muitos desenvolvedores de software já há mais de 10 anos, no entanto o termo Microservices Architecture tem ganhado popularidade apenas recentemente.

Venho trabalhando em uma arquitetura de micro serviços, desenvolvida sobre o .NET Framework, já há quase 1 ano, desde antes da popularização do termo e até mesmo antes da publicação do Manifesto Reativo. No entanto, essa arquitetura tem se mantido desde o início bem aderente a esses dois conceitos.

Chamada aqui de Plataforma ST (nome real omitido), trata-se de uma arquitetura que permite que pequenos serviços de aplicação coexistam e se comuniquem entre si, de modo seguro, escalável e permitindo que novos serviços possam ser incluídos na plataforma a qualquer momento, complementando as funcionalidades já existentes. Note que não se trata de um único produto composto por múltiplos serviços relacionados, mas sim de uma plataforma de agregação de serviços. É possível haver uma instância da Plataforma ST agregando serviços de CRM, outra agregando serviços de ERP e outra para serviços de POS, cada uma dessas compondo um sistema distinto. Ainda assim, para cada uma delas, existe a possibilidade de se agregar novos serviços, incluindo alguns que sejam responsáveis exclusivamente pela interação entre esses diferentes sistemas.

Segundo as recomendações do DDD, módulos de um sistema, no nosso caso assemblies ou namespaces .NET, não devem conter no seu nome um nome de produto, mas sim a funcionalidade que ele provê, assim como devem conter como prefixo o nome da empresa que os desenvolveu. Assim, um módulo de gerenciamento de projetos ágeis desenvolvido pela empresa Contoso deveria ser nomeado com.contoso.agileprojectmanagement.applicationservice, de acordo com o que fora apresentado por Vaughn Vernon em Implementing Domain-Driven Design. No entanto, o padrão com.nomedaempresa se limita ao mundo Java, linguagem usada pelo autor para ilustrar o livro. Em projetos .NET, não há o costume de acrescentar o nome da empresa nos nomes dos módulos, e muito menos o prefixo com.

Ainda assim, poderíamos adaptar essa terminologia e nomear um dos nossos módulos de Contoso.AgileProjectManagement.ApplicationService, no entanto optei por usar ST.AgileProjectManagement.ApplicationService, e posso justificar essa decisão.

A Plataforma ST requer que os serviços desenvolvidos para executar sobre ela sigam um determinado padrão. Há uma classe abstrata ou no minimo uma interface que precisa ser implementada por todos os serviços, além disso eles precisam ser desenvolvidos levando em consideração o modo como a Plataforma ST irá gerir seu ciclo de vida. E mais, a Plataforma ST não é uma bala de prata, obviamente. Há cenários em que o mais interessante seja usar uma outra plataforma, ou desenvolver o sistema diretamente sobre o .NET Framework, já descartando os casos em que o próprio .NET Framework não seja a melhor opção.

Imagine por exemplo que seja desenvolvido na mesma empresa um sistema de colaboração, uma espécie de Wiki, que se adere aos padrões DDD mas não se encaixa na Plataforma ST. Esse sistema será desenvolvido de modo completamente independente dela, seus módulos serão totalmente incompatíveis. Agora seguindo a recomendação de usar o nome da empresa para determinar o nome dos módulos, teríamos algo como Contoso.Collaboration.ApplicationService, algo muito semelhante aos módulos dos sistemas desenvolvidos sobre a Plataforma ST, mas sem relação alguma com ela.

Por que não usar então Contoso.ST.AgileProjectManagement.ApplicationService? Ai vem um ponto em que discordo da recomendação do Vernon. Usar o nome da empresa, de qualquer modo que seja, na nomenclatura dos módulos, pode ser ruim e prefiro usar em seu lugar não o nome comercial de um serviço, o que concordo não ser recomendável, mas manter o módulo nomeado conforme sua função e prefixá-lo com um nome de projeto ao invés do nome da empresa. Seria algo que identifica todos os módulos que possuem algo em comum e cumpre a mesma função do nome da empresa na recomendação do livro.

Mas por que isso? Já trabalhei em uma empresa que mudou de nome, e via produtos legados com o nome antigo por todos os lados. Há casos de fusões e aquisições, em que o nome do proprietário do produto muda, e mesmo havendo motivações para manter o nome do desenvolvedor original mesmo que ele não exista mais, há o risco de novos módulos que integrem a mesma aplicação passarem a ser nomeados conforme o novo nome da empresa, o que geraria uma combinação de nomes de módulos não muito interessante.

Enfim, era isso que gostaria de compartilhar aqui e gostaria de ouvir a opinião de quem trabalha com DDD e já teve que passar por situações semelhantes às que descrevi. O que vocês tem a dizer?