Presentazione di vice: passa a canali su molte macchine

La concorrenza è un ottimo modo per fare più cose più velocemente. I canali Go sono perfetti per consentire a più goroutine simultanee di comunicare in modo sicuro all’interno di un singolo processo, ma se vogliamo consentire a più macchine / nodi di comunicare in modo simile, dobbiamo scrivere codice completamente diverso e integrarlo con code di messaggistica, gRPC o qualcosa del genere altro. Fino ad ora.

Vice astrae le tecnologie delle code di messaggi e ti offre semplici vecchi canali Go attraverso i quali puoi invece comunicare.

Nello specifico, puoi:

In GrayMeta utilizziamo Vice con successo da un paio d’anni; quindi è abbastanza ben testato in produzione.

Il resto di questo articolo spiegherà le basi di Vice e mostrerà alcuni esempi di come creare servizi reali.

Scrivere un semplice servizio

Scriviamo il mio tipo di servizio preferito; il tuo amichevole saluto di quartiere.

Un saluto e r prende un nome, lo trasforma in un saluto (anteponendo & quot; Hello & quot; ) e restituisce il nuova stringa.

Il nostro Greeter sarà solo una semplice funzione Go. Ci vorrà un context.Context (per consentire alle persone di fermarlo), un canale di nomi di sola ricezione, un canale di saluti di sola invio, e un canale per gli errori.

Se non hai mai utilizzato il contesto per annullare le cose prima, controlla Utilizzo dei contesti per evitare perdite di goroutine.

Utilizzando un blocco select , aspetteremo che qualcuno invii un nome tramite il canale names , a quel punto creeremo un saluto e lo invieremo al Canale saluti .

Tutti i canali comunicano sezioni di byte [] byte , il che significa che possiamo gestire stringhe semplici per casi semplici, oppure utilizzare una delle tante opzioni di codifica (come JSON o Gob) per trasmetterne di più dati complessi.

Finora, questo è tutto codice Go idiomatico, ed è particolarmente eccitante quando guardiamo allo unit test per il nostro servizio / funzione Greeter.

Utilizza i normali canali Go nei test

Ecco uno unit test per la nostra funzione Greeter :

Per testare la nostra funzione Greeter , creiamo i canali che richiede e iniziamo con la parola chiave go , in modo che venga eseguita in background. Rimandiamo la cancellazione del contesto in modo che il messaggio di benvenuto si fermi quando la nostra funzione di test ha terminato con esso.

Quindi inviamo la stringa & quot; Vice & quot; attraverso il canale names e leggiamo il saluto dal canale greetings , che poi controlla e fallisci se è sbagliato. (Qui stiamo convertendo da e verso i tipi [] byte e string , ma niente di più complicato di così).

Questo test è uno unit test perfetto, non richiede dipendenze esterne e contiene tutto ciò di cui ha bisogno per essere eseguito.

Hmm, ma questo può bloccare per sempre …

Un’aggiunta che potremmo decidere di includere è coprire la situazione in cui il Greeter non fa quello che dovrebbe fare. Se non invia mai il saluto al canale greetings , il nostro codice di prova si bloccherà per sempre (o fino a quando go test deciderà di rinunciare per noi).

Poiché questo è solo un normale codice Go, un blocco di selezione nel nostro codice di prova è tutto ciò di cui abbiamo bisogno per aggiungere un timeout:

Questo codice si bloccherà finché non accadrà una delle due cose; o passa 1/2 secondo e segnaliamo un errore, oppure riceviamo un saluto. In ogni caso, non dobbiamo aspettare molto per sapere se il nostro codice funziona come previsto e non dobbiamo preoccuparci che i nostri test impieghino troppo tempo per essere eseguiti.

Aggiunta di code

Ora che abbiamo implementato il nostro servizio Greeter completamente testato, è ora di aggiungere l’impianto idraulico per trasformarlo in un servizio in grado di funzionare su una coda di messaggistica.

Vice si affida ai trasporti sottostanti (implementano l’interfaccia vice.Transport ) per svolgere il lavoro disordinato di interagire con le code.

Visualizza le code supportate nel repository GitHub

Diamo una rapida occhiata all’interfaccia di vice.Transport :

Notare che i metodi Send e Receive restituiscono canali; questi sono i canali che possiamo passare ai nostri servizi.

Tutto quello che dobbiamo fare nel nostro programma è:

Abbiamo configurato il nostro contesto in modo che duri 1 minuto, ma ha più senso che venga annullato catturando il segnale di terminazione, come quando l’utente preme Ctrl + C.

Creiamo un trasporto NSQ (NSQ è la coda di messaggistica di Bitly, scritta interamente in Go) importando il pacchetto appropriato e chiediamo a Transport di creare i nostri canali nomi e saluti .

Usiamo defer per fermare il Transport , il che è importante perché alcuni client registrano e annullano la registrazione del loro interesse nella coda e dobbiamo assicurarci che tutto sia pulito. Dopo aver chiamato Stop , attendiamo che il trasporto si fermi completamente aspettando la chiusura del canale Done () . Questo aiuta a garantire che la pulizia sia terminata prima di uscire dal nostro programma.

Per ulteriori informazioni sui canali di segnale, leggi Avvio e interruzione di operazioni con un canale di segnale.

Quindi passiamo questi canali, insieme al canale di errore di trasporto, alla funzione Greeter .

E questo è tutto. Ora, il nostro programma ascolterà l’argomento NSQ chiamato “nomi” e invierà risposte all’argomento “saluti”.

Ogni implementazione del trasporto ha una configurazione o personalizzazione specifica per la coda che è possibile eseguire, i cui dettagli sono nella documentazione di tale trasporto.

Compromessi

Vice offre un’astrazione molto semplice, ma vale la pena comprendere i compromessi e i compromessi.

Blocco e chiusura dei canali?

Se un canale Go non ha buffer, si bloccherà fino a quando qualcun altro non leggerà da esso. Usiamo questa natura come parte della progettazione dei nostri programmi, ma lo stesso non si applica quando si inviano quei messaggi su code di messaggi. Quando l’invio di un canale Vice si sblocca, non significa necessariamente che il messaggio sia stato consegnato come avviene con i canali Go in-process.

Per quanto riguarda la chiusura, i canali si chiuderanno quando il trasporto viene interrotto, quindi saprai quando le cose si saranno fermate.

Casi d’uso a bassa latenza

Se hai bisogno di messaggi ultra veloci a bassa latenza (come il commercio di azioni, il gameplay, ecc.), probabilmente vorrai creare qualcosa di più basso livello e lavorare direttamente con una specifica tecnologia di coda. Perderai i vantaggi di Vice, ma potrebbe essere un compromesso che vale la pena fare.

E i casi d’uso più complicati?

Quando inizi a esaminare le tue esigenze per una coda di messaggistica, ti rendi conto di avere alcune cose da considerare, come ad esempio:

David Hernandez (e in realtà l’intero progetto Go) è un grande sostenitore delle impostazioni predefinite ragionevoli , e questo è stato preso a cuore quando Vice è stato progettato. Quindi per impostazione predefinita, funziona e basta, se hai bisogno di modificare il comportamento puoi.

Quando crei il trasporto, hai la possibilità di configurarlo e ottimizzarlo in base alle tue esigenze. Ad esempio, NSQ ha il concetto di connessione a consumatori , quindi il tipo nsq.Transport espone la funzione ConnectConsumer , che viene fornita con un valore predefinito ragionevole ma puoi sovrascriverlo se vuoi configurarlo.

Non tutte le tecnologie per le code hanno gli stessi concetti, quindi non ha senso che questi concetti diventino astrazioni.

Conclusione

Vice ti consente di scrivere servizi utilizzando solo canali Go idiomatici e successivamente collegarli a tecnologie di code di messaggistica altamente scalabili che raggiungono una scala enorme. Ha una buona selezione di tecnologie per le code tra cui scegliere, quindi puoi iniziare oggi stesso, ma se il tuo preferito manca, puoi sempre essere un eroe e aggiungerlo.

A proposito, c’è un’altra caratteristica di questo progetto che è davvero utile quando si tratta di contribuire …

Una nota a margine; Test dell’interfaccia

Una caratteristica interessante di questa base di codice è l’uso dei test di interfaccia. Un test di interfaccia è un codice di test (di solito una singola funzione) che accetta un’interfaccia come vice.Transport e la utilizza in vari modi affermando che si comporta come previsto.

Il codice di test non sa nulla dei dettagli dell’implementazione; non importa. Si preoccupa solo che i metodi di interfaccia e i tipi restituiti facciano ciò che dovrebbero.

Affinché un trasporto sia considerato buono, deve superare tutti i test.

Quindi, se hai voglia di scrivere un’implementazione di Vice per la tua tecnologia di coda di messaggistica preferita, a condizione di aggiungere il seguente test (e viene superato), probabilmente sarà accettato.

E poi?