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
| Componente | ActiveMQ Classic | ActiveMQ Artemis |
| I/O Layer | Sincrono (BIO) o NIO custom | Completamente asincrono tramite Netty |
| Modello Interno | JMS-centric (Destinations native) | Address-based (Address → Queues) |
| Routing | Basato su tipi di destinazione | Anycast (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
| Caratteristica | ActiveMQ (Artemis) | RabbitMQ | Apache Kafka |
| Throughput | Migliaia msg/s | Migliaia msg/s | Milioni msg/s |
| Latenza | Molto bassa (NIO/Netty) | Ultra-bassa | Moderata (batch-centric) |
| Persistenza | Distruttiva (dopo ACK) | Distruttiva (dopo ACK) | Log-based (immutabile) |
| Ordering | Garantito per coda | Garantito per coda | Garantito per partizione |
| Supporto XA | Nativo/Completo | Limitato | Non-standard |