Entretanto, eventualmente, há cenários, mesmo em sistemas distribuídos, em que pode ser interessante com que partes de um sistema, intencionalmente decompostas, sejam combinadas para funcionar bem, juntas, em um única máquina. Neste capítulo, apresentamos padrões aplicáveis para estes cenários.
A arte da “decomposição”
Genericamente, a decomposição de sistemas pode ocorrer em unidades de implementação e em unidades de mitigação.
Decompondo sistemas em unidades de implementação
O método mais comum para decompor um sistema de software é a modularização, ou seja, a distribuição de suas responsabilidades em categorias coesas realizadas em unidades de implementação distintas (módulos).
Um sistema de e-commerce, por exemplo, modularizado, poderia ser decomposto em gestão do catálogo, cálculo de preço, cálculo de frete, recomendações, vendas, cobrança, disponibilidade, etc. Cada uma dessas unidades de implementação contemplaria, idealmente, comportamentos (features) e estado (dados).
Quanto mais coesa uma unidade de implementação, mais fácil será sua manutenção e operação. |
Decompondo sistemas em unidades de mitigação (de erros)
Além da modularização, também deve-se considerar a decomposição de um sistema de software em unidades de mitigação. A ideia é reduzir as chances de que erros em uma parte do sistema afetem – tanto pelas ocorrências quanto pelas ações para recuperação – outras partes, melhorando a resiliência.
Em um sistema de e-commerce, por exemplo, seria desejável que instabilidades da “cobrança” não afetassem o funcionamento de “vendas”. Isso seria possível se estas partes operassem em unidades de mitigação distintas, assíncronas e eventualmente consistentes.
Quanto menores e menos acopladas forem as unidades de mitigação de um sistema, maior o potencial para tolerância a falhas. |
Padrões para “composição”
Os padrões de combinação mais conhecidos, em grupos de contêineres, são sidecars, ambassadors e adapters.
Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services Nesse livro, Brendan Burns, um dos criadores do Kubernetes, compartilha descrições detalhadas dos três padrões propostos aqui. |
Sidecar
A implementação do padrão sidecar compreende a composição de um grupo de contêineres – compartilhando recursos como sistemas de arquivos e rede – com dois elementos: o primeiro que contém a lógica da aplicação propriamente dita e o segundo alguma “ampliação”, geralmente operacional.
O contêiner da aplicação, idealmente, não tem sequer conhecimento da existência do sidecar.
Como lógica de decomposição, pode-se atribuir, por exemplo, ao contêiner da aplicação uma unidade de implementação restrita a lógicas de negócio, enquanto o sidecar se encarrega de fundamentos operacionais (como indicadores para sistemas de monitoramento, por exemplo). Outra possibilidade é manter no contêiner da aplicação uma unidade de implementação legada, ampliada no sidecar.
Ambassador
Tecnicamente, a lógica de implementação do padrão ambassador é bem semelhante ao do sidecar. A diferença mais marcante é que o contêiner ambassador passa a intermediar todo acesso externo ao contêiner da aplicação, potencialmente, agregando aspectos de observabilidade e táticas básicas de resiliência (como load shedding, rate limiting, autenticação ou bilhetagem).
Adapter
O padrão adapter, conceitualmente, opera de maneira muito semelhante ao padrão ambassador. Entretanto, seu propósito é desacoplar o contrato exposto pela unidade de implementação presente no contêiner aplicação daquele esperado por eventuais consumidores.
Para pensar…
Os padrões de composição (e decomposição) que observamos aqui representam a essência do trabalho da moderna arquitetura de software. São basilares, tanto para a construção de aplicações fáceis de desenvolver, manter, operar e evoluir, quanto para construção de sistemas resilientes.
A conversation with Brendan Burns: What is Kubernetes? |