ARCHITETTURE CLIENT SERVER

Prima di affrontare l’argomento “Python e RabbitMQ” parliamo un po’ di architetture introducendo il modello client-server e le architetture distribuite.

IL CLIENT

Il software client in genere è di limitata complessità, limitandosi normalmente ad operare come interfaccia verso il server. In generale nel campo informatico il termine client indica una componente che accede ai servizi o alle risorse di un’altra componente, detta server. In questo contesto si può quindi parlare di client riferendosi all’hardware o al software. Un computer collegato ad un server tramite rete locale o geografica, ed al quale richiede uno o più servizi, utilizzando uno o più protocolli di rete è un esempio di client hardware. Un programma di posta elettronica è un esempio di client software.

SOFTWARE DIVISI IN UNA PARTE CLIENT E UNA PARTE SERVER

Sono sempre di più i software, come il web, l’e-mail, i database, che sono divisi in una parte client (residente ed in esecuzione sul pc client) e una parte server (residente ed in esecuzione sul server). Il termine client indica anche il software usato sul computer client per accedere alle funzionalità offerte dal server. Ad esempio, nel web il software client è il web browser, e parla con un server web attraverso il protocollo HTTP; per l’e-mail il client è detto in gergo mail user agent o MUA (ad esempio, Outlook, Mozilla Thunderbird, Eudora, …), e parla con il server (Mail Transfer Agent o MTA) attraverso i protocollo SMTP e POP o IMAP; il client per la consultazione o la modifica del database (spesso costituito da librerie software utilizzate da un’applicazione) parla con il DBMS, che gestisce il database e risponde alle interrogazioni del client.

SERVER

Il software server, oltre alla gestione logica del sistema, deve implementare tutte le tecniche di gestione degli accessi, allocazione e rilascio delle risorse, condivisione e sicurezza dei dati o delle risorse. Ad esempio un server di posta elettronica è paragonabile ad un qualunque ufficio postale. Gli utilizzatori per accedere via client alla loro cassetta di posta elettronica devono essere stati autorizzati. In modo analogo un utente deve possedere la chiave della cassetta situata presso un ufficio postale dalla quale vuole prelevare la corrispondenza.

Client-server_model

STRUTTURA DI UNA WEB APPLICATION

Request Response

La figura riporta la struttura di una web application in cui il client è un Browser che si collega al server locale o remoto. Sul server gira un web server. In una architettura come questa semplificando c’è una prima fase in cui il client genera la Request che invia al server. Il server la elabora se necessario accede a un database per fornire i dati richiesti e la restituisce al client sotto forma di Response. La risposta potrebbe essere una pagina web, un messaggi in formato Json, Xml o un’immagine etc.

ARCHITETTURE DISTRIBUITE

Nelle architetture distribuite vi è un Producer che produce una certa informazione e delle applicazioni che sono interessate a consumare i dati prodotti e che vengono chiamati Consumer. L’applicazione Producer notifica la propria informazione quando questa si rende disponibile attraverso un messaggio che contiene l’informazione che può essere testuale, in formato json, xml etc.

Producer Consumer

Vi sono tre caratteristiche essenziali affinché si possa parlare di architettura distribuita che sono:

  • Nel momento in cui l’applicazione produce un messaggio non è detto che il consumer sia disponibile, in altre parole l’applicazione che deve ricevere il messaggio potrebbe non essere attiva nel momento in cui questo viene prodotto. Non per questo il messaggio deve andare perduto.
Producer Consumer
  • Seconda considerazione, il consumer potrebbe essere più di uno, cioè lo stesso messaggio potrebbe dover essere consegnato ad un certo numero di Consumer, anche molto alto, non necessariamente tutti disponibili all’atto della pubblicazione del messaggio.
Producer Consumer
  • Il Producer non deve mai essere a conoscenza di quali sono e quanti sono i Consumer, in modo tale da produrre un forte disaccoppiamento tra produttori e consumatori.
Producer Consumer

PYTHON E RABBITMQ – IL MESSAGE BROKER

Proprio per disaccoppiare Producer e Consumer viene introdotta una terza applicazione che si interpone tra i due in modo tale da produrre un forte disaccoppiamento. Il message broker è un’applicazione server, quindi installato su un server che normalmente non è il server che contiene il Producer, né il server che contiene i Consumer. Ha il compito di fare da intermediario tra i Producer e i Consumer. Può essere configurato in modo che mantenga i messaggi in modo indeterminato, così se un Consumer in un certo momento non è collegato comunque può ricevere il messaggio dal message broker quando si collega. Un message broker può essere configurato con delle regole di instradamento anche molto sofisticate, per instradare il messaggio anche a consumer differenti.

Message Broker

Sul mercato esistono vari tipi di message broker, sicuramente il più famoso è RabbitMQ un prodotto open source ed è quello che utilizzeremo per la nostra applicazione di esempio. Dispone di driver per un elevato numero di linguaggi di programmazione tra cui Python.  

RabbitMQ

PYTHON E RABBITMQ – INSTALLAZIONE DI RABBITMQ

Recarsi all’indirizzo www.rabbitmq.com

RabbitMQ site
  • Selezionare la scheda Get Started e successivamente Download + Installation.
  • Scegliere la versione per il proprio sistema operativo. 
  • Mettere in esecuzione Rabbit.
Installazione RabbitMQ

INSTALLIAMO PIKA LA LIBRERIA PYTHON PER RABBIT

Aprire di nuovo il sito di RabbitMQ e selezionare Download + Installation. Recarsi nella Client Library.

Install Pika
Install Pika

Per installare pika utilizzeremo la linea di comando. Affinché il terminale riconosca il comando pip3 è necessario registrare il percorso Scripts, situato in una sotto directory della cartella in cui è installato Python10, nella variabile di sistema Path. Riavviare il sistema. Se vuoi essere sicuro che l’installazione di pika sia andata a buon fine apri il terminale e fai un import del package pika.

Install pika
Cartella scripts

RABBITMQ ARCHITETTURA DI UN MESSAGE BROKER

Architettura RabbitMQ

Dal punto di vista del consumatore Rabbit ci mette a disposizione la possibilità di creare delle code. Le code sono come una sorta di casella postale in cui vengono depositati i messaggi per poi inoltrarli al/ai Consumer quando il messaggio si rende disponibile. Per ogni Consumer è necessario stabilire quale coda utilizzerà per poter fruire dei messaggi inviati dal Broker quando disponibili. All’estremo opposto, cioè mettendoci dalla parte del Producer ci sono gli Exchange. Essi sono il punto di ingresso a Rabbit e permettono ai Producer di consegnare i propri messaggi. Infine ci sono i Binding cioè delle regole configurate all’interno del message Broker per collegare gli Exchange con le Code. Attraverso il Binding i Producer e i Consumer sono completamente disaccoppiati.

CONNESSIONE A RABBITMQ

La prima cosa è stabilire una Connection, una volta stabilita la connessione possiamo richiedere un canale di comunicazione che attraverso la connessione ci permette di arrivare al Message Broker. Una singola connessione può ospitare più canali di comunicazione. Più applicazioni possono usare la stessa connessione e canali diversi.

Connection e Channel

Normalmente questa configurazione viene utilizzata per distribuire il carico di lavoro di una serie magari enorme di messaggi a n Consumer tutti collegati alla stessa coda. L’elaborazione avviene in parallelo. Connettendo tutti i consumer ad una unica coda Rabbit smisterà il primo messaggio al primo consumer, il secondo messaggio al secondo consumer il terzo al terzo e così via ripetendo sempre il ciclo. Questo meccanismo viene chiamato Round-Robin e consente di realizzare applicazioni estremamente scalabili in quanto i Consumer lavorano in parallelo.

Producer e Worker
import pika
print('Collegamento a RabbitMQ......')
params = pika.ConnectionParameters(host='localhost')#PARAMETRI DA PASSARE ALLA CONNESSIONE
connections=pika.BlockingConnection(params)#CONNESSIONE A RABBITMQ
channel = connections.channel() #OTTENGO IL CANALE 
channel.queue_declare(queue='worker_queue')#CODA CHE USERANNO I CONSUMER O WORKER

print('Eseguito......')
#INVIAMO AL BROKER 100.000 MESSAGGI IN RAPIDA SEUQENZA
i=0
while True:
    message = str(i)
    i+=1
    #DOBBIAMO PUBBLICARE IL MESSAGGIO SULLA EXCHANGE
    #LA routing_key E' LA DEFINIZIONE DEL BINDING
    #CHIEDIAMO ALL'EXCHANGE DI PUBBLICARE TUTTO QUELLO CHE 
    #ARRIVA SU UNA CODA LA worker_queue GIA' DEFINITA
    channel.basic_publish(exchange='',routing_key='worker_queue',body=message)
    print(f'Inviato messaggio {message}')
    if i > 100_000:
        break
#CHIUSURA DELLA CONNESSIONE A RABBITMQ 
connections.close()
import pika
#LA FASE DI CONNESSIONE E' LA STESSA VISTA CON IL PRODUCER
print('Collegamento a RabbitMQ......')
params = pika.ConnectionParameters(host='localhost')
connections=pika.BlockingConnection(params)
channel = connections.channel()
channel.queue_declare(queue='worker_queue')

print('Eseguito......')
#DOBBIAMO INDICARE A RABBIT TRAMITE PIKA COSA DOBBIAMO FARE OGNI
#VOLTA CHE RICEVIAMO UN MESSAGGIO. PER FARE CIO' SCRIVIAMO UNA FUNZIONE
#DI CALLBACK CHE VERRA' ESEGUITA OGNI VOLTA CHE ARRIVA UN
#MESSAGGIO DALLA CODA.
def callback(channel,method,properties,body):
    print(f'Ricevuto messaggio {body}')
    
channel.basic_consume(queue='worker_queue',on_message_callback=callback,auto_ack=False)
#start_consuming() PROVOCA L'ARRESTO DEL WORKER CHE SI METTERA'
#IN ATTESA DELLA PUBBLICAZIONE DI MESSAGGI DAL PRODUCER.
channel.start_consuming()

PYTHON E RABBITMQ – LINK AL CODICE GITHUB

GITHUB

PYTHON E RABBITMQ – LINK AI POST PRECEDENTI

PREVIOUS POST LINKS

Per eseguire i programmi apri il terminale e imposta come directory corrente la cartella contenente i programmi consumer.py e producer.py. Apri quattro schede nel terminale, su tre metti in esecuzione i programmi consumer.py utilizzando il seguente comando: python consumer.py attendi che i Consumer siano in attesa. Sul quarto terminale metti in esecuzione producer.py. Visualizza l’esecuzione sulle 4 schede.