Scegliere lo stile architetturale: monolite, N-tier o microservices

In AZ-305 il punto non è “quale stile è migliore in assoluto”, ma quale stile è coerente con i requisiti di rilascio, scalabilità e affidabilità del carico. Un monolite su Azure App Service resta la scelta corretta quando il team è piccolo, il dominio è semplice e il deploy unico non è un collo di bottiglia: massimizza il pilastro Operational Excellence (una sola pipeline, un solo artefatto) e minimizza i costi. L’architettura N-tier (web, business, data separati) è appropriata per applicazioni line-of-business tradizionali con confini chiari fra presentazione e persistenza, spesso migrate “as-is” verso PaaS.

I microservices vanno raccomandati solo quando esiste un driver concreto: scalabilità indipendente di componenti con profili di carico divergenti, rilasci indipendenti per team autonomi, o isolamento dei guasti. In cambio si paga complessità operativa. La domanda d’esame giusta è sempre: il requisito giustifica il costo di frammentazione?

Isolamento e piattaforma di hosting

Il confronto ricorrente riguarda dove eseguire i servizi:

  • Azure App Service (multi-tenant): ottimo per web app e API stateless, con scaling e slot di deployment gestiti. Prima scelta se non servono requisiti di isolamento di rete stringenti.
  • App Service Environment (ASE v3): raccomandato quando il requisito è isolamento di rete dedicato, integrazione in VNet single-tenant, compliance o carichi ad alto throughput. Non sceglierlo “per default”: aumenta costo e complessità.
  • Azure Kubernetes Service (AKS): indicato per orchestrazione di container su larga scala, controllo fine su networking/scheduling e portabilità. Comporta la responsabilità di gestire cluster, upgrade e osservabilità.
  • Azure Container Apps: opzione serverless per microservizi containerizzati con scale-to-zero e Dapr integrato, quando non serve il controllo completo di Kubernetes. Spesso la risposta “giusta” quando il requisito è “microservizi senza gestire un cluster”.

Regola pratica d’esame: se lo scenario dice “isolamento di rete + PaaS gestito” → ASE; “serverless event-driven a microservizi” → Container Apps; “controllo cluster / ecosistema Kubernetes esistente” → AKS.

Statelessness e scaling

Il pilastro Reliability del Azure Well-Architected Framework richiede componenti stateless: lo stato di sessione va esternalizzato (Azure Cache for Redis, database, storage) affinché qualsiasi istanza gestisca qualsiasi richiesta e lo scale-out orizzontale sia possibile. Preferire lo scale-out (più istanze) allo scale-up (istanza più grande) per resilienza e per superare i limiti di una singola macchina. Distribuire le istanze su Availability Zones per proteggersi dai guasti di datacenter.

Pattern di resilienza

Nelle comunicazioni distribuite i guasti transitori sono la norma, non l’eccezione:

  • Retry con exponential backoff + jitter: per errori transitori, evitando ondate sincronizzate di ritentativi.
  • Circuit breaker: interrompe le chiamate verso un servizio in degrado, evitando di saturare risorse e propagare il guasto (fondamentale contro i cascading failure).
  • Bulkhead: isola pool di risorse (connessioni, thread) per servizio, così che il collasso di una dipendenza non affami le altre.

Retry e circuit breaker sono complementari: il retry gestisce il guasto breve, il circuit breaker protegge dal guasto prolungato. Delegare questa logica a un service mesh o a Dapr riduce il codice boilerplate.

Il trade-off centrale: flessibilità vs complessità

I microservizi danno agilità di rilascio e scaling mirato, ma introducono osservabilità distribuita come requisito non negoziabile: distributed tracing (Application Insights / OpenTelemetry), correlazione delle richieste e health probe. Senza questo, il debugging diventa impraticabile. Valutare sempre l’impatto sul pilastro Cost Optimization: più servizi significano più superficie operativa, più networking e più overhead.

Trappole tipiche d’esame

  • Requisito: microservizi con deploy indipendenti, ma i servizi condividono lo stesso database e si rilasciano insieme → è un distributed monolith: raccomanda database-per-service e confini di dominio ben definiti, altrimenti resta un monolite più fragile.
  • Requisito: latenza elevata per pagina che aggrega dati da molti servizi → sintomo di chatty inter-service communication: raccomanda pattern Gateway Aggregation / BFF o eventi asincroni, riducendo le chiamate sincrone a catena.
  • Requisito: app PaaS che deve risiedere in una VNet isolata con compliance → non basta App Service con VNet integration: raccomanda App Service Environment v3.
  • Requisito: un servizio downstream lento sta saturando l’intera app → applica circuit breaker + bulkhead; il solo retry aggraverebbe la saturazione.
  • Requisito: scaling indipendente di un solo componente ad alto carico su un monolite → non frammentare tutto: estrai solo il componente critico come servizio separato (strangler pattern incrementale).