Luca Boeri Luca Boeri avatar

5 minute read

Dalle notifiche di Facebook ad un tweet stream, da Google Docs ai giochi multiplayer in HTML5, la necessità di uno scambio dati in due direzioni, efficiente e a bassa latenza, ha determinato l’ascesa negli ultimi anni di soluzioni basate su WebSocket.

Internet delle cose e web 2.0 trovano oramai sempre meno spazio all’interno del protocollo HTTP/1. Le tecniche di polling e long polling, in voga fino a pochi anni fa, non permettevano di trasmettere in full duplex (tra server e client) contemporaneamente, erano costrette ad un alto overhead HTTP e richiedevano diversi sforzi per simulare notifiche push server side.

Il protocollo WAMP

WAMP (Web Application Messaging Protocol e non Windows, Apache, etc.!) offre un moderno pattern di messaggistica RPC e Pub/Sub in maniera unificata. Registrato presso lo IANA come sottoprotocollo WebSocket, definisce uno standard aperto per lo scambio di messaggi in tempo reale tra applicazioni e componenti, e permette la creazione di architetture debolmente accoppiate basate su microservizi. Utilizza canali full-duplex ordinati ed è quindi adatto ad implementazioni basate su WebSocket, ma supporta allo stesso modo socket Unix, socket raw o long polling HTTP.

Il protocollo risulta piuttosto completo ed adeguato a diversi scenari di utilizzo se comparato ad altri sistemi di messaggistica ed RPC.

Technology PubSub RPC Routed RPC Web native Cross Language Open Standard
WAMP
AJAX
AMQP
REST
SOAP
Socket.io
SockJS
XMPP
ZeroMQ
fonte: Wikipedia

Può essere utilizzato con profitto per sviluppare una piattaforma di gioco online multiplayer, strumenti di business intelligence real time e piattaforme collaborative per numerosi utenti.

Una piattaforma web di help desk ad esempio, può beneficiare di notifiche, chat, strumenti di scrittura multi-utente ed analisi dell’andamento in tempo reale sullo stesso protocollo WAMP.

Per funzionare WAMP necessità di uno o più server di routing centralizzati, allo stesso modo di RabbitMQ per AMQP. Per quanto esistano diverse implementazioni di router, in diversi linguaggi, lo standard de facto è rappresentato da Crossbar, sviluppato da Tavendo, alla quale si deve anche la definizione del protocollo stesso.

Crossbar

Crossbar, scritto in python (open source, licenza AGPL v3), supporta completamente le funzionalità descritte dal protocollo oltre a vantare configurazioni avanzate come ad esempio le subscriptions basate su pattern, le progressive result su RPC e profili di autenticazione ed autorizzazione dinamici.

Nessuna delle altre implementazioni è poi al momento in grado di vantare le stesse prestazioni e la stabilità di Crossbar: una istanza del router è in grado di servire 1000 messaggi/secondo su Pub/Sub, a 1000 client, con una latenza di 25ms su una RaspberryPi!

Router Broker Dealer Advanced Profile Language
Crossbar Pyhton
Thruway PHP
wamp.rt NodeJS
jawampa Java
WampSharp C#
Erwa Erlang
fonte: WAMP.ws

..e PHP?

Diverse applicazioni web di backend usate presso Facile.it permettono ad un gran numero di operatori di lavorare sulle stesse pratiche in maniera collaborativa in tempo reale. Il protocollo WAMP è una tecnologia sulla quale è possibile sviluppare in maniera efficiente dashboard collaborative e realtime.. ma sarà anche in grado di funzionare adeguatamente assieme alle soluzioni PHP (spesso in Symfony 2) sviluppate in casa e non precedentemente disegnate per l’uso con WebSocket?

Esistono diverse librerie (come Thruway) che permettono di operare come client PHP in ambiente WAMP, ma per semplificare l’integrazione del protocollo con altri servizi, Crossbar supporta il bridge HTTP delle funzionalità Pub/Sub e RPC.

In pratica, parlando ad esempio di Pub/Sub, è possibile pubblicare via HTTP (o HTTPS) su Crossbar messaggi che saranno inoltrati su topic ai client connessi via WebSocket in maniera trasparente. Altresì è possibile iscriversi ai topic fornendo un endpoint HTTP da chiamare per ricevere i messaggi pubblicati da client WebSocket.

L’esempio sottostante configura un router Crossbar in grado di accettare connessioni websocket, pubblicazioni via HTTP e che si occupa di forwardare alcuni messaggi ad un endpoint HTTPS:

Il gist precedente può essere lanciato al volo con docker: docker run -p 80:80 -p 8080:8080 -v $PWD/crossbar-config.json:/.crossbar/config.json vinelab/crossbar.

Ovviamente l’esempio non tiene conto di profili di configurazione più avanzati, come cifratura TLS, autenticazione, ruoli separati di pubblicazione e/o iscrizione, disponibili nella documentazione di Crossbar.

Features come la firma delle richieste HTTP, richiedono più di qualche minuto di sviluppo, ma sono indispensabili in un ambiente di produzione.

Per semplificare l’adozione del bridge HTTP in ambito PHP, in Facile.it abbiamo sviluppato e rilasciato un bundle che permette la configurazione automatica di servizi di Publisher WAMP nel service container di Symfony 2.

Il bundle, disponibile su Packagist (composer) può essere installato con $ composer require facile-it/crossbar-http-publisher-bundle dev-master e richiede una configurazione rapida ed intuitiva:

facile_crossbar_http_publisher:
  connections:
    foo_publisher_1:
        protocol: http
        host: 127.0.0.1

L’uso è molto semplice:

// recupero del servizio
$fooPublisher = $container
                ->get('facile.crossbar.publisher.foo_publisher_1');

$topic = 'com.myapp.hello';

// pubblicazione
$firstPublisher->publish($topic, ['foo',1]);

Con le poche righe sopra riportate, attraverso il metodo publish() viene effettuata una chiamata HTTP POST verso il router WAMP, ed il messaggio ['foo',1] raggiunge in tempo (quasi) reale tutti i client (ad esempio tutti i browser degli utenti) iscritti al topic com.myapp.hello.

Anche in questo caso, la configurazione può supportare diversi host, porte, uso TLS, signed request, e attraverso GitHub è possibile trovare diversi esempi di possibili configurazioni.

..ma i miei utenti lo supporteranno?

Lato browser, passare a WAMP è davvero semplice: la libreria Autobahn|JS garantisce piena compatibilità anche per node.js, supporta l’autenticazione, ed è in grado di gestire in maniera asincronia sia RPC che Pub/Sub.

Qualora il browser di un vostro utente non supportasse WebSocket (e dovrebbe oramai!), Autobahn|JS è in grado di fornire un fallback automatico a long polling.

Iscriversi ad un topic o pubblicare un messaggio richiede poche linee:

Nell’esempio sopra riportato, il client JS si iscrive al topic com.myapp.hello e passa i messaggi ricevuti ad una semplice funzione console.log(); inoltre pubblica un messaggio sul topic com.myapp.topic1. Quest’ultimo, sarà anche forwardato da Crossbar sul nostro endpoint HTTPS https://hostname/subscriptions.

Grazie alle funzionalità HTTP bridge di Crossabar l’utilizzo di WAMP in ambito PHP, senza connessioni persistenti o consumer sempre accesi, è semplice ed immediato!

Per un ulteriore approfondimento su WAMP, saranno inoltre utili le slide che seguono:

Riferimenti

comments powered by Disqus