Hvordan Dark implementerer kode på 50 ms

Hvordan Dark implementerer kode på 50 ms

Jo hurtigere udviklingsprocessen er, desto hurtigere vokser teknologivirksomheden.

Desværre arbejder moderne applikationer imod os - vores systemer skal opdateres i realtid uden at genere nogen og uden at føre til nedetid og afbrydelser. Udrulning i sådanne systemer bliver en kompleks opgave og kræver komplekse pipelines til kontinuerlig levering, selv i små teams.

Disse pipelines har ofte en snæver anvendelse, arbejder langsomt og er ikke særlig pålidelige. Udviklere skal først oprette dem manuelt og derefter administrere dem, og virksomheder ansætter ofte hele DevOps-teams til dette.

Hastigheden af disse pipelines bestemmer hastigheden af udviklingen. For de bedste teams tager udrulning 5-10 minutter, men normalt tager det meget længere, og én udrulning kræver flere timer.

I Dark tager det 50 ms. Fifty. Milliseconds. Dark - det er en omfattende løsning med et programmeringssprog, en editor og infrastruktur, der er skabt specifikt til kontinuerlig levering, og alle aspekter af Dark, herunder selve sproget, er bygget med henblik på sikker øjeblikkelig udrulning.

Hvorfor er pipelines til kontinuerlig levering så langsomme?

Lad os sige, vi har en Python-webapplikation, og vi allerede har oprettet en fantastisk og moderne pipeline til kontinuerlig levering. For udvikleren, der dagligt arbejder på dette projekt, vil udrulning af en lille ændring se nogenlunde således ud:

Foretagelse af ændringer

  • Oprettelse af en ny gren i git
  • Foretagelse af ændringer bag en funktionsskifter
  • Modultest for at kontrollere ændringer med og uden funktionsskifter

Pull-request

  • Commit af ændringer
  • Send ændringer til den fjerne repository på github
  • Pull-request
  • CI-bygningen udføres automatisk i baggrunden
  • Kodegennemgang
  • Yderligere nogle gennemgange, hvis nødvendigt
  • Sammenflet ændringerne med master-grenen i git.

CI udføres på masteren

  • Installation af frontend-afhængigheder via npm
  • Bygning og optimering af HTML+CSS+JS-ressourcer
  • Kørsel af modulære og funktionelle tests i frontenden
  • Installation af Python-afhængigheder fra PyPI
  • Kørsel af modulære og funktionelle tests i backend
  • Integrationstest i begge ender
  • Send frontend-ressourcer til CDN
  • Bygning af containeren til Python-programmet
  • Afsendelse af container til registrering
  • Opdatering af Kubernetes-manifest

Udskiftning af gammel kode med ny

  • Kubernetes kører flere instanser af den nye container
  • Kubernetes venter på, at instanserne bliver operationelle
  • Kubernetes tilføjer instanser til HTTP-loadbalanceret
  • Kubernetes venter på, at de gamle instanser ikke længere bliver brugt
  • Kubernetes stopper de gamle instanser
  • Kubernetes gentager disse operationer, indtil alle gamle instanser er blevet udskiftet

Aktivering af den nye funktionsskifter

  • Den nye kode aktiveres kun for sig selv for at sikre, at alt fungerer korrekt
  • Den nye kode aktiveres for 10% af brugerne; drifts- og forretningsmetrikker overvåges
  • Den nye kode aktiveres for 50% af brugerne; drifts- og forretningsmetrikker overvåges
  • Den nye kode aktiveres for 100% af brugerne; drifts- og forretningsmetrikker overvåges
  • Til sidst gentager du hele proceduren for at fjerne den gamle kode og skifteren

Processen afhænger af værktøjer, sprog og brug af serviceorienterede arkitekturer, men generelt ser det sådan ud. Jeg nævnte ikke implementeringer med database-migrering, fordi det kræver omhyggelig planlægning, men nedenfor vil jeg beskrive, hvordan Dark håndterer dette.

Der er mange komponenter, og mange af dem kan let bremse, fejle, skabe midlertidig konkurrence eller knække det arbejdende system.

Og da disse pipelines næsten altid er skræddersyede, er de svære at stole på. Mange oplever dage, hvor koden ikke kan implementeres, fordi der er problemer i Dockerfilen, en af de mange tjenester fejler, eller den nødvendige specialist er på ferie.

Værre endnu, mange af disse trin gør slet ikke noget nyttigt. De var nødvendige tidligere, da vi implementerede kode direkte til brugerne, men nu har vi skiftere til den nye kode, og disse processer er blevet opdelt. Resultatet er, at det trin, hvor koden implementeres (den gamle udskiftes med den nye), nu blot er en unødig risiko.

Selvfølgelig er dette en meget gennemført pipeline. Holdet, der skabte den, har ikke skånet tid eller penge for hurtig implementering. Normalt er implementeringspipelines meget langsommere og mindre pålidelige.

Implementering af kontinuerlig levering i Dark

Den kontinuerlige leverance er så vigtig for Dark, at vi fra starten sigtede mod en tid på mindre end et sekund. Vi har gennemgået alle trin i pipeline for at fjerne unødvendigheder og perfekt udforme det resterende. Sådan fjernede vi trin.

Jessie Frazelle (Jessie Frazelle) opfandt det nye ord deployless (uden deployment) på konferencen Future of Software Development i Reykjavik.

Vi besluttede straks, at Dark ville være baseret på konceptet 'deployless' (tak til Jessie Frazelle for neologismen). Deployless betyder, at enhver kode straks deployeres og er klar til brug i produktion. Selvfølgelig vil vi ikke lade defekt eller ufuldstændig kode slippe igennem (sikkerhedsprincipperne vil jeg beskrive nedenfor).

Under Dark-demonstrationer blev vi ofte spurgt, hvordan vi kunne accelerere deployment så meget. Underligt spørgsmål. Folk tænker sikkert, at vi har opfundet en superteknologi, der sammenligner koden, kompilere den, pakkere den i en container, starter en virtuel maskine, og ved kolde opstarter containeren, alt sammen på 50 ms. Det er næppe muligt. Men vi har skabt en særlig deployment-motor, der ikke har brug for det.

Dark kører tolke i skyen. Antag, at du skriver kode i en funktion eller en HTTP- eller event-handler. Vi sender forskellen til det abstrakte syntaktiske træ (den kodeimplementering, som vores editor og servere bruger internt) til vores servere og udfører så denne kode, når der kommer forespørgsler. Så deployment ser ganske enkelt ud som en besked til databasen — øjeblikkelig og simpel. Deployment foregår så hurtigt, fordi det kun inkluderer det mest nødvendige.

I fremtiden planlægger vi at lave Dark til en infrastrukturcompiler, som vil skabe og køre den ideelle infrastruktur for høj ydeevne og pålidelighed af applikationer. Øjeblikkelig deployment forsvinder selvfølgelig ikke.

Sikker deployment

Struktureret editor

Koden i Dark skrives i Dark-editoren. Den strukturerede editor tillader ikke syntaksfejl. Faktisk findes der ikke engang en parser i Dark. Mens du indtaster tekst, arbejder vi direkte med det abstrakte syntaktiske træ (AST), ligesom Paredit, Sketch-n-Sketch, Tofu, Prune og MPS.

Enhver ufuldendt kode i Dark har en gyldig kørselssemantikken, omtrent som typed holes i HazelFor example, if you change the function call, we keep the old function until the new one is ready.

Every program in Dark has its purpose, so incomplete code does not interfere with completed code.

Editing Modes

You write code in Dark in two cases. First: you are writing new code and are the sole user. For example, it’s in REPL, and other users will never have access to it, or it’s a new HTTP route that you’re not referencing anywhere. Here you can work without any precautions, and you’re currently doing just that in the development environment.

The second situation: the code is already in use. If traffic is flowing through the code (functions, event handlers, databases, etc.), caution is required. For this, we block all used code and require more structured tools for editing it. I’ll talk about the structured tools below: feature toggles for HTTP and event handlers, a powerful migration platform for databases, and a new version management method for functions and types.

Feature Toggles

One way to reduce unnecessary complexity in Dark is to solve multiple problems with one solution. Feature toggles perform various tasks: replacing the local development environment, git branches, deploying code, and of course, the traditional slow and controlled release of new code.

Creating and deploying a feature toggle is done in our editor in one operation. It creates an empty space for the new code and provides controls to access both the old and new code, as well as buttons and commands for gradually shifting to the new code or excluding it.

Feature toggles are built into the Dark language, and even incomplete toggles do their job—if the condition in the toggle isn’t met, the old blocked code will execute.

Development Environment

Funktionsvælgere erstatter det lokale udviklingsmiljø. I dag er det svært for teams at holde styr på, at alle bruger de samme versioner af værktøjer og biblioteker (kodeformateringsværktøjer, linters, pakkehåndterere, compilere, preprocessorer, testværktøjer osv.). Med Dark er der ikke behov for at installere afhængigheder lokalt, administrere en lokal Docker-installation eller tage andre skridt for at sikre nogen form for lighed mellem udviklingsmiljøet og produktionen. Da sådanne ligheder alligevel er umulige,, vil vi ikke engang lade som om, at vi stræber efter det.

I stedet for at oprette et klonet lokalt miljø, skaber funktionvelgere i Dark en ny sandkasse i produktionen, der erstatter udviklingsmiljøet. I fremtiden planlægger vi også at skabe sandkasser til andre dele af applikationen (f.eks. øjeblikkelige kloner af databaser), selvom det ikke virker så vigtigt lige nu.

Grene og implementeringer

Der er i øjeblikket flere måder at få ny kode ind i systemerne på: git-grene, implementeringsfaser og funktionsvelgere. De adresserer et problem i forskellige dele af arbejdsgangen: git — i faserne før implementeringen, implementeringen — i det øjeblik, vi går fra gammel kode til ny, og funktionsvelgere — til kontrolleret udgivelse af ny kode.

Den mest effektive metode er funktionsvelgere (og også den nemmeste at forstå og bruge). Med dem kan man helt undvære de to andre metoder. Især er det nyttigt at eliminere implementeringen — hvis vi trods alt bruger funktionsvelgere til at aktivere koden, så skaber skridtet med at overføre servere til den nye kode kun unødige risici.

Git er svært at bruge, især for nybegyndere, hvilket begrænser dets anvendelse, men det har den fordel, at det har praktiske grene. Vi har afhjulpet mange af git's ulemper. Dark redigeres i realtid og muliggør samarbejde i stil med Google D/docs, så man ikke behøver at sende kode, og man kan oftere undgå rebase og merge.

Funktioneressourcer udgør kernen i sikker implementering. Sammen med øjeblikkelige implementeringer giver de mulighed for hurtigt at teste koncepter i små bidder med lav risiko i stedet for at anvende én stor ændring, der kan bringe systemet i fare.

Versionering

Til ændring af funktioner og typer benytter vi versionering. Hvis du ønsker at ændre en funktion, opretter Dark en ny version af denne funktion. Du kan derefter kalde denne version med en switch i HTTP- eller begivenhedshåndteringen. (Hvis det er en funktion dybt i kaldetræet, oprettes der automatisk en ny version for hver funktion. Det kan virke overdrevet, men funktionerne interfererer ikke, hvis du ikke bruger dem, så du vil ikke engang bemærke det.)

Af de samme grunde versionerer vi typer. Vi har tidligere beskrevet vores typesystem i det forrige indlæg.

Med versionering af funktioner og typer kan du implementere ændringer i applikationen gradvist. Du kan kontrollere, at hver enkelt handler fungerer med den nye version uden at skulle ændre alt i applikationerne på én gang (men vi har værktøjer til hurtigt at gøre det, hvis du ønsker).

Det er langt sikrere end straks at implementere alt på én gang, som det er tilfældet nu.

Nye versioner af pakker og standardbiblioteket

Når du opdaterer en pakke i Dark, erstatter vi ikke straks brugen af hver funktion eller type i hele kodebasen. Det er ikke sikkert. Koden fortsætter med at bruge den samme version, som den brugte før, mens du opdaterer brugen af funktioner og typer til den nye version for hvert enkelt tilfælde ved hjælp af switches.

Hvordan Dark implementerer kode på 50 ms
Skærmbillede af en del af den automatiske proces i Dark, der viser to versioner af funktionen Dict::get. Dict::get_v0 returnerede typen Any (som vi fraskriver os), mens Dict::get_v1 returnerer typen Option.

Vi tilbyder ofte en ny funktion i standardbiblioteket og fjerner ældre versioner. Brugere med ældre versioner i koden vil stadig have adgang til dem, men nye brugere vil ikke kunne få adgang til dem. Vi planlægger at tilbyde værktøjer til at migrere brugere fra ældre versioner til nye med et enkelt trin, også ved hjælp af funktionsswitch.

Dark giver også en unik mulighed: da vi kører din arbejds kode, kan vi selv teste nye versioner ved at sammenligne output for nye og gamle forespørgsler, så vi kan informere dig om ændringerne. Som følge heraf indebærer opdatering af pakker, som ofte udføres blindt (eller kræver omfattende sikkerhedstest), langt færre risici og kan udføres automatisk.

Nye versioner af Dark

Overgangen fra Python 2 til Python 3 strakte sig over et årti og forbliver stadig et problem. Da vi udvikler Dark til kontinuerlig levering, skal disse sprogændringer tages i betragtning.

Når vi laver mindre ændringer i sproget, opretter vi en ny version af Dark. Den gamle kode forbliver i den gamle version af Dark, mens den nye kode anvendes i den nye version. For at skifte til den nye version af Dark kan du bruge omskiftere eller funktionsversioner.

Dette er særligt nyttigt, da Dark er relativt nyt. Mange ændringer i sproget eller biblioteket kan vise sig at være mislykkede. Trinvist versionering af sproget gør det muligt for os at foretage små opdateringer, dvs. vi behøver ikke at skynde os og kan udsætte mange beslutninger om sproget, indtil vi har flere brugere, hvilket betyder, at vi også får mere information.

Database-migrationer

Der findes en standardformel til sikker migration af databaser Tilpas koden til at understøtte nye og gamle formater:

  • Konverter alle data til det nye format
  • Fjern gammel adgang til data
  • Som følge heraf trækker database-migrationen ud og kræver mange ressourcer. Og vi har et ophobning af forældede skemaer, da selv simple opgaver som at rette navnet på en tabel eller kolonne ikke er værd at den tid, der bruges.

Dark har en effektiv database-migrationsplatform, der (forhåbentlig) vil forenkle processen så meget, at du ikke længere vil frygte den. Alle datalagre i Dark (key-value par lagre eller permanente hash-tabeller) har en type. For at overføre datalageret, skal du blot tildele det en ny type og en rollback- og rollforward-funktion til konvertering af værdier mellem de to typer.

Dark har en effektiv database migrationsplatform, som (vi håber) vil gøre processen så simpel, at du ikke længere vil frygte den. Alle datalagre i Dark (key-value par lagre eller permanente hash-tabeller) har en type. For at overføre et datalager tildeler du det blot en ny type og en rollback- og redeploy-funktion til at konvertere værdierne mellem de to typer.

Adgang til datalagre i Dark sker gennem versionsstyrede variabelnavne. For eksempel vil datalageret Users oprindeligt blive kaldt Users-v0. Når der oprettes en ny version med en anden type, ændres navnet til Users-v1. Hvis data er gemt via Users-v0, og du tilgår dem gennem Users-v1, anvendes rollback-funktionen. Hvis data er gemt via Users-v1, og du tilgår dem gennem Users-v0, anvendes rollback-funktionen.

Hvordan Dark implementerer kode på 50 ms
Skærmbilledet til migrering af databasen indeholder navne på felterne i den gamle database, rollback- og undo-udtryk samt instruktioner til at aktivere migreringen.

Brug funktionsswitcher til at dirigere kald til Users-v0 til version Users-v1. Dette kan gøres en HTTP-handler ad gangen for at mindske risiciene, og switcherne fungerer for enkelte brugere, så du kan teste, at alt fungerer som forventet. Når der ikke er flere brugere af Users-v0, konverterer Dark alle resterende data i baggrunden fra det gamle format til det nye. Du vil næppe bemærke det.

Testning

Dark er en funktionsbaseret programmeringssprog med statisk type og umodificerbare værdier, så testfladen er betydeligt mindre sammenlignet med objektorienterede sprog med dynamisk type. Men der skal stadig testes.
I Dark udfører editoren automatisk unit tests i baggrunden for den redigerede kode og kører som standard disse tests for alle funktionsswitcher. I fremtiden ønsker vi at udføre fuzzing af koden automatisk ved hjælp af statiske typer, så vi kan finde fejl.

Derudover kører Dark din infrastruktur i produktion, hvilket åbner nye muligheder. Vi gemmer automatisk HTTP-anmodninger i Dark-infrastrukturen (indtil videre gemmer vi alle anmodninger, men senere ønsker vi at overgå til sampling). Vi tester nyt kode og udfører unit tests på dem, og hvis du ønsker det, kan du nemt konvertere interessante anmodninger til unit tests.

Hvad vi har sagt farvel til

Da vi ikke har deployment, men har funktionsswitcher, forbliver omkring 60% af deploymentsystemet udenfor. Vi har ikke brug for git branches eller pull requests, bygging af backend-ressourcer og containere, upload af ressourcer og containere til registre eller deployment-trin i Kubernetes.

Hvordan Dark implementerer kode på 50 ms
Sammenligning af den standardiserede pipeline til kontinuerlig levering (til venstre) og kontinuerlig levering Dark (til højre). I Dark består leveringen af 6 trin og 1 cyklus, mens den traditionelle version inkluderer 35 trin og 3 cyklusser.

I Dark er der kun 6 trin og 1 cyklus i deployment (trin, der gentages flere gange), mens den moderne pipeline til kontinuerlig levering består af 35 trin og 3 cyklusser. I Dark køres testene automatisk, og du ser det endda ikke; afhængigheder installeres automatisk; alt, der relaterer til git eller Github, er ikke længere nødvendigt; at bygge, teste og sende Docker-containere er ikke nødvendigt; deployment i Kubernetes er ikke længere nødvendigt.

Selv de resterende trin i Dark er blevet enklere. Da funktionsswitchene kan styres med én handling, behøver man ikke at gennemgå hele deployment-pipelinen igen for at fjerne gammel kode.

Vi har gjort vores bedste for at forenkle kodens levering, hvilket har reduceret tid og risici ved kontinuerlig levering. Og vi har også betydeligt forenklet opdatering af pakker, database-migreringer, test, versionsstyring, installation af afhængigheder, lighed mellem udviklings- og produktionsmiljøer og hurtige og sikre opgraderinger af sprogversioner.

Jeg svarer på spørgsmål om dette på HackerNews.

For at lære mere om Dark, læs artiklen om Dark, følg os på Twitter (eller på mig) eller tilmeld dig beta-versionen og modtag notifikationer om kommende indlæg. Hvis du tager til StrangeLoop i september, kom og besøg os til lanceringen.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster