Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Alexej Najdenow, CEO ITooLabs, spricht über die Entwicklung einer Telekommunikationsplattform für Anbieter von Kommunikationsdiensten in der Programmiersprache Go (Golang). Alexej teilt auch seine Erfahrungen bei der Implementierung und dem Betrieb der Plattform bei einem der größten asiatischen Telekommunikationsanbieter, der die Plattform für Voicemail-Services und Cloud-CTI genutzt hat.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Alexej Najdenow (im Folgenden – AN): – Hallo zusammen! Mein Name ist Alexej Najdenow. Ich bin der Direktor von ITooLabs. Zunächst möchte ich erläutern, was ich hier mache und wie ich hierher gekommen bin.

Wenn Sie sich den Bitrix24 Marketplace (Bereich „Telefonie“) ansehen, gibt es 14 Apps und 36, die dort zu finden sind (40%) – das sind wir:

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Genauer gesagt, sind das unsere Partneranbieter, aber hinter all dem steht unsere Plattform (Platform as a Service) – das, was wir ihnen für kleines Geld verkaufen. Tatsächlich möchte ich über die Entwicklung dieser Plattform und darüber, wie wir zu Go kamen, sprechen.

Die aktuellen Zahlen zu unserer Plattform sind:

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

44 Partnernetzbetreiber, darunter "Megafon". Ganz ehrlich, wir lieben es, uns auf verschiedene Abenteuer einzulassen, und wir haben tatsächlich Zugang zu 100 Millionen Abonnenten von 44 Anbietern hier in Russland. Wenn also jemand geschäftliche Ideen hat, sind wir immer bereit, zuzuhören.

  • 5000 Unternehmensnutzer.
  • Insgesamt 20.000 Abonnenten. Das alles ist B2B – wir arbeiten ausschließlich mit Unternehmen.
  • 300 Anrufe pro Minute tagsüber.
  • 100 Millionen Minuten an Anrufen im vergangenen Jahr (das haben wir gefeiert). Das ohne interne Gespräche, die auf unserer Plattform stattfinden.

Wie hat alles begonnen?

Wie fangen die richtigen Leute an, ihre Plattform zu entwickeln? Man muss auch berücksichtigen, dass wir in der Vergangenheit Hardcore-Enterprise-Entwicklung hatten, und das zur besten Zeit des Jahres für Enterprise! Es war die glückliche Zeit, als man zum Kunden kommt und sagt: "Wir brauchen noch ein paar Server." Und der Kunde antwortet: "Kein Problem! Wir haben zehn in der Rack stehen."

Deshalb haben wir uns mit Oracle, Java, WebSphere, Db2 und ähnlichen Technologien beschäftigt. Wir haben die bestenVendorlösungen ausgewählt, sie integriert und versucht, damit durchzustarten. Es war ein internes Startup-Projekt.

Alles begann im Jahr 2009. Seit 2006 beschäftigen wir uns intensiv mit Betreiberlösungen. Wir haben einige maßgeschneiderte virtuelle Telefonanlagen entwickelt (ähnlich dem, was wir jetzt anbieten): Wir haben es uns angesehen, festgestellt, dass es gut funktioniert und beschlossen, ein internes Startup zu gründen.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Wir haben VMWare verwendet. Da wir auf eigene Kosten gearbeitet haben, mussten wir auf umfangreiche Vendor-Storage-Lösungen verzichten. Wir wissen alles über sie: Versprechen muss man durch 3 teilen, und die Kosten multipliziert man mit 10. Darum haben wir DirDB und ähnliches entwickelt.

Dann begann es zu wachsen. Dazu kam ein Abrechnungsservice, weil die Plattform nicht mehr zurechtkam. Der Abrechnungsserver von MySQL wurde auf Mongo umgestellt. Am Ende hatten wir eine funktionierende Lösung, die alle eingehenden Anrufe verarbeitet:

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Doch irgendwo da drinnen dreht sich das genau richtige Produkt – das Haupt-, das zentrale, welches wir einmal übernommen haben. Gegen Ende 2011 wurde uns klar, dass dieses Produkt unser größtes Engpass sein würde – genau auf dieses werden wir stoßen. Wir sahen eine Wand vor uns, gegen die wir mit vollem Lauf rasten, da die Kunden kamen und hinzukamen.
Also mussten wir irgendwie handeln. Natürlich haben wir umfangreiche Recherchen zu verschiedenen Produkten angestellt – sowohl Open Source als auch Vendor-Lösungen. Ich möchte nicht weiter darauf eingehen – das ist nicht das Thema. Die letzte Option, über die wir nachdachten, war, unsere eigene Plattform zu entwickeln.

Schließlich sind wir genau zu dieser Option gelangt. Warum? Weil alle Vendor- und Open Source-Produkte zur Lösung von Problemen gemacht wurden, die vor 10 Jahren aufgetreten sind. Gut, wenn sie 10 Jahre alt sind, einige sogar noch älter! Für uns war die Wahl offensichtlich: entweder wir verabschieden uns von unserer großartigen Idee des idealen Dienstes (für Partner, Betreiber und uns selbst), oder wir erschaffen etwas Eigenes.

Wir haben beschlossen, etwas Eigenes zu entwickeln!

Anforderungen an die Plattform

Wenn man sich längere Zeit mit etwas beschäftigt (ein fremdes Produkt nutzt), kommt einem irgendwann der Gedanke: Wie würde ich das selbst machen? Da wir in der Firma alles Programmierer sind (außer den Verkäufern, gibt es keine Nicht-Programmierer), haben sich unsere Anforderungen schon lange herauskristallisiert, und sie waren klar verständlich:

  1. Hohe Entwicklungsgeschwindigkeit. Das Produkt des Anbieters, das uns gequält hat, hat uns in erster Linie dadurch gestört, dass alles lange und langsam ging. Wir wollten es schnell – wir hatten viele Ideen! Und auch jetzt haben wir viele Ideen, aber damals war die Liste so lang, dass es schien, als würden wir zehn Jahre in die Zukunft planen. Jetzt sind es nur noch ein Jahr.
  2. Maximale Auslastung der Mehrkernhardware. Das war uns ebenfalls wichtig, da wir sahen, dass die Anzahl der Kerne nur weiter steigen würde.
  3. Hohe Zuverlässigkeit. Auch ein Punkt, bei dem wir viel geweint haben.
  4. Hohe Ausfallsicherheit.
  5. Wir wollten letztendlich zu einem Prozess mit täglichen Releases kommen. Dafür benötigten wir eine Sprachwahl.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Entsprechend ergeben sich aus den Anforderungen an das Produkt, die wir an uns selbst gestellt haben, ganz logisch die Anforderungen an die Sprache.

  1. Wenn wir Unterstützung für Mehrkernsysteme möchten, benötigen wir Unterstützung für parallele Ausführung.
  2. Wenn wir Geschwindigkeit in der Entwicklung wollen, brauchen wir eine Sprache, die konkurrierende Programmierung unterstützt. Wer sich nicht mit dem Unterschied auskennt, der ist ganz einfach erklärt:
    • Paralleles Programmieren bedeutet, dass zwei verschiedene Threads auf unterschiedlichen Kernen ausgeführt werden;
    • konkurrierende Ausführung, genauer gesagt die Unterstützung von Parallelität, beschreibt, wie die Sprache (oder die Laufzeitumgebung, ganz gleich) hilft, die gesamte Komplexität, die aus paralleler Ausführung resultiert, zu verbergen.
  3. Hohe Zuverlässigkeit. Offensichtlich benötigten wir ein Cluster, und zwar besser als das, was wir mit dem vendor-spezifischen Produkt hatten.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Tatsächlich hatten wir nicht viele Optionen, wenn wir daran zurückdenken. Erstens, 'Erlang' – wir lieben es und kennen es, es war mein persönlicher Favorit. Zweitens, Java – genauer gesagt Scala. Drittens, eine Sprache, die wir zu diesem Zeitpunkt überhaupt nicht kannten – Go. Es war gerade erst erschienen, genauer gesagt, es existierte seit etwa zwei Jahren, war aber noch nicht offiziell veröffentlicht.

Go hat gewonnen!

Die Geschichte von Go

Wir haben die Plattform darauf aufgebaut. Ich werde versuchen zu erklären, warum.

Eine kurze Geschichte von Go. Gestartet im Jahr 2007, offiziell eröffnet 2009, die erste Version erschien 2012 (das heißt, wir haben noch vor dem ersten Release angefangen zu arbeiten). Der Initiator war Google, das, wie ich vermute, Java ersetzen wollte.

Die Autoren sind ziemlich namhaft:

  • Ken Thompson, der hinter Unix steht, UTF-8 erfunden hat und an Plan 9 gearbeitet hat;
  • Rob Pike, der zusammen mit Ken UTF-8 entwickelt hat, arbeitete ebenfalls an Plan 9, Inferno und Limbo bei Bell Labs;
  • Robert Griesemer, den wir kennen und lieben für die Erfindung des Java HotSpot Compilers und seine Arbeit am Generator in V8 (dem JavaScript-Interpreter von Google);
  • Und über 700 weitere Mitwirkende, einschließlich einiger unserer Patches.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Go: Ein erster Blick

Wir sehen, dass die Sprache mehr oder weniger einfach und verständlich ist. Es gibt offensichtliche Typen: in einigen Fällen müssen sie deklariert werden, in anderen nicht (das bedeutet, dass die Typen folglich abgeleitet werden).

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Es ist offensichtlich, dass es üblich ist, Strukturen zu beschreiben. Wir sehen, dass es ein Konzept für Zeiger gibt (dort, wo der Stern steht). Es ist erkennbar, dass es spezielle Unterstützung für die Deklaration und Initialisierung von Arrays und assoziativen Arrays gibt.

Es ist ziemlich klar – man kann leben. Lassen Sie uns versuchen, Hello, World zu schreiben:

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Was sehen wir? Es handelt sich um eine C-ähnliche Syntax, das Semikolon ist optional. Es kann als Trennzeichen zwischen zwei Zeilen verwendet werden, aber nur, wenn es sich um zwei Anweisungen handelt, die auf einer einzigen Zeile stehen.

Wir sehen, dass die Klammern in Kontrollstrukturen (in Zeile 14) optional sind, aber die geschweiften Klammern immer erforderlich sind. Wir sehen auch, dass die Typisierung statisch ist. Der Typ wird in den meisten Fällen abgeleitet. Dieses Beispiel ist etwas komplizierter als das übliche Hello, World – nur um zu zeigen, dass es eine Bibliothek gibt.

Was sehen wir noch? Der Code ist in Pakete organisiert. Um ein Paket in Ihrem eigenen Code zu verwenden, muss es mittels der Import-Direktive importiert werden – das ist ebenfalls wichtig. Lassen Sie es laufen – es funktioniert. Großartig!

Versuchen wir etwas Komplexeres: Hello, World, aber diesmal ist es ein HTTP-Server. Was Interessantes sehen wir hier?

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Zunächst einmal ist die Funktion ein Parameter. Das bedeutet, dass die Funktion ein „First-Class Citizen“ ist, und wir können damit viele interessante Dinge im funktionalen Stil machen. Überraschenderweise verweist die Import-Direktive direkt auf das GitHub-Repository. Das ist korrekt, und genau so sollte es auch sein.

In Go ist die universelle Kennung eines Pakets die URL seines Repositories. Es gibt ein spezielles Tool namens Goget, das alle Abhängigkeiten herunterlädt, installiert, kompiliert und ggf. für die Nutzung vorbereitet. Dabei kennt Goget auch html-meta. Entsprechend kann man ein http-Verzeichnis führen, in dem Links zu dem eigenen Repository hinterlegt sind (wie wir es beispielsweise tun).

Was sehen wir noch? Http und Json sind in der Standardbibliothek vorhanden. Es gibt offensichtlich eine Introspektion – Reflection, die in encoding/json verwendet werden sollte, weil wir damit einfach ein beliebiges Objekt übergeben.

Wir starten und sehen, dass wir in 20 Zeilen nützlichen Code untergebracht haben, der kompiliert, ausgeführt wird und die aktuelle durchschnittliche Auslastung der Maschine zurückgibt (auf der Maschine, auf der er ausgeführt wird).
Was ist noch wichtig, das wir hier sofort sehen können? Es wird in ein einziges statisches Binary (buinary) kompiliert. Dieses Binary hat überhaupt keine Abhängigkeiten, keine Bibliotheken! Es kann auf jedes System kopiert und sofort ausgeführt werden, und es wird funktionieren.

Lassen Sie uns weitermachen.

Go: Methoden und Schnittstellen

In Go gibt es Methoden. Sie können eine Methode für jeden benutzerdefinierten Typ deklarieren. Dabei muss es sich nicht unbedingt um eine Struktur handeln; es kann auch ein Alias für einen bestimmten Typ sein. Sie können einen Alias für N32 erstellen und für ihn Methoden definieren, um nützliche Dinge zu tun.

Und hier stoßen wir zum ersten Mal auf ein Problem... Es stellt sich heraus, dass Go keine Klassen im eigentlichen Sinne hat. Diejenigen, die Go kennen, werden sagen, dass es Typen-Inklusion gibt, aber das ist etwas ganz anderes. Je früher ein Entwickler damit aufhört, dies als Vererbung zu betrachten, desto besser. In Go gibt es keine Klassen, und somit auch keine Vererbung.

Frage! Was hat das Autorenteam unter der Leitung von Google uns gegeben, um die gesamte Komplexität der Welt darzustellen? Uns wurden Schnittstellen gegeben!

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

Ein Interface ist eine spezielle Art, die es ermöglicht, einfache Methoden und deren Signaturen zu definieren. Jeder Typ, für den diese Methoden existieren (ausgeführt werden), entspricht diesem Interface. Das bedeutet, dass Sie einfach die entsprechende Funktion für einen Typ und einen anderen (der dem Interface-Typ entspricht) beschreiben können. Danach deklarieren Sie eine Variable dieses Interface-Typs und weisen ihr eines dieser Objekte zu.

Für Hardcore-Fans kann ich sagen, dass in dieser Variablen tatsächlich zwei Zeiger vorhanden sein werden: einer auf die Daten und der andere auf eine spezielle Deskriptortabelle, die spezifisch für diesen bestimmten Typ und das Interface dieses Typs ist. Der Compiler erstellt solche Deskriptortabellen zum Zeitpunkt des Linkens.

In Go gibt es natürlich auch Zeiger auf void. Das Wort interface {} (mit zwei geschweiften Klammern) ist eine Variable, die auf jedes beliebige Objekt verweisen kann.
Bis jetzt ist alles in Ordnung, alles vertraut. Nichts Überraschendes.

Go: Goroutines

Jetzt kommen wir zu dem, was interessiert: die leichtgewichtigen Prozesse – Goroutines (Goroutinen) in der Terminologie von Go.

Aleksey Naydenov. ITooLabs. Fallstudie zur Entwicklung einer Telefonplattform in Go (Golang). Teil 1

  1. Zunächst einmal sind sie wirklich leichtgewichtig (unter 2 KB).
  2. Zweitens sind die Kosten für die Erstellung eines solchen Goroutinen vernachlässigbar: Sie können tausend pro Sekunde erstellen – es kostet nichts.
  3. Sie werden von ihrem eigenen Scheduler verwaltet, der einfach die Kontrolle von einer Goroutine zur nächsten übergibt.
  4. Dabei erfolgt die Kontrolle in den folgenden Fällen:
    • Wenn das go-Ausdruck auftritt (wenn eine Goroutine die nächste Goroutine startet);
    • Wenn ein blockierender Eingabe-/Ausgabebefehl aktiviert wird;
    • Wenn die Müllsammlung gestartet wird;
    • Wenn eine Operation mit Kanälen gestartet wird.

Das bedeutet, dass jedes Mal, wenn ein Go-Programm auf einem Computer ausgeführt wird, es die Anzahl der Kerne im System ermittelt und so viele Threads startet, wie benötigt werden (entweder so viele wie es Kerne im System gibt oder so viele, wie Sie ihm gesagt haben). Entsprechend startet der Scheduler diese leichtgewichtigen Ausführungsstränge in all diesen Betriebssystem-Threads in jedem Kern.

Es ist wichtig zu erwähnen, dass dies der effizienteste Weg ist, Hardware zu verwerten. Neben dem Gezeigten bieten wir noch viele weitere Lösungen an. Zum Beispiel entwickeln wir DPI-Systeme, die es ermöglichen, 40 Gigabit pro Einheit zu bedienen (je nachdem, was in diesen Zeilen geschieht).

Dort haben wir bereits vor Go genau dasselbe Schema aus diesem Grund verwendet: Es ermöglicht, die Lokalität des CPU-Caches zu erhalten und die Anzahl der Kontextwechsel des Betriebssystems erheblich zu reduzieren (was ebenfalls viel Zeit in Anspruch nimmt). Ich wiederhole: Dies ist der effizienteste Weg, um Hardware zu verwerten.

Dieses einfache Beispiel mit 21 Zeilen zeigt, wie man einen einfachen Echo-Server erstellt. Beachten Sie, dass die Funktion 'serve' extrem einfach und linear ist. Es gibt keine Callback-Funktionen, und Sie müssen sich nicht kompliziert anstellen und nachdenken... Sie lesen und schreiben einfach!

Wenn Sie lesen und schreiben, sollte es sich tatsächlich blockieren – diese Goroutine wird einfach in die Warteschlange eingeordnet und vom Scheduler entnommen, wenn die Ausführung wieder möglich ist. Das bedeutet, dass dieser einfache Code als Echo-Server für so viele Verbindungen arbeiten kann, wie das Betriebssystem auf dieser Maschine zulässt.

Die Fortsetzung kommt in Kürze...

Video abspielen

Ein wenig Werbung 🙂

Danke, dass Sie bei uns bleiben. Gefallen Ihnen unsere Artikel? Möchten Sie mehr interessante Inhalte sehen? Unterstützen Sie uns, indem Sie eine Bestellung aufgeben oder uns Ihren Freunden empfehlen. Cloud-VPS für Entwickler ab 4,99 $, eine einzigartige Alternative zu Einsteiger-Servern, die wir für Sie entwickelt haben: Alles über VPS (KVM) E5-2697 v3 (6 Kerne) 10GB DDR4 480GB SSD 1Gbps ab 19 $ oder wie man einen Server richtig teilt? (Verfügbar sind Optionen mit RAID1 und RAID10, bis zu 24 Kerne und bis zu 40GB DDR4).

Dell R730xd im Equinix Tier IV Rechenzentrum in Amsterdam zum halben Preis? Nur bei uns 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB ab 199 $ in den Niederlanden! Dell R420 — 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — ab 99 $! Lesen Sie darüber Wie man eine Unternehmenskosten-Infrastruktur mit Dell R730xd E5-2650 v4-Servern für ein paar Euro aufbaut?

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster