Backend Programmeren

Waarom Kubernetes en Docker Geschreven Zijn in Go

Terwijl ontwikkelaars debatteren over de voor- en nadelen van Python, Java en C#, is er in de loop van het laatste decennium een andere taal dominant geworden op de achtergrond van het internet: Go (Golang). Ontwikkeld door Google, is Go uitgegroeid tot de onofficiële “taal van de cloud”. Vrijwel alle essentiële, prestatiekritieke cloud-infrastructuur tools die vandaag de dag worden gebruikt — zoals Docker, Kubernetes, Terraform, Prometheus en HashiCorp Vault — zijn volledig geschreven in Go. Het succes van de taal ligt in de geniale balans die het slaat: de rauwe uitvoersnelheid en lage systeemvoetafdruk van C of C++, gecombineerd met de leessnelheid, simpliciteit en productiviteit van dynamische talen zoals Python.

Voor backend software developers die microservices bouwen die hoge netwerkdoorvoer vereisen en zwaar leunen op asynchrone communicatie, biedt Golang out-of-the-box functies die andere talen missen of pas na ingewikkelde optimalisaties kunnen evenaren.

Goroutines: Concurrency Zonder de Pijn

De absolute ‘killer feature’ van Go is de manier waarop het omgaat met gelijktijdigheid (concurrency). In traditionele talen zoals Java of C# gebruiken ontwikkelaars OS-threads om taken parallel uit te voeren. OS-threads zijn ‘zwaar’ (ze consumeren al snel 1-2 megabyte RAM per thread) en het opstarten en wisselen tussen threads (context switching) vereist aanzienlijke CPU-resources. Een server loopt dan ook vast bij een paar duizend threads.

Go lost dit op met ‘Goroutines’. Dit zijn ‘lightweight, green threads’ die niet worden beheerd door het besturingssysteem, maar door de Go Runtime zelf. Een Goroutine kost slechts 2 kilobyte aan opstartgeheugen. U start een asynchrone functie in Go simpelweg door het woordje go voor de functie-aanroep te plaatsen (bijv. go stuurEmail(gebruiker)). Hierdoor is het volkomen normaal dat een backend-service op een simpele VPS miljoenen onafhankelijke Goroutines gelijktijdig open heeft staan voor het afhandelen van HTTP-verzoeken of WebSocket-verbindingen zonder dat de server instort.

Communicating Sequential Processes (CSP) via Channels

Wanneer miljoenen asynchrone taken gelijktijdig draaien, moeten ze veilig data met elkaar kunnen uitwisselen. In andere talen delen threads geheugen (shared memory) en gebruikt u ingewikkelde ‘Mutex Locks’ om te voorkomen dat twee threads tegelijkertijd data overschrijven (race conditions). De filosofie van Go is fundamenteel anders: “Do not communicate by sharing memory; instead, share memory by communicating.”

Dit wordt bereikt door middel van ‘Channels’. Een channel is een veilige, georkestreerde ‘pijplijn’ tussen Goroutines. Goroutine A dumpt een taak in het channel, en de Go runtime garandeert dat de data veilig, zonder externe locks en data corruption, uit het channel wordt geplukt door Goroutine B. Dit leidt tot een zeer robuust architectuur-ontwerp (het Worker-Pool patroon) dat extreem schaalbaar is over multi-core processoren.

Statisch Gecompileerd: Deployment is Simpel

Waar u voor een Node.js of Python app uw productie-container moet voorzien van complexe afhankelijkheden (zoals package.json bestanden, pip requirements, of de runtime dependencies), blinkt Go uit in distributie. Go is een gecompileerde taal. De compiler neemt uw gehele codebase en plakt dit samen in één enkel, onafhankelijk, statisch binair uitvoerbaar bestand (executable). U kunt dit kleine bestand (vaak maar 15MB) overzetten naar elke ‘kale’ Linux-server, zonder dat de Go-runtime zelf op de server hoeft te zijn geïnstalleerd. Het bestand bevat alles wat nodig is en start in fracties van een milliseconde op. Voor inzicht in concurrerende en prestatiegerichte backend-talen, leest u meer in de achtergronden op Tweakers.

Volgende: Modern Database Design: De Strijd Tussen NoSQL, Relational, en NewSQL (CockroachDB)

Inhoudsopgave

Geverifieerd door MonsterInsights