
Hoe sneller het ontwikkelproces, hoe sneller het technologiebedrijf zich ontwikkelt.
Helaas werken moderne applicaties tegen ons ā onze systemen moeten in real-time worden geüpdatet en tegelijkertijd niemand storen of leiden tot stilstand en onderbrekingen. Implementatie in dergelijke systemen wordt een complexe taak en vereist ingewikkelde continue leveringspipelines, zelfs in kleine teams.
Deze pipelines hebben vaak een beperkte toepasbaarheid, werken traag en zijn niet betrouwbaar. Ontwikkelaars moeten ze eerst handmatig opzetten en vervolgens beheren, en bedrijven huren vaak hele DevOps-teams in voor dit doel.
De snelheid van deze pipelines bepaalt de snelheid van de ontwikkeling. Bij de beste teams duurt een implementatie 5-10 minuten, maar meestal duurt het veel langer, en voor ƩƩn implementatie zijn meerdere uren nodig.
Bij Dark kost dit 50 ms. Vijftig. Milliseconden.. Dark ā , speciaal ontwikkeld voor continue levering, waarbij alle aspecten van Dark, inclusief de programmeertaal zelf, zijn opgebouwd met het oog op veilige momentane implementatie.
Waarom zijn pipelines voor continue levering zo traag?
Stel je voor dat we een Python-webapplicatie hebben en we hebben al een geweldige en moderne continu-leveringspipeline opgezet. Voor de ontwikkelaar die dagelijks met dit project bezig is, ziet de implementatie van een kleine wijziging er ongeveer zo uit:
Wijzigingen aanbrengen
- Een nieuwe branch aanmaken in git
- Wijzigingen aanbrengen achter de feature toggle
- Modulaire tests om de wijzigingen met en zonder feature toggle te controleren
Pull request
- Wijzigingen committen
- Wijzigingen naar de externe repository op github versturen
- Pull request
- De CI-build wordt automatisch op de achtergrond uitgevoerd
- Code review
- Nog een paar reviews, indien nodig
- Wijzigingen samenvoegen met de master in git.
CI wordt op de master uitgevoerd
- Frontend-afhankelijkheden installeren via npm
- HTML+CSS+JS middelen bouwen en optimaliseren
- Modulaire en functionele tests in de frontend uitvoeren
- Python-afhankelijkheden uit PyPI installeren
- Modulaire en functionele tests in de backend uitvoeren
- Integratietests aan beide uiteinden
- Frontend middelen naar de CDN versturen
- Container bouwen voor het Python-programma
- Container verzenden naar het register
- Kubernetes-manifest bijwerken
Oude code vervangen door nieuwe
- Kubernetes start meerdere instanties van de nieuwe container
- Kubernetes wacht tot de instanties operationeel zijn
- Kubernetes voegt instanties toe aan de HTTP-loadbalancer
- Kubernetes wacht tot oude instanties niet meer worden gebruikt
- Kubernetes stopt oude instanties
- Kubernetes herhaalt deze stappen totdat nieuwe instanties alle oude hebben vervangen
Nieuwe feature toggle inschakelen
- Nieuwe code wordt alleen voor zichzelf ingeschakeld om ervoor te zorgen dat alles goed werkt
- Nieuwe code wordt ingeschakeld voor 10% van de gebruikers; operationele en zakelijke metrics worden gevolgd
- Nieuwe code wordt ingeschakeld voor 50% van de gebruikers; operationele en zakelijke metrics worden gevolgd
- Nieuwe code wordt ingeschakeld voor 100% van de gebruikers; operationele en zakelijke metrics worden gevolgd
- Ten slotte herhaalt u de hele procedure om de oude code en toggle te verwijderen
Het proces is afhankelijk van de tools, de taal en het gebruik van servicegerichte architecturen, maar in grote lijnen ziet het er zo uit. Ik heb het niet over uitrol met database-migratie, omdat hiervoor zorgvuldige planning nodig is, maar hieronder leg ik uit hoe Dark hiermee omgaat.
Er zijn veel componenten en veel van hen kunnen gemakkelijk vertragingen, crashes, tijdelijke concurrentie of falende systemen veroorzaken.
En aangezien deze pipelines vrijwel altijd voor een specifieke situatie zijn gemaakt, is het moeilijk om erop te vertrouwen. Veel mensen hebben dagen waarop het onmogelijk is om code uit te rollen omdat er problemen zijn met de Dockerfile, een van de tientallen services is gecrasht of de benodigde specialist met verlof is.
Slechter nog, veel van deze stappen doen totaal niets nuttigs. Ze waren eerder nodig toen we code rechtstreeks voor gebruikers uitrolden, maar nu hebben we toggles voor nieuwe code en zijn deze processen gescheiden. Uiteindelijk is de stap waarop code wordt uitgerold (de oude wordt vervangen door de nieuwe) nu gewoon een onnodig risico.
Natuurlijk is dit een zeer doordachte pipeline. Het team dat deze heeft gemaakt, heeft geen moeite en geld gespaard om snelle uitrol mogelijk te maken. Gewoonlijk zijn uitrolpipelines veel langzamer en onbetrouwbaarder.
Implementatie van continue levering in Dark
Continue levering delivery is so important for Dark that we aimed for sub-second times from the very beginning. We went through every step of the pipeline to eliminate the superfluous and refined the rest. Hereās how we streamlined the steps.
Jessie Frazelle () coined the term deployless at the Future of Software Development conference in Reykjavik.
We immediately decided that Dark would be based on the concept of deployless (thanks to for the neologism). Deployless means that any code is deployed instantly and ready for production use. Of course, we won't bypass faulty or incomplete code (security principles will be detailed below).
During the Dark demonstration, we were often asked how we managed to accelerate deployment so drastically. A strange question. People might think we invented some super-technology that compares code, compiles it, packages it into a container, launches a virtual machine, cold starts the container, and all that within 50 ms. Itās unlikely that's possible. But we created a special deployment engine that doesnāt require any of that.
Dark runs interpreters in the cloud. Letās say you write code in a function or HTTP/event handler. We send the diff to an abstract syntax tree (the internal implementation of the code used by our editor and servers) on our servers and run that code when requests come in. So, deployment looks just like a simple database entry ā instant and straightforward. The deployment happens so fast because it includes the bare minimum.
In the future, we plan to make Dark an infrastructure compiler that will create and run the ideal infrastructure for high performance and reliability of applications. Instant deployment certainly isn't going anywhere.
Safe deployment
Structured Editor
Code in Dark is written in the Dark editor. The structured editor doesn't allow syntax errors. Essentially, there isnāt even a parser in Dark. As you type text, we work directly with the abstract syntax tree (AST), just like , , , en .
Every unfinished code in Dark has a permissible execution semantics, somewhat like . Bijvoorbeeld, als je een functieaanroep wijzigt, bewaren we de oude functie totdat de nieuwe klaar is voor gebruik.
Elke applicatie in Dark heeft zijn eigen betekenis, daarom stoort onafgemaakte code de voltooide niet.
Bewerkingsmodi
Je schrijft code in Dark in twee situaties. Ten eerste: je schrijft nieuwe code en bent de enige gebruiker. Bijvoorbeeld, als je het in REPL doet, hebben andere gebruikers er nooit toegang toe, of het is een nieuwe HTTP-route waar je nergens naar verwijst. In dit geval kun je zonder enige voorzorgsmaatregelen werken, en dit is ongeveer hoe je nu in de ontwikkelomgeving werkt.
De tweede situatie: de code wordt al gebruikt. Als er verkeer door de code gaat (functies, event handlers, databases, etc.), moet je voorzichtig zijn. Daarom blokkeren we alle gebruikte code en vereisen we het gebruik van meer gestructureerde tools voor bewerking. Over gestructureerde tools zal ik hieronder vertellen: functie-switches voor HTTP- en event handlers, een krachtige migratieplatform voor databases en een nieuwe manier om versies te beheren voor functies en types.
Functie-switches
Een van de manieren in Dark te verminderen, is door meerdere problemen met ƩƩn oplossing aan te pakken. Functie-switches vervullen veel verschillende taken: het vervangen van een lokale ontwikkelomgeving, git-branching, code-implementatie en, natuurlijk, de traditionele langzame en gecontroleerde uitrol van nieuwe code.
Het creƫren en implementeren van een functie-switch gebeurt in onze editor in ƩƩn handeling. Het creƫert een lege ruimte voor nieuwe code en biedt toegangselementen voor oude en nieuwe code, evenals knoppen en opdrachten voor een geleidelijke overgang naar de nieuwe code of het uitsluiten ervan.
Functie-switches zijn ingebouwd in de taal Dark, en zelfs onafgemaakte switches vervullen hun taak ā als de voorwaarde in de switch niet wordt voldaan, zal de oude geblokkeerde code worden uitgevoerd.
Ontwikkelomgeving
Functieverdelers vervangen de lokale ontwikkelomgeving. Tegenwoordig is het voor teams moeilijk om ervoor te zorgen dat iedereen dezelfde versies van tools en bibliotheken gebruikt (codeformatteertools, linters, pakketbeheerders, compilers, preprocessors, testtools, enzovoort). Met Dark hoeft u niets lokaal te installeren, geen lokale Docker-installatie te beheren of andere maatregelen te nemen om zelfs maar een gelijkenis tussen de ontwikkelomgeving en de productieomgeving te waarborgen. , zullen we zelfs niet doen alsof we ernaar streven.
In plaats van een gekloonde lokale omgeving te creƫren, creƫren de schakelaars in Dark een nieuwe sandbox in productie, die de ontwikkelomgeving vervangt. In de toekomst zijn we ook van plan om sandboxes voor andere delen van de applicatie te creƫren (zoals directe klonen van de database), hoewel dat momenteel niet zo belangrijk lijkt.
Branches en implementaties
Er zijn momenteel verschillende manieren om nieuwe code in systemen te introduceren: git-branches, implementatiefases en functieverdelers. Ze lossen ƩƩn probleem op in verschillende delen van de workflow: git ā tijdens de fasen voor implementatie, implementatie ā op het moment dat we van de oude code naar de nieuwe overschakelen, en functieverdelers ā voor gecontroleerde uitrol van nieuwe code.
De meest effectieve manier zijn functieverdelers (tegelijkertijd de eenvoudigste om te begrijpen en te gebruiken). Ze maken het mogelijk om volledig af te zien van de andere twee methoden. Het is vooral nuttig om de implementatie te verwijderen ā als we toch functieverdelers gebruiken om code in te schakelen, creĆ«ert de stap om servers op nieuwe code over te zetten alleen maar extra risico.
Git is moeilijk te gebruiken, vooral voor beginners, en dat beperkt het enorm, maar het heeft wel handige branches. We hebben veel van de nadelen van git gladgestreken. Dark is in realtime bewerkbaar en biedt samenwerking in de stijl van Google Documenten, zodat je geen code hoeft op te sturen en minder vaak hoeft te rebasen en samen te voegen.
Functieschakelaars vormen de basis van veilige implementatie. Samen met directe implementaties stellen ze ons in staat om concepten snel te testen in kleine segmenten met een laag risico, in plaats van ƩƩn grote wijziging toe te passen die het systeem kan laten crashen.
Versiebeheer
Voor het wijzigen van functies en types maken we gebruik van versiebeheer. Als u een functie wilt wijzigen, maakt Dark een nieuwe versie van die functie. U kunt deze versie vervolgens aanroepen met behulp van een schakelaar in de HTTP- of evenementenhandler. (Als deze functie diep in de oproepgrafiek zit, wordt onderweg een nieuwe versie van elke functie gemaakt. Dit lijkt misschien teveel, maar functies verstoren elkaar niet als u ze niet gebruikt, dus u zult het misschien niet opmerken.)
Om dezelfde redenen versioneren we ook types. We hebben uitgebreid over ons typesysteem gesproken. .
Dankzij het versiebeheer van functies en types kunt u gelaagd wijzigingen in de applicatie aanbrengen. U kunt verifiƫren dat elke afzonderlijke handler werkt met de nieuwe versie, zonder dat u alle wijzigingen onmiddellijk in de applicatie hoeft aan te brengen (maar we hebben tools om dit snel te doen als u dat wilt).
Dit is veel veiliger dan het gelijktijdig implementeren van alles, zoals nu het geval is.
Nieuwe versies van pakketten en de standaardbibliotheek
Wanneer u een pakket in Dark bijwerkt, vervangen we niet onmiddellijk het gebruik van elke functie of type in de gehele codebase. Dit is onveilig. De code blijft de versie gebruiken die deze gebruikte, terwijl u het gebruik van functies en types bijwerkt naar de nieuwe versie voor elke afzonderlijke instantie met behulp van schakelaars.
Screenshot van een deel van het automatische proces in Dark, waarop twee versies van de functie Dict::get worden getoond. Dict::get_v0 retourneerde het type Any (waarvan we afzien), terwijl Dict::get_v1 het type Option retourneert.
We bieden vaak een nieuwe functie in de standaardbibliotheek aan en sluiten oude versies uit. Gebruikers met oude versies in hun code behouden toegang tot deze, maar nieuwe gebruikers kunnen deze niet meer krijgen. We zijn van plan om tools te bieden om gebruikers in ƩƩn stap van oude versies naar nieuwe te migreren, wederom met behulp van functievensters.
Dark biedt ook een unieke kans: omdat we uw werkcode uitvoeren, kunnen we zelf nieuwe versies testen door de uitvoer voor nieuwe en oude verzoeken te vergelijken, zodat we u op de hoogte kunnen stellen van wijzigingen. Als gevolg hiervan brengt de pakketupdate, die vaak blindeling wordt uitgevoerd (of grondig getest moet worden voor de veiligheid), veel minder risico's met zich mee en kan deze automatisch plaatsvinden.
Nieuwe versies van Dark
De overgang van Python 2 naar Python 3 heeft een decennium geduurd en blijft een probleem. Omdat we Dark ontwikkelen voor continue levering, moeten we rekening houden met deze taalaanpassingen.
Wanneer we kleine wijzigingen in de taal aanbrengen, creƫren we een nieuwe versie van Dark. Oude code blijft in de oude versie van Dark, terwijl nieuwe code in de nieuwe versie wordt gebruikt. Om over te schakelen naar de nieuwe versie van Dark kunnen schakelaars of functieversies worden gebruikt.
Dit is bijzonder nuttig, gezien het feit dat Dark nog maar recent is verschenen. Veel wijzigingen in de taal of bibliotheek kunnen mislukt zijn. Geleidelijk versiebeheer van de taal stelt ons in staat om kleine updates uit te voeren, wat betekent dat we niet haasten en veel taalkwesties uitstellen totdat we meer gebruikers hebben, en dus meer informatie.
Database-migraties
Voor een veilige migratie van databases bestaat er :
- Herschrijf de code om zowel het nieuwe als het oude formaat te ondersteunen.
- Converteer alle gegevens naar het nieuwe formaat.
- Verwijder de oude toegang tot gegevens.
Uiteindelijk neemt de migratie van de database veel tijd in beslag en vereist het veel middelen. En we verzamelen verouderde schema's, aangezien zelfs eenvoudige taken, zoals het corrigeren van een tabel- of kolomnamen, de moeite niet waard zijn.
Dark heeft een efficiƫnt database-migratieplatform dat (hoop ik) het proces zo zal vereenvoudigen dat u er geen angst meer voor heeft. Alle gegevensopslag in Dark (opslag van 'sleutel-waarde'-paren of permanente hash-tabellen) heeft een type. Om een gegevensopslag te verplaatsen, wijst u eenvoudig een nieuw type en functie voor terug- en vooruitzetten toe voor het omzetten van waarden tussen de twee types.
Toegang tot data-opslag in Dark geschiedt via versies van variabelen. Bijvoorbeeld, de data-opslag Users wordt aanvankelijk Users-v0 genoemd. Wanneer er een nieuwe versie met een andere soort wordt aangemaakt, verandert de naam in Users-v1. Als gegevens zijn opgeslagen via Users-v0 en u deze benadert via Users-v1, wordt de rollback-functie toegepast. Als gegevens zijn opgeslagen via Users-v1 en u deze benadert via Users-v0, wordt de terugdraai-functie toegepast.
Het migratiescherm van de database toont de veldnamen van de oude database, evenals de rollback- en terugdraai-expressies en instructies voor het inschakelen van de migratie.
Gebruik functie-schakelaars om verzoeken naar Users-v0 te sturen in versie Users-v1. Dit kan per HTTP-handler worden gedaan om risico's te minimaliseren, en de schakelaars werken ook voor individuele gebruikers, zodat u kunt controleren of alles werkt zoals verwacht. Zodra er geen gebruikers van Users-v0 meer zijn, zal Dark alle resterende gegevens op de achtergrond omzetten van het oude formaat naar het nieuwe. Dit zult u nauwelijks opmerken.
Testen
Dark is een en onveranderlijke waarden, waardoor de testoppervlakte aanzienlijk kleiner is dan bij objectgeoriƫnteerde talen met dynamische typing. Maar testen blijft noodzakelijk.
In Dark worden moduletests automatisch op de achtergrond uitgevoerd voor de bewerkbare code, en deze tests worden standaard uitgevoerd voor alle functie-schakelaars. In de toekomst willen we met behulp van statische types automatisch fuzzing van de code uitvoeren om bugs te vinden.
Bovendien draait Dark uw infrastructuur in productie, wat nieuwe mogelijkheden opent. We slaan automatisch HTTP-verzoeken op in de Dark-infrastructuur (voorlopig slaan we alle verzoeken op, maar later willen we overschakelen naar sampling). We testen nieuw code op basis daarvan en voeren moduletests uit, en als u wilt, kunt u gemakkelijk interessante verzoeken omzetten in moduletests.
Waar we vanaf zijn
Aangezien we geen implementatie hebben, maar wel functie-schakelaars, blijft ongeveer 60% van de implementatie-pijplijn buiten beschouwing. We hebben geen git-branches of pull-requests nodig, geen backend-broncoderingen en containers, geen verzending van bronnen en containers naar registers, en geen implementati stappen in Kubernetes.
Vergelijking tussen de standaard pipeline voor continue levering (links) en de Dark continue levering (rechts). In Dark bestaat de levering uit 6 stappen en 1 cyclus, terwijl de traditionele versie 35 stappen en 3 cycli omvat.
In Dark zijn er slechts 6 stappen en 1 cyclus in de implementatie (stappen die meerdere keren worden herhaald), terwijl een moderne pipeline voor continue levering bestaat uit 35 stappen en 3 cycli. In Dark worden tests automatisch uitgevoerd, en dit zie je niet eens; afhankelijkheden worden automatisch geĆÆnstalleerd; alles wat met git of GitHub te maken heeft, is niet meer nodig; het bouwen, testen en verzenden van Docker-containers is niet meer nodig; implementatie in Kubernetes is niet meer nodig.
Zelfs de resterende stappen in Dark zijn eenvoudiger geworden. Omdat functie-schakelaars met ƩƩn actie kunnen worden beheerd, is het niet nodig om opnieuw door de gehele implementatie-pipeline te gaan om oude code te verwijderen.
We hebben de levering van code zoveel mogelijk vereenvoudigd door de tijd en risico's van continue levering te verkorten. Bovendien hebben we het bijwerken van pakketten, database-migraties, testen, versiebeheer, het installeren van afhankelijkheden, gelijkenis tussen ontwikkel- en productieomgevingen en snelle en veilige upgrades van taalversies aanzienlijk vereenvoudigd.
Ik beantwoord vragen hierover op .
Om meer te leren over het Dark-apparaat, lees , (of op ) of . Als je in september naar StrangeLoop gaat, .
Bron: habr.com
