in Architettura Software, Informatica

ActiveMQ: Analisi Tecnica e Architetturale

Apache ActiveMQ è un broker di messaggi multiprotocollo basato su Java, progettato per il disaccoppiamento asincrono tramite lo standard JMS (Java Message Service) e protocolli enterprise. Esistono due rami attivi: ActiveMQ Classic (architettura tradizionale basata su thread) e ActiveMQ Artemis (architettura asincrona non-blocking).

1. Architettura del Core e Modelli di Routing

Il broker funge da intermediario tra producers e consumers, gestendo il ciclo di vita dei messaggi tramite due modelli principali:

  • Punto-Punto (Queues): Implementa la semantica “exactly-one consumer”. Il broker bilancia il carico tra i consumatori collegati; se nessun consumatore è attivo, il messaggio viene persistito.
  • Pubblica-Sottoscrivi (Topics): Implementa la semantica broadcast. In modalità standard, i messaggi sono volatili e recapitati solo ai sottoscrittori attivi. Le Durable Subscriptions permettono la persistenza dei messaggi per sottoscrittori offline.

Differenze Classic vs Artemis

ComponenteActiveMQ ClassicActiveMQ Artemis
I/O LayerSincrono (BIO) o NIO custom Completamente asincrono tramite Netty
Modello InternoJMS-centric (Destinations native) Address-based (Address → Queues)
RoutingBasato su tipi di destinazioneAnycast (P2P) o Multicast (Pub/Sub)

In Artemis, ogni sottoscrittore di un indirizzo multicast riceve una propria coda interna, eliminando la distinzione rigida tra Topic e Queue a livello di kernel del broker.

2. Meccanismi di Persistenza e Storage

Il broker garantisce la durabilità tramite motori di storage pluggabili.

  • KahaDB (Classic): Utilizza un Journal (file append-only per velocità di scrittura sequenziale) integrato con un indice B-Tree per il recupero rapido dei messaggi non consumati.
  • Artemis Journal: Progettato per minimizzare le operazioni di random access. Il journal è gestito interamente in memoria per il dispatching attivo. Se la memoria è satura, Artemis attiva il Paging sul lato produttore, scrivendo i messaggi in file sequenziali prima che entrino nel journal principale.
  • JDBC Support: Entrambe le versioni supportano database SQL (PostgreSQL, MySQL) per la persistenza, a scapito del throughput a causa dell’overhead dei lock di riga.

3. Gestione del Flusso e Trasporto

Astrazione del Trasporto

ActiveMQ implementa il Command Pattern distribuito: client e broker scambiano oggetti “Command” (messaggi, ack, transazioni) tramite un TransportChannel.

  • WireFormats: I comandi vengono serializzati tramite plug-in WireFormat. OpenWire è il formato binario nativo più efficiente per client Java. Sono supportati AMQP, STOMP, MQTT e WebSocket.

Producer Flow Control

Quando il broker rileva il superamento dei limiti di memoria (memoryLimit) o di storage, rallenta i produttori sincroni o blocca temporaneamente il trasporto. Per i produttori asincroni (non-persistent), è necessario configurare la ProducerWindowSize per forzare l’attesa di un acknowledgement dal broker dopo un volume prefissato di dati.

4. Alta Disponibilità e Scalabilità

Master-Slave (High Availability)

  • Shared Storage: Più broker puntano allo stesso storage (NFS, SAN, JDBC). Il lock esclusivo determina il Master; il failover è gestito dal client tramite URI failover://(tcp://master:61616,tcp://slave:61616).
  • ZooKeeper Replicated: Utilizzato in configurazioni dove i dati sono replicati tra i nodi (Artemis utilizza quorum basati su replicazione nativa o ZooKeeper).

Network of Brokers (Scalability)

Consente la scalabilità orizzontale collegando più broker in una topologia mesh o hub-and-spoke. I messaggi vengono inoltrati tramite bridge “store-and-forward” solo se è presente un consumatore attivo su un broker remoto della rete.

5. Parametri di Performance Tuning

  • Prefetch Policy: Determina quanti messaggi il broker invia al consumatore prima di attendere un ACK. Valori alti massimizzano il throughput; valori bassi (es. 1) garantiscono un bilanciamento equo tra consumatori con tempi di elaborazione variabili.
  • Optimized Acknowledge: Permette l’invio di ACK in batch (solitamente al 65% del buffer di prefetch), riducendo il traffico di rete e il carico sul broker.
  • Transazioni XA: Supporta transazioni distribuite (Two-Phase Commit) tra ActiveMQ e risorse esterne (DB). L’uso di transazioni in batch è tecnicamente più veloce della modalità individuale “persistent sync” poiché aggrega le sincronizzazioni su disco.

6. Analisi Comparativa: Performance e Semantica

CaratteristicaActiveMQ (Artemis)RabbitMQApache Kafka
ThroughputMigliaia msg/s Migliaia msg/s Milioni msg/s
LatenzaMolto bassa (NIO/Netty)Ultra-bassa Moderata (batch-centric)
PersistenzaDistruttiva (dopo ACK)Distruttiva (dopo ACK)Log-based (immutabile)
OrderingGarantito per codaGarantito per codaGarantito per partizione
Supporto XANativo/Completo LimitatoNon-standard