Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Aleksej Najdjonov, CEO ITooLabs, parla dello sviluppo di una piattaforma di telecomunicazioni per gli operatori di rete utilizzando il linguaggio di programmazione Go (Golang). Aleksej condivide anche la sua esperienza di implementazione e gestione della piattaforma presso uno dei più grandi operatori di telecomunicazioni asiatici, che ha utilizzato la piattaforma per offrire servizi di segreteria telefonica (VoiceMail) e Centralino Virtuale (Cloud PBX).

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Aleksej Najdjonov (di seguito – AN): – Ciao a tutti! Mi chiamo Aleksej Najdjonov. Sono il direttore di ITooLabs. Vorrei prima di tutto spiegare cosa faccio qui e come sono arrivato qui.

Se guardate il Bitrix24 Marketplace (sezione 'Telefonia'), 14 delle 36 applicazioni disponibili (40%) sono nostre:

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

In realtà, sono i nostri operatori partner, ma dietro a tutto ciò c'è la nostra piattaforma (Platform as a Service) – ciò che vendiamo loro per una piccola cifra. Vorrei quindi parlare dello sviluppo di questa piattaforma e di come siamo arrivati a Go.

I numeri relativi alla nostra piattaforma attualmente:

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

44 partner operatori, incluso «Megafon». In generale, amiamo intraprendere diverse avventure e abbiamo accesso effettivo a 100 milioni di abbonati di 44 operatori qui in Russia. Pertanto, se qualcuno ha qualche idea di business, siamo sempre felici di ascoltarla.

  • 5000 aziende utenti.
  • 20.000 abbonati in totale. Questo è tutto B2B – lavoriamo esclusivamente con le aziende.
  • 300 chiamate al minuto durante il giorno.
  • 100 milioni di minuti di chiamate nell'anno scorso (l'abbiamo festeggiato). Questo senza contare le comunicazioni interne che avvengono sulla nostra piattaforma.

Come è iniziato tutto?

Come iniziano i veri professionisti a creare la propria piattaforma? Bisogna anche considerare che nel nostro background c'era lo sviluppo «hardcore enterprise», proprio nel periodo più strategico dell'anno per l'enterprise! Era quel momento fortunato in cui andavi dal cliente e dicevi: «Abbiamo bisogno di un paio di server in più». E il cliente: «Nessun problema! Ne abbiamo decine in rack».

Ecco perché ci siamo occupati di Oracle, Java, WebSphere, Db2 e simili. Abbiamo scelto, ovviamente, le migliori soluzioni vendor, le abbiamo integrate e abbiamo cercato di far decollare il progetto. Eravamo in proprio. Questo sarebbe stato un interno startup.

Tutto è iniziato nel 2009. Dal 2006 ci occupiamo seriamente di soluzioni per operatori, in un modo o nell'altro. Abbiamo realizzato alcune centraline virtuali su misura (simili a quelle che abbiamo attualmente a richiesta): abbiamo osservato, deciso che andava bene e così abbiamo deciso di avviare un startup interno.

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Abbiamo scelto VMWare. Poiché eravamo in proprio, siamo stati costretti a rinunciare a uno storage di alto livello fornito da un vendor. Sappiamo tutto su di loro: ciò che promettono va diviso per 3, mentre il costo va moltiplicato per 10. Pertanto, abbiamo realizzato DirDB e così via.

Poi ha iniziato a crescere. A ciò si è aggiunto un servizio di fatturazione, perché la piattaforma non riusciva più a gestire il carico. Successivamente, il server di fatturazione è passato da MySQL a Mongo. Alla fine, è emersa una soluzione funzionante, capace di elaborare tutte le chiamate che riceve:

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Ma da qualche parte, all'interno, ruota quel prodotto vendor – principale, centrale, che una volta abbiamo adottato. Verso la fine del 2011, ci siamo resi conto che il vero collo di bottiglia per noi sarebbe stato proprio questo prodotto – ci saremmo imbattuti in esso. Ci trovavamo di fronte a un muro contro il quale correvamo a tutta velocità, mentre i clienti arrivavano, si aggiungevano.
Pertanto, dovevamo fare qualcosa. Certo, abbiamo condotto ricerche a lungo su vari prodotti – sia open source che vendor. Non mi soffermerò su questo adesso – non è il punto. L'ultima opzione che stavamo considerando era quella di creare la nostra piattaforma.

Alla fine, siamo arrivati proprio a questa opzione. Perché? Perché tutti i prodotti vendor e open source erano stati creati per risolvere problemi di 10 anni fa. È già buono se parliamo di 10 anni fa, e alcuni anche di più! È diventato evidente per noi: o abbandoniamo la nostra bella idea di un servizio ideale (per i partner, gli operatori e noi stessi), oppure creiamo qualcosa di nostro.

Abbiamo deciso di creare qualcosa di nostro!

Requisiti per la piattaforma

Se ci si dedica a qualcosa a lungo (sfruttando un prodotto di terzi), pian piano prendi in considerazione la domanda: come lo farei io? Poiché in azienda siamo tutti programmatori (tranne i venditori, non ci sono programmatori), le nostre esigenze si sono consolidate da tempo e sono diventate chiare:

  1. Alta velocità di sviluppo. Il prodotto del fornitore, che ci ha dato tanto filo da torcere, ci ha deluso soprattutto per il fatto che tutto avveniva in modo lento e laborioso. Volevamo velocità – avevamo tante idee! Ne abbiamo ancora molte, ma allora la lista delle idee era tale che sembrava ci proiettassimo di dieci anni in avanti. Ora solo per un anno.
  2. Massima sfruttamento dell'hardware multi-core. Questo era importante per noi, poiché abbiamo visto che il numero di core sarebbe aumentato sempre di più.
  3. Alta affidabilità. È qualcosa su cui abbiamo anche pianto.
  4. Alta resilienza ai guasti.
  5. Volevamo alla fine arrivare a un processo con rilasci quotidiani. Per fare ciò avevamo bisogno di una scelta del linguaggio.

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Di conseguenza, dai requisiti del prodotto che ci siamo posti, nascono in modo chiaramente logico i requisiti per il linguaggio.

  1. Se vogliamo supporto per sistemi multicuore, abbiamo bisogno di supporto per l'esecuzione parallela.
  2. Se abbiamo bisogno di velocità nello sviluppo, abbiamo bisogno di un linguaggio che supporti lo sviluppo concorrente e la programmazione concorrente. Se qualcuno non ha mai affrontato la differenza, è molto semplice:
    • la programmazione parallela riguarda come due diversi flussi vengono eseguiti su core diversi;
    • l'esecuzione concorrente, più precisamente il supporto per la concorrenza, riguarda come il linguaggio (o il runtime, non importa) aiuta a nascondere tutta la complessità derivante dall'esecuzione parallela.
  3. Alta resilienza. È ovvio che avevamo bisogno di un cluster, e meglio di quello che avevamo con il prodotto del fornitore.

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

In realtà, non avevamo molte opzioni. Prima di tutto, Erlang – lo amiamo e lo conosciamo, è stato il mio personale favorito. In secondo luogo, Java – non Java, ma specificamente Scala. In terzo luogo, un linguaggio che a quel tempo non conoscevamo affatto – Go. Era appena apparso, in effetti, esisteva da circa due anni, ma non era ancora stato rilasciato.

Ha vinto Go!

Storia di Go

Abbiamo sviluppato la piattaforma su di esso. Proverò a spiegare perché.

Una breve storia di Go. È iniziato nel 2007, è stato aperto nel 2009 e la prima versione è uscita nel 2012 (quindi abbiamo iniziato a lavorare prima del primo rilascio). Il promotore è stato Google, che voleva sostituire Java, a quanto sospetto.

Gli autori sono molto noti:

  • Ken Thompson, che ha contribuito a Unix, ha inventato l'UTF-8 ed ha lavorato sul sistema Plan 9;
  • Rob Pike, che con Ken ha sviluppato l'UTF-8, ha anche lavorato su Plan 9, Inferno e Limbo ai Bell Labs;
  • Robert Griesemer, noto e amato per aver creato Java HotSpot Compiler e per aver lavorato sul generatore di V8 (l'interprete JavaScript di Google);
  • E oltre 700 partecipanti, inclusi alcuni dei nostri patch.

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Go: una prima occhiata

Possiamo vedere che il linguaggio è più o meno semplice e chiaro. Abbiamo tipi ovvi: in alcuni casi è necessario dichiararli, in altri no (questo significa che i tipi vengono dedotti, in un modo o nell'altro).

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

È evidente che è alla moda descrivere le strutture. È chiaro che abbiamo il concetto di puntatore (lì dove c'è l'asterisco). È evidente che c'è un supporto speciale per la dichiarazione e l'inizializzazione di array e array associativi.

Abbastanza chiaro: si può vivere. Proviamo a scrivere Hello, world:

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

Cosa vediamo? Questa è una sintassi simile a C, il punto e virgola è facoltativo. Può fungere da separatore per due righe, ma solo se si tratta di due istruzioni che sono effettivamente sulla stessa riga.

Vediamo che le parentesi nelle strutture di controllo (alla riga 14) sono facoltative, mentre quelle graffe sono sempre obbligatorie. Si nota inoltre che la tipizzazione è statica. Il tipo viene dedotto nella maggior parte dei casi. Questo esempio è un po' più complesso rispetto al tipico Hello, world, giusto per mostrare che esiste una libreria.

Cosa vediamo di importante? Il codice è organizzato in pacchetti. Per utilizzare un pacchetto nel proprio codice, è necessario importarlo usando la direttiva import — questo è anch'esso importante. Eseguiamo — funziona. Ottimo!

Proviamo qualcosa di più complesso: Hello, world, ma questa volta è un server http. Cosa vediamo di interessante qui?

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

In primo luogo, la funzione si comporta come un parametro. Questo significa che la funzione è un "cittadino di prima classe" e con essa si possono fare molte cose interessanti in stile funzionale. Notiamo poi qualcosa di inaspettato: la direttiva import fa riferimento direttamente al repository GitHub. È corretto, ed è esattamente quello che bisogna fare.

In Go, l'identificatore universale di un pacchetto è l'URL del suo repository. Esiste un'utilità speciale chiamata Goget, che si occupa di tutte le dipendenze, le scarica, le installa, le compila e le prepara per l'uso, se necessario. Inoltre, Goget è a conoscenza di html-meta. Pertanto, si può mantenere una directory http che contenga collegamenti al proprio repository specifico (come facciamo, ad esempio).

Cosa vediamo ancora? Http e Json fanno parte della libreria standard. Ovviamente c'è l'introspezione – reflection, che deve essere utilizzata in encoding/json, poiché le forniamo semplicemente un oggetto arbitrario.

Eseguiamo e vediamo che in 20 righe abbiamo del codice utile, che si compila, si avvia e restituisce il carico medio attuale della macchina (sulla macchina su cui è eseguito).
Cosa è importante sapere di più che possiamo vedere qui? Si compila in un unico binario statico (binary). Questo binario non ha alcuna dipendenza, nessuna libreria! Può essere copiato su qualsiasi sistema, avviato immediatamente e funzionerà.

Andiamo avanti.

Go: metodi e interfacce

In Go ci sono metodi. Puoi dichiarare un metodo per qualsiasi tipo personalizzato. Non è necessario che sia una struttura, può anche essere un alias di un certo tipo. Puoi dichiarare un alias per N32 e scrivere metodi per esso per fare qualcosa di utile.

E qui ci troviamo per la prima volta in difficoltà… Risulta che Go non ha classi in senso stretto. Coloro che conoscono Go possono dire che ci sono tipi incorporati, ma è un'altra cosa. Prima smette di pensare a questo come a un'eredità, meglio è. In Go non ci sono classi e nemmeno eredità.

Domanda! Cosa ci ha dato la compagnia degli autori sotto la guida di Google per mostrare tutta la complessità del mondo? Ci hanno dato interfacce!

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

L'interfaccia è un tipo speciale che consente di definire solo metodi e le loro firme. Qualsiasi tipo per il quale questi metodi esistono (sono implementati) sarà conforme a quest'interfaccia. Questo significa che puoi semplicemente descrivere una funzione corrispondente per un tipo e un'altra (che corrisponde a quel tipo di interfaccia). Successivamente, dichiara una variabile di quel tipo di interfaccia e assegna a essa uno qualsiasi di questi oggetti.

Per gli amanti del hardcore, posso dire che in questa variabile ci saranno in realtà due puntatori: uno ai dati e l'altro a una tabella speciale di descrittori, caratteristica proprio di questo tipo specifico, per l'interfaccia di quel tipo. Questo significa che il compilatore crea tali tabelle di descrittori al momento del linking.

E ci sono in Go, naturalmente, puntatori a void. La parola interface {} (con due parentesi graffe) è una variabile che può riferirsi a qualsiasi oggetto in generale.
Fino ad ora va tutto bene, tutto è familiare. Nulla di straordinario.

Go: goroutines

Ora arriviamo a ciò che ha suscitato il vostro interesse: i processi leggeri – le goroutines nella terminologia di Go.

Aleksej Najdjonov. ITooLabs. Caso di sviluppo di una piattaforma telefonica in Go (Golang). Parte 1

  1. In primo luogo, sono davvero leggeri (meno di 2 KB).
  2. In secondo luogo, i costi per creare un goroutine sono trascurabili: è possibile crearne mille al secondo – senza alcun problema.
  3. Sono gestiti da un proprio scheduler, che semplicemente passa il controllo da un goroutine all'altro.
  4. Il controllo viene passato nei seguenti casi:
    • se incontra un'espressione go (quando un goroutine lancia il successivo goroutine);
    • se viene attivata una chiamata bloccante di Input/Output;
    • se viene avviata la raccolta dei rifiuti;
    • se viene avviata qualche operazione con i canali.

Cioè ogni volta che un programma Go viene avviato su un computer, determina il numero di core nel sistema e avvia tanti thread quanti ne servono (il numero di core nel sistema o quello che hai specificato). Di conseguenza, lo scheduler avvierà questi leggeri thread di esecuzione su tutti questi thread del sistema operativo in ogni core.

È importante notare che questo è il modo più efficiente per smaltire l'hardware. Oltre a quanto mostrato, facciamo anche molte altre cose. Ad esempio, realizziamo sistemi DPI che consentono di gestire 40 gigabit in un'unità (a seconda di ciò che accade in queste righe).

Lì, prima di Go, utilizzavamo esattamente lo stesso schema proprio per questo motivo: permette di mantenere la località della cache del processore, riducendo notevolmente il numero di switch di contesto del sistema operativo (che richiede anche molto tempo). Ripeto: questo è il modo più efficiente per smaltire l'hardware.

Questo semplice esempio di 21 righe è un esempio che realizza semplicemente un echo-server. Notate che la funzione serve è estremamente semplice, è lineare. Non ci sono callback, né necessità di complicarsi la vita… Basta leggere e scrivere!

Tuttavia, se stai leggendo e scrivendo, dovrebbe effettivamente bloccarsi: questa goroutine viene semplicemente messa in coda e ripresa dal pianificatore quando diventa nuovamente possibile l'esecuzione. Quindi, questo semplice codice può funzionare come echo-server con il numero di connessioni che il sistema operativo permette su quella macchina.

Continuazione in arrivo molto presto…

Riproduci video

Un po' di pubblicità 🙂

Grazie per essere con noi. Ti piacciono i nostri articoli? Vuoi vedere più contenuti interessanti? Supportaci effettuando un ordine o raccomandandoci ai tuoi conoscenti, VPS cloud per sviluppatori a partire da $4,99, un'alternativa unica ai server entry-level, che abbiamo creato per te: Tutta la verità su VPS (KVM) E5-2697 v3 (6 Core) 10GB DDR4 480GB SSD 1Gbps a partire da $19. Come dividere il server correttamente? (disponibili opzioni con RAID1 e RAID10, fino a 24 core e fino a 40GB DDR4).

Dell R730xd a metà prezzo nel data center Equinix Tier IV ad Amsterdam? Solo da noi 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB a partire da $199 nei Paesi Bassi! Dell R420 — 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — a partire da $99! Scopri di più su Come costruire un'infrastruttura di classe enterprise con server Dell R730xd E5-2650 v4 dal costo di 9000 euro a prezzi stracciati?

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster