RabbitMQ CookBook

Oggi è uscito RabbitMQ Cookbook, un libro che ho scritto insieme al mio amico e collega Sigismondo. Risultato di 13 mesi di lavoro e ricerca sul middleware RabbitMQ, il libro contiene moltissimi esempi pratici correlati di codice sorgente.

6501OS_RabbitMQ-Cookbook

 

Nel libro si parla di scalabilità, integrazione, cloud computing (IaaS e PaaS), mobile e web application.

Link del libro:

Packtpub

Amazon

Configurazione di un’istanza Amazon Ec2

Oggi ho pubblicato il seguente post sul blog indigeni digitali:
http://blog.indigenidigitali.com/amazon-ec2/

In questo post viene descritto:

  1. Come configurare un’istanza Amazon Ec2 da zero.
  2. Come reperire istanze configurate dal sito bitnami.org
  3. Considerazioni sul risparmio economico che un Cloud può offrire.

Amazon SQS

In questi giorni ho effettuato un po’ di test utilizzando Simple Queue Service (Amazon SQS), che a mio avviso é un servizio eccezionale!
Ho trovato interessante il fatto che SQS è stato uno dei primi servizi che amazon ha realizzato per scalare i propri server.
Questo post è un approfondimento dell’articolo “Message-Oriented Middleware capitolo  II
, dove sto sperimentado i servizi  di Amazon per bilanciare richieste complesse sui server.
Il test simula le richieste di un acquisto on-line, dove gli ordini vengono salvati in una coda SQS ed in seguito rielaborati.

Il codice è stato sviluppato in Java con l’sdk di Amazon(http://aws.amazon.com/sdkforjava/).
L’account di Amazon usato è di tipo  “AWS Free Usage Tier” (http://aws.amazon.com/free/) .Il test si divide in due fasi:
  1. Invio del messaggio sul cloud.
  2. Ricezione ed elaborazione del messaggio dal cloud.

1. INVIO DEL MESSAGGIO
Il messaggio, proveniente da un webserver, viene preso in consegna e rediretto verso una coda SQS, di seguito un pezzo di codice in java per l’invio del messaggio.

Class SQS{

xml message String xmlexample = "<Order> <iduser>XYZ</iduser> <idoperation>555555</idoperation> <mailoperation>mail@mailmail.com</mailoperation> <bookid>5556677999</bookid> </Order>";

ThreadPoolExecutor poolexc = new ThreadPoolExecutor(10, 10, 50000L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue()); for (int j = 0; j < 500; j++) {     poolexc.execute(new Task(j+xmlexample,j)); }
poolexc.shutdown();

Task Class
public void run()
{
queue us-east String myQueueUrl ="https://sqs.us-east-1.amazonaws.com/44444/queue-1";//
try {
request SendMessageRequest sq = new SendMessageRequest(myQueueUrl,_xml); /// send message sqs.sendMessage(sq);
.....

La classe SQS simula un carico di 500 richieste di un xml (lungo 143) con un ThreadPoolExecutor di 10 elementi, quindi la responsabilità del modulo Request.Aumentando il numero di task sul ThreadPoolExecutor si aumenta il throughput, ovviamente il numero task va deciso in base ai server e al tipo di connessione. Un valore troppo elevato potrebbe avere l’effetto contrario.

Eseguendo il test dalla mia normalissima connessione di casa ho avuto i seguenti risultati:

****** Start Request Time:2011-04-26 17:06:16:616

****** End Request 499 at 17:06:28:919  (post ultimo messaggio )

(circa 41 messaggi al secondo).
Ho provato lo stesso JAR su una istanza MICRO EC2 (debian) ed ho ripetuto il test avendo i seguenti risultati:
XMLExample len:143

****** Start Request :2011-04-26 15:15:38:1538

****** End Request  task 499 at 15:15:40:832  (post ultimo messaggio )

(circa 250 messaggi al secondo).

Ovviamente sull’istanza EC2 è molto più veloce.

Il throughput non è elevatissimo ma, considerando tutte le garanzie offerte dal servizio, direi che é ottimo. N.B. Le performance indicate non possono essere prese come riferimento, ma solo come indicazione.

2. RICEZIONE DEL MESSAGGIO

Per ricevere i messaggi dalla coda bisogna effettuare un pool di lettura.

Il modulo Elab a tempo controlla se ci sono messaggi, di seguito un pezzo di codice per la ricezione del messaggio:

ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
message receiveMessageRequest.setMaxNumberOfMessages(10);
List messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
if (messages.size()>0)
{ for (Message message : messages) {
elabmessage(message )
String messageRecieptHandle = message.getReceiptHandle(); sqs.deleteMessage(new DeleteMessageRequest(myQueueUrl, messageRecieptHandle))
};

Quando il server è scarico può ricevere il messaggio elaborarlo e cancellarlo.

Invio e ricezione completati.

Note:
SQS di default salva il messaggio per 4 giorni, volendo si può estendere a 2 settimane, ma l’idea è che il messaggio dovrebbe essere processato subito.
Un messaggio può essere al massimo di 64k, per informazioni più grandi bisogna utilizzare altre tecniche.
Data la natura distribuita del sistema, SQS non garantisce la sequenzialità dei messaggi.
Ogni volta che un messaggio viene preso in consegna è opportuno cancellarlo.

Conclusioni

Amazon SQS è un ottimo servizio a messaggi che può essere usato sia sui server che sui dispositivi mobile.
Come tutti i servizi Amazon ci sono a disposizione varie regions da poter utilizzare , quindi c’è la garanzia di continuità è decisamente elevata.

In questo esempio non c’è un throughput elevatissimo (specialmente dalla mia rete ), ma l’idea è che il redirect sul cloud deve essere fatto solo dei messaggi ritenuti importanti, quindi se riesci a vendere 250 libri al secondo per tutto l’anno puoi anche permetterti delle istanze più grandi e linee più veloci :)!!

SQS ha un costo che, secondo me, se hai un bel business è trascurabile. Studiando i casi d’uso di amazon c’è chi ha installato un broker ( es:RabbitMQ,ActiveMQ eccc) su delle istanze EC2. Questa soluzione può aumentare le performance e diminuire i costi, ma il cluster dei broker non è più gestito da Amazon, per cui possono aumentare i punti di failover.

Su una istanza EC2 sto provando FuseMessageBroker basato su ActiveMQ.

SNS e SQS in Amazon cloud

Da appasiontato di sistemi messaggistica ho iniziato lo studio del cloud amazon partendo dai servizi :
Amazon Simple Notification Service (Amazon SNS) e Amazon Simple Queue Service (Amazon SQS).Entrambi sono sistemi di messaggistica ma con ruoli diversi, SQS è un sistema a code dove il producer invia un messaggio , messaggio che può essere ricevuto anche in un secondo momento dal consumer. SNS è un publish/subscribe di tipo uno a molti, un messaggio può essere inviato a più consumer contemporaneamente.In breve il mio esperimento è stato il seguente:

  1. Ho creato un topic SNS dalla console da AWS manager console.
  2. Ho creato una serie di sottoscrittori di tipo MAIL,HTTP e SQS.
  3. Ho inviato un messaggio dalla console dalla AWS console.

Ovviamente il test è andato a buon fine, tutti i sottoscrittori hanno ricevuto il messaggio con tecniche diverse:

  1. Sottoscrittore MAIL:  SNS invia una mail con il testo del messaggio.
  2. Sottoscrittore HTTP:  SNS invia una POST sul link del sottoscrittore inserito.
  3. Sottoscrittore SQS:  SNS posta il messaggio in coda, in seguito il consumer ( nel mio caso in Java)  riceve il messaggio lo elabora e lo cancella dalla coda.
Sono rimasto piacevolmente colpito da questi servizi, gli scenari che si possono comprire sono davvero tantissimi, si pensi che una  coda SQS può essere utlizzata sia in un server che in un dispositivo mobile.A breve riporterò l’esempio completo spep by spep.

ActiveMQ MapMessage

Hiram Chirino, Logo for Apache ActiveMQ, http:...

Hiram Chirino, Logo for Apache ActiveMQ, http://activemq.apache.org/ Released under the Apache Software License 2.0 (Photo credit: Wikipedia)

In molti esempi di ActiveMQ si fa riferimento sempre ad uno scambio di messaggi piuttosto semplice, come ad esempio stringhe.

Se c’è bisogno di scambiare strutture più complesse ci sono vari tipi di messaggi, a me è piaciuto molto il MapMessage.

Il MapMessage non è altro che una mappa di Chiave-Valore dove ogni attributo può essere tipizzato.
Ad esempio:

mymap.setString("name","Gabriele");
mymap.setint("foo",3);

Questo approccio  è molto utile perché evita la scrittura di un protocollo all’interno dei messaggi, inoltre garantisce  l’indipendenza ai moduli interessati.

Ad Esempio:
Client c#

MyMapMessage.SetString("name", "gabriele");
MyMapMessage.SetString("surname","Santomaggio");
producer.Send(MyMapMessage);


Server Java:
public void onMessage(Message message) {
string name = ((MapMessage)message).getString("name");
string Surname = ((MapMessage)message).getString("surname");
}

Se varia della mappa del client, ad esempio:

MyMapMessage.SetString("name", "gabriele");
MyMapMessage.SetString("surname","Santomaggio");
MyMapMessage.Setint("newfield",55);

Il  server può non essere aggiornato, perché nel peggiore dei casi non gestisce il nuovo campo “newfield”.
Questo dettaglio è molto importante in presenza di un numero elevato di moduli e di server, oltre a  garantire  un forte disaccoppiamento tra i moduli ed una certa tranquillità in fase di aggiornamento, che non guasta :))!!!.

La mappa mette a disposizione una serie di tipi primitivi es: String , double, short, ecc che risolvono  problemi legati alla conversione di tipi tra diversi linguaggi di programmazione.

Active MQ Cluster

Hiram Chirino, Logo for Apache ActiveMQ, http:...

Image via Wikipedia

Quale modo migliore di festeggiare l’inizio anno con un test di Active MQ, uno dei tanti modi di usare il cluster.

Failover:

Questo test è stato davvero molto semplice, ho tirato su due broker su due macchine diverse, in fase di connessione ho specificato gli ip dei broker.

[java code]
private static String brokerURL = “failover://tcp://localhost:61616,tcp://172.16.65.132:61616”;
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
Connection connection = factory.createConnection();
connection.start();
[end code]

Durante il test ho provato a pubblicare dei messaggi su una coda, fermando il primo broker i messaggi sono stati dirottati verso il secondo. Fermando il secondo i dati sono stati dirottati verso il primo.

Fantastico, senza fare praticamente niente ho realizzato un piccolo cluster ad alta affidabilità. Ovviamente, i parametri di configurazione di failover sono tanti, ma il mio obiettivo è sempre quello di partire dalla situazione più semplice, specialmente in fase di studio.

Rif :http://fusesource.com/products/enterprise-activemq/#documentation

Active MQ Start

Hiram Chirino, Logo for Apache ActiveMQ, http:...

Image via Wikipedia

In questi giorni sto studiando un po’ ActiveMQ di  Apache Software Foundation (JMS 1.1 compliant).
Alla versione 5.4.2 è tra i broker (MOM) più “vecchi” e consolidati sul mercato. Personalmente non l’ho mai usato in produzione, ma vedendo la documentazione ed il suo utilizzo di sicuro é uno strumento interessante e molto potente.
La cosa che mi ha stupito di questo prodotto è la facilità di startup e la possibilità di gestire scenari semplici  e scenari complessi  con configurazione cluster , failover, load balance sotto nodi ecc ecc ecc.

Il broker inoltre supporta moltissimi client: http://activemq.apache.org/connectivity.html quindi l’interazione tra diversi linguaggi di programmazione è piuttosto semplice.
La mia filosofia è di non perdersi troppo in spiegazioni, ma partire subito con qualcosa di concreto.
Let’s go…
Per tutti gli esempi ho preso come riferimento:
http://fusesource.com/products/enterprise-activemq/ un broker basato su Activemq.

Primo step – start broker:Far partire il broker è molto semplice:..

sudo ./activemq start
Starting ActiveMQ Broker…

per controllare lo stato:…
sudo ./activemq status
ActiveMQ Broker is running (769).

Per fermare il tutto:…  sudo ./activemq stop
Stopping ActiveMQ Broker..
Stopped ActiveMQ Broker.

Sull’indirizzo http://localhost:8161/ c’è la console web, http://localhost:8161/demo/ sono presenti alcuni demo molto carini. Sul file system c’è bin\activemq-admin che espone funzionalità amministrative a riga di comando.

Secondo Step -Connessione al broker.
Per connettersi al broker ci sono vari modi, vediamo il primo molto semplice:
[java code]
/// init connection
ConnectionFactory factory = new ActiveMQConnectionFactory(“tcp://localhost:61616”);
Connection connection = factory.createConnection();
connection.start();
Connessione al broker effettuata..

Terzo Step -Disconnessione dal broker.
connection.close();
Disconnessione dal broker…..

Primo capitolo terminato, in questo primo capitolo abbiamo fatto partire il broker, controllato il suo stato , abbiamo visto la console web, ed un piccolo esempio di connessione e disconnessione in java.

Message-Oriented middleware (MOM)

“Enterprise messaging software has been in existence since the late 1980s. Not only is messaging a style of communication between application, it is also a style of integration”

Si legge su “Active MQ in Action”, dove in 2 righe racchiude tutto il senso dei sistemi bastati su messaggi.

Moltissima documentazione si trova in rete sui Message-Oriented middleware detti MOM, tra wikipedia , google, slideshare,ecc…quindi evito discorsi tecnici troppo lunghi e noiosi e vi delizio solo delle mie impressioni:))!!!!.

Perché MOM e non RPC?

I  sistemi bastati su RPC sincroni hanno dei grandi limiti di fronte alla continua necessità di distribuzione  dati e  iterazione fra moduli eterogenei . I MOM nascono per superare questi limiti, ponendo fra i moduli un “broker”e gestendo la comunicazione a messaggi in modo asincrono, disaccoppiando di fatto le responsabilità tra i moduli .

Facciamo un esempio pratico:
Diciamo che  un modulo A  invia dei dati ad un modulo B che riceve  i dati e li inserisce in un DB.
Vediamo nelle 2 modalità:
Sync RPC:
ModuloA -> Connect(“ModuloB.ip”);
ModuloA ->ExecRemoteProcedureOnMobuleB(Buffer[]); <<—– Il moduloA a questo punto è bloccato
ModuloB->SendAck() ;
ModuloA <<<<— Il modulo A a questo punto è disponibile per un’altra operazione.

Async MOM
ModuloA -> Connect(“MOM.ip”);
ModuloB -> Connect(“MOM.ip”);
ModuloA -> Publish(Buffer[]); <<—- Invia il messaggio ed è subito disponibile
ModuloB->OnReceivedData->InsertBuffIntoDB(Buffer[]);
ModuloB->SendAck() ;

Come si  può vedere dall’esempio le differenze sostanziali sono 2:

  1. Nel caso RCP il moduloA si connette direttamente al ModuloB, mentre nel caso MOM entrambi si connettono ad un broker.
  2. Nel caso RCP il ModuloA rimane bloccato finché il ModuloB non termina l’operazione, mentre nel caso MOM il ModuloA invia un messaggio sul MOM e torna subito disponibile, il ModuloB riceve il dato e lo elabora in modo autonomo.

Si capisce quindi l’oggettivo guadagno del caso MOM, i moduli lavorano in modo indipendente tutte le operazioni vengono gestite dal broker attraverso delle “code” (concetto che in seguito approfondiremo) .
La cosa che mi ha subito colpito, nell’uso dei broker, è la semplicità con la quale creare un loadbalancer tra i Moduli.
Complichiamo l’esempio , per capire meglio:
Diciamo che il ModuloA invia i dati molto  velocemente ed il  ModuloB non riesce a “smaltire” tutte le richieste. Quindi bisogna aggiungere un altro ModuloB1 in modo da bilanciare le chiamante.
Vediamo nei 2 casi:

  1. Sync RCP , il ModuloA deve fare round robin tra i due moduli, in modo bilanciare l’invio dei dati sui due ModuliB.
  2. Async MOM , il Modulo A non deve fare niente, basta aggiungere il ModuloB1 e connetterlo al broker ed automaticamente i dati vengono bilanciati.

L’indipendenza dei moduli, nel II° caso, fa sì che che chi invia i dati ( spesso detto Producer) non conosce l’esatta collocazione di chi li riceve e li elabora ( spesso detto Consumer). Questa caratteristica, secondo me, è la chiave per realizzare un sistema scalabile molto molto facilmente senza troppe complicazioni “sistemistiche”.

Nel pochissimo tempo libero che ho  vorrei scrivere un semplice  sistema di LOG asincrono con linguaggi diversi, non tanto perché il mondo ne ha bisogno ma solo a scopo “didattico”.

Il tutto lo troverete su github.com/Gsantomaggio/AsyncLog dove per il momento è vuoto …ma confido in breve tempo di mettere su qualcosa.

Mentre ascolto Led Zeppelin Remasters Vol I , penso a come sviluppare il mio fantastico sistema di log asincrono, penso che utilizzerò  RabbitMQ oppure ActiveMQ come middleware e   MongoDB oppure CouchDB come database.

..to be continued….