Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O padrão Bulkhead é um tipo de design de aplicativo tolerante a falhas. Em uma arquitetura de antepara, também conhecida como arquitetura baseada em células, os elementos de um aplicativo são isolados em pools para que, se um falhar, os outros continuem a funcionar. Deve o seu nome às divisórias seccionadas (anteparas) do casco de um navio. Se o casco do navio ficar comprometido, apenas as secções danificadas se enchem com água, impedindo que o navio se afunde.
Contexto e problema
Um aplicativo baseado em nuvem pode incluir vários serviços, com cada serviço tendo um ou mais consumidores. Carga excessiva ou falha em um serviço afetará todos os consumidores do serviço.
Além disso, um consumidor pode enviar solicitações para vários serviços simultaneamente, usando recursos para cada solicitação. Quando o consumidor envia uma solicitação para um serviço que está configurado incorretamente ou não responde, os recursos usados pela solicitação do cliente podem não ser liberados em tempo hábil. À medida que as solicitações ao serviço continuam, esses recursos podem ser esgotados. Por exemplo, o pool de conexões do cliente pode estar esgotado. Nesse momento, os pedidos do consumidor para outros serviços são afetados. Eventualmente, o consumidor deixa de poder enviar pedidos para outros serviços, não apenas para o serviço original sem resposta.
O mesmo problema de esgotamento de recursos afetará os serviços com vários consumidores. Um grande número de solicitações originadas de um cliente pode esgotar os recursos disponíveis no serviço. Outros consumidores já não conseguem consumir o serviço, provocando um efeito de falhas em cascata.
Solução
Particione os serviços em diferentes grupos, com na base na carga do consumidor e nos requisitos de disponibilidade. Este design ajuda a isolar falhas e permite-lhe suportar a funcionalidade dos serviços para alguns consumidores, mesmo durante uma falha.
Um consumidor também pode particionar recursos para garantir que os recursos utilizados para chamar um serviço não afetam os recursos utilizados para chamar outro serviço. Por exemplo, um consumidor que chama vários serviços pode receber um pool de conexões para cada serviço. Se um serviço falhar, só afeta o conjunto de ligações para esse serviço, permitindo que o consumidor continue a utilizar os outros serviços.
As vantagens deste padrão incluem:
- Isola os consumidores e serviços de falhas em cascata. Um problema que afeta um consumidor ou serviço pode ser isolado dentro do seu próprio bulkhead, impedindo a falha total da aplicação.
- Permite-lhe preservar alguma funcionalidade em caso de falha de serviços. Outros serviços e funcionalidades da aplicação continuarão a funcionar.
- Permite-lhe implementar os serviços que oferecem uma qualidade diferente de serviço para aplicações de consumo. Um conjunto de consumidores de alta prioridade pode ser configurado para utilizar serviços de alta prioridade.
O diagrama seguinte mostra bulkheads estruturados em torno de conjuntos de ligações que chamam serviços individuais. Se o serviço A falhar ou provocar algum outro problema, o conjunto de ligações é isolado, pelo que apenas as cargas de trabalho que utilizam o conjunto de threads atribuído ao serviço A são afetadas. As cargas de trabalho que usam os Serviços B e C não são afetadas e podem continuar funcionando sem interrupção.
O diagrama seguinte mostra vários clientes a chamar um único serviço. Cada cliente tem atribuída uma instância de serviço separada. O Cliente 1 tem efetuado demasiados pedidos e sobrecarregou a respetiva instância. Uma vez que cada instância de serviço está isolada das outras, os outros clientes podem continuar a fazer chamadas.
Problemas e considerações
- Defina partições em torno do negócio e requisitos técnicos da aplicação.
- Se estiver usando DDD tático para projetar microsserviços, os limites de partição devem se alinhar com os contextos limitados.
- Ao particionar serviços ou consumidores em bulkheads, considere o nível de isolamento oferecido pela tecnologia, bem como a sobrecarga em termos de custo, desempenho e capacidade de gestão.
- Considere combinar bulkheads com a repetição, o disjuntor automático e padrões de limitação para fornecer um processamento de falhas mais sofisticado.
- Ao particionar consumidores em bulkheads, considere a utilização de processos, conjuntos de threads e semáforos. Projetos como resilience4j e Polly oferecem uma estrutura para a criação de anteparas de consumo.
- Ao particionar serviços em bulkheads, considere implementá-los em máquinas virtuais, contentores ou processos separados. Os contentores oferecem um bom equilíbrio de isolamento de recursos com sobrecarga consideravelmente baixa.
- Os serviços que comunicam por mensagens assíncronas podem ser isolados através de diferentes conjuntos de filas. Cada fila pode ter um conjunto dedicado de instâncias a processarem mensagens na fila, ou um único grupo de instâncias que utilizam um algoritmo para remover da fila e distribuir o processamento.
- Determine o nível de granularidade dos bulkheads. Por exemplo, se quiser distribuir locatários entre partições, você pode colocar cada locatário em uma partição separada ou colocar vários locatários em uma partição.
- Monitore o desempenho e o SLA de cada partição.
Quando utilizar este padrão
Utilize este padrão para:
- Isolar recursos usados para consumir um conjunto de serviços de back-end, especialmente se o aplicativo puder fornecer algum nível de funcionalidade mesmo quando um dos serviços não estiver respondendo.
- Isolar consumidores críticos de consumidores padrão.
- Proteger a aplicação contra falhas em cascata.
Este padrão pode não ser adequado quando:
- Uma utilização menos eficiente dos recursos pode não ser aceitável no projeto.
- A complexidade adicional não é necessária
Design da carga de trabalho
Um arquiteto deve avaliar como o padrão Bulkhead pode ser usado no design de sua carga de trabalho para abordar as metas e os princípios abordados nos pilares do Azure Well-Architected Framework. Por exemplo:
| Pilar | Como esse padrão suporta os objetivos do pilar |
|---|---|
| As decisões de projeto de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e a garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | A estratégia de isolamento de falhas introduzida através da segmentação intencional e completa entre componentes tenta conter falhas apenas na antepara que está enfrentando o problema, evitando o impacto em outras anteparas. - RE:02 Fluxos críticos - RE:07 Autopreservação |
| As decisões de design de segurança ajudam a garantir a confidencialidade, integridade e disponibilidade dos dados e sistemas da sua carga de trabalho. | A segmentação entre componentes ajuda a restringir os incidentes de segurança à antepara comprometida. - SE:04 Segmentação |
| A Eficiência de Desempenho ajuda sua carga de trabalho a atender às demandas de forma eficiente por meio de otimizações em escala, dados e código. | Cada antepara pode ser dimensionada individualmente para atender de forma eficiente às necessidades da tarefa encapsulada na antepara. - PE:02 Planeamento da capacidade - PE:05 Dimensionamento e particionamento |
Como em qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com esse padrão.
Exemplo
O ficheiro de configuração Kubernetes seguinte cria um contentor isolado para executar um único serviço, com os seus próprios recursos e limites de CPU e memória.
apiVersion: v1
kind: Pod
metadata:
name: drone-management
spec:
containers:
- name: drone-management-container
image: drone-service
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "1"