Kuidas Dark käivitab koodi 50 ms jooksul

Kuidas Dark käivitab koodi 50 ms jooksul

Mida kiiremini toimub arendamine, seda kiiremini areneb tehnoloogiaettevõte.

Kahjuks töötavad tänapäeva rakendused meie vastu - meie süsteemid peavad olema reaalajas uuendatud, segamata samas kedagi ning põhjustamata viivitusi ja katkestusi. Sellistes süsteemides on juurutamine keeruline ülesanne ja nõuab isegi väikestes meeskondades keerulisi pideva tarnimise vooge.

Need vooged on tavaliselt kitsaste rakendustega, töötavad aeglaselt ja ei ole usaldusväärsed. Arendajad peavad need esmalt käsitsi looma ja seejärel haldama ning ettevõtted palgavad sageli selleks eraldi DevOps meeskondi.

Need vood mõjutavad arendamise kiirus. Parimate meeskondade puhul kestab juurutamine 5–10 minutit, kuid tavaliselt võtab see aega palju kauem ja ühe juurutuse jaoks kulub mitu tundi.

Darkis kulub sellele 50 ms. Viiskümmend. Millisekundit.. Dark - see on integreeritud lahendus programmeerimiskeele, redigeerija ja infrastruktuuriga, mis on loodud spetsiaalselt pidevaks tarnimiseks, ja kõik Darki aspektid, sealhulgas keele loomine, on üles ehitatud ohutuks koheseks juurutamiseks.

Miks on pideva tarnimise vood nii aeglased?

Oletame, et meil on olemas Python veebirakendus ja me oleme juba loonud suurepärase ja kaasaegse pideva tarnimise voo. Arendaja jaoks, kes igapäevaselt selle projektiga tegeleb, näeb ühe väikese muudatuse juurutamine välja enam-vähem selline:

Muutuste tegemine

  • Uue haru loomine git'is
  • Muutuste tegemine funktsioonide vahetamise korral
  • Moodulitestimine muudatuste kontrollimiseks funktsioonide vahetamisega ja ilma selleta

Pull-request

  • Muutuste commitimine
  • Muutuste saatmine kaugrepositoriosse github'is
  • Pull-request
  • CI kokkupanekut teostatakse automaatselt taustal
  • Koodi ülevaatus
  • Veel mõned ülevaatused, kui on vaja
  • Muudatuste sulandumine git masteriga.

CI teostatakse masteris

  • Frontend sõltuvuste installimine läbi npm
  • HTML + CSS + JS ressursside kokkupanek ja optimeerimine
  • Frontendis moodul- ja funktsionaalsete testide läbiviimine
  • Python sõltuvuste installimine PyPI-st
  • Backendis moodul- ja funktsionaalsete testide läbiviimine
  • Integreerimistestide läbiviimine mõlemas otsas
  • Frontend ressursside saatmine CDN-i
  • Python programmi konteineri kokkupanek
  • Konteineri registreerimine
  • Kubernetes'i manifesti värskendamine

Vana koodi asendamine uuega

  • Kubernetes käivitab mitu uue konteineri eksemplari
  • Kubernetes ootab, et eksemplarid saaksid töökorda
  • Kubernetes lisab eksemplarid HTTP koormuse tasakaalustajasse
  • Kubernetes ootab, kuni vanad eksemplarid lõpetavad kasutamise
  • Kubernetes peatab vanad eksemplarid
  • Kubernetes kordab neid toiminguid, kuni uued eksemplarid asendavad kõik vanad

Uue funktsiooni lüliti aktiveerimine

  • Uus kood aktiveeritakse vaid endale, et veenduda, et kõik on korras
  • Uus kood aktiveeritakse 10% kasutajatest, jälgitakse operatiiv- ja ärimõõdikuid
  • Uus kood aktiveeritakse 50% kasutajatest, jälgitakse operatiiv- ja ärimõõdikuid
  • Uus kood aktiveeritakse 100% kasutajatest, jälgitakse operatiiv- ja ärimõõdikuid
  • Lõpuks tõstate kogu protseduuri, et eemaldada vana kood ja lüliti

Protsess sõltub tööriistadest, keelest ja teenustele orienteeritud arhitektuuride kasutamisest, kuid üldiselt näeb see välja nii. Ma ei maininud andmebaasi migreerimisega seotud juurutusi, kuna nende jaoks on vajalik hoolikas planeerimine, kuid allpool räägin, kuidas Dark sellega tegeleb.

Siin on palju komponente ning paljud neist võivad kergesti aeglustuda, kokku kukkuda, põhjustada ajutist konkurentsi või crashida töösüsteemi.

Ja kuna need torujuhtmed on peaaegu alati loodud erijuhtumiks, on neile raske toetuda. Paljudel on päevi, mil koodi ei saa juurutada, kuna Dockerfile’is on probleeme, mõnes kümnes teenuses on tõrge või vajalik spetsialist on puhkusel.

Halvem on see, et paljud neist sammudest ei tee üleüldse midagi kasulikku. Need olid vajalikud varem, kui juurutasime koodi otse kasutajatele, kuid nüüd on meil uue koodi jaoks lülitid ja need protsessid on eraldi. Lõpptulemusena on samm, kus kood juurutatakse (vana asendatakse uuega), nüüd lihtsalt ülemäärane risk.

Muidugi on see väga läbi mõeldud torujuhtme lahendus. Meeskond, kes selle lõi, ei kahetsenud aega ja raha kiiresti juurutamiseks. Üldiselt on juurutustorud palju aeglasemad ja ebausaldusväärsemad.

Jätkuva tarnimise rakendamine Darkis

Constant supply is so important for Dark that we aimed for under one second from the very beginning. We went through every step of the pipeline to eliminate anything unnecessary and refined the rest. Here’s how we removed steps.

Jessie Frazelle (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 Jessie Frazelle for the neologism). Deployless means that any code is instantly deployed and ready for production use. Of course, we won’t miss any broken or incomplete code (I will outline the safety principles below).

At the Dark demonstration, we were often asked how we managed to accelerate deployments so much. A strange question. People probably 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 in 50 ms. That’s hardly possible. But we created a special deployment engine that doesn’t need that.

Dark runs interpreters in the cloud. Suppose you write code in a function or an HTTP or event handler. We send a diff to the abstract syntax tree (the code representation that our editor and servers internally use) to our servers and then run that code when requests come in. So deployment looks just like a simple database record — instantaneous and straightforward. Deployment happens so fast because it includes only the essentials.

In the future, we plan to make Dark an infrastructure compiler that will create and launch the perfect infrastructure for high performance and reliability of applications. Instant deployment, of course, will not go away.

Safe deployment

Structured editor

Code in Dark is written in the Dark editor. The structured editor does not allow syntax errors. Essentially, Dark doesn't even have a parser. While you are typing, we work directly with the abstract syntax tree (AST), just like Paredit, Sketch-n-Sketch, Tofu, Prune ja MPS.

Any unfinished code in Dark has valid execution semantics, somewhat like typed holes in Hazel. Näiteks, kui muudate funktsiooni kutsumistingimusi, hoiame vanad funktsioonid kuni uus on rakendatav.

Igal programmil Darkis on oma tähendus, seega ei sega lõpetamata kood lõpetatud koodi tööd.

Redigeerimisrežiimid

Te kirjutate Darkis koodi kahes olukorras. Esimene: kirjutate uut koodi ja olete ainus kasutaja. Näiteks on see REPL-is ja teised kasutajad ei saa sellele kunagi ligi, või see on uus HTTP marsruut, millele te kusagil viitate. Sellisel juhul saate töötada ilma ettevaatusabinõudeta ja praegu töötate just nii arenduskeskkonnas.

Teine olukord: kood on juba kasutuses. Kui koodis liigub liiklus (funktsioonid, sündmuskäitlejad, andmebaasid jne), tuleb olla ettevaatlik. Selleks blokeerime kogu kasutatava koodi ja nõuame, et kasutate selle redigeerimiseks struktureeritumaid tööriistu. Struktureeritud tööriistade kohta räägin allpool: funktsioonide lülitid HTTP ja sündmuskäitlejate jaoks, tugeva andmebaasi migratsiooni platvorm ja uus versioonihalduse meetod funktsioonide ja tüüpide jaoks.

Funktsioonide lülitid

Üks viis liigse keerukuse eemaldamiseks Darkis — on lahendada mitu probleemi ühe lahendusega. Funktsioonide lülitid täidavad palju erinevaid ülesandeid: asendavad kohalikku arenduskeskkonda, git haru, koodi kasutuselevõttu ja muidugi traditsioonilise aeglaselt kontrollitud uue koodi väljasuretuse.

Funktsiooni lülitite loomine ja kasutuselevõtt toimub meie redigeerijas ühe toiminguna. See loob tühja ruumi uuele koodile ja pakub juurdepääsukontrolli vanale ja uuele koodile, samuti nuppe ja käske uue koodi sujuvaks kasutuselevõtuks või selle eraldamiseks.

Funktsioonide lülitid on sisseehitatud Darki keelde ja isegi lõpetamata lülitid täidavad oma ülesande — kui lüliti tingimus ei ole täidetud, käivitatakse vana blokeeritud kood.

Arenduskeskkond

Funktsionaalsuse lülitid asendavad kohaliku arenduskeskkonna. Praegu on meeskondadel keeruline jälgida, et kõik kasutaksid sama versiooni tööriistadest ja teeki (koodiformaatimise tööriistad, lintreid, paketihaldurid, kompilaatorid, eelprotsessorid, testimistööriistad jne). Darki abil ei pea sõltuvusi kohaliku taseme, Dockerit seadistama ega võtma muid meetmeid, et tagada mingigi võrdsus arenduskeskkonna ja tootmise vahel. Arvestades, et selline võrdsus on ikkagi võimatu,, me isegi ei teeselda, et püüame selle poole.

Kohaliku keskkonna kloonimise asemel loob Darki lüliti uue liivakasti tootmises, mis asendab arenduskeskkonna. Tulevikus plaanime luua liivakaste ka rakenduse teistele osadele (näiteks andmebaasi kohesed kloonid), kuigi praegu ei tundu see nii tähtis.

Oksad ja juurutamised

Praegu on mitu viisi uue koodi sisestamiseks süsteemidesse: git-oksad, juurutamisetapid ja funktsionaalsuse lülitid. Need lahendavad ühe probleemi erinevates töövoogudes: git - juurutamise eelsetes etappides, juurutamine - vana koodilt uuele üleminekul, ja funktsionaalsuse lülitid - kontrollitud uue koodi avaldamiseks.

Kõige tõhusam viis on funktsionaalsuse lülitid (samuti kõige lihtsam mõista ja kasutada). Nende abil saab täielikult loobuda ülejäänud kahest meetodist. Eriti kasulik on juurutamine eemaldada - kui me ikkagi kasutame funktsionaalsuse lüliteid koodi aktiveerimiseks, siis serverite üleviimise samm uuele koodile tekitab vaid liigseid riske.

Giti kasutamine on keeruline, eriti algajatele, ja see piirab seda suuresti, kuid sellel on mugavad oksad. Oleme siledanud palju giti puudusi. Dark muudab reaalajas ja pakub koostööd sarnasel viisil nagu Google Docs, et ei peaks koodi saatma ja saaksime harvemini rebase ja merge läbi viia.

Funktsioonide lülitid on ohutu juurutamise aluseks. Koos kiirete juurutamistega võimaldavad need kiiresti testida kontseptsioone väikestes fragmentides, millel on madal risk, selle asemel et rakendada ühte suurt muudatust, mis võib süsteemi kokku kukutada.

Versioonihaldus

Funktsioonide ja tüüpide muutmiseks kasutame versioonihaldust. Kui soovite funktsiooni muuta, loob Dark selle funktsiooni jaoks uue versiooni. Siis saate seda versiooni kutsuda välja lüliti abil HTTP- või sündmuste töötlejas. (Kui see funktsioon on kutsumisgraafis sügaval, luuakse igal kutsumisel uus versioon. See võib tunduda liialdusena, kuid funktsioonid ei sega üksteist, kui te neid ei kasuta, nii et te isegi ei märka seda.)

Samadel põhjustel haldame ka tüüpide versioone. Me oleme põhjalikult rääkinud oma tüüpide süsteemist. eelmisel postitusel.

Funktsioonide ja tüüpide versioonihaldus võimaldab teil rakenduses muudatusi järk-järgult sisse viia. Saate kontrollida, et iga üksik töötleja töötab uue versiooniga, kuid ei pea kohe kõiki muudatusi rakendustesse tegema (kuid meil on tööriistad, et seda kiiresti teha, kui soovite).

See on palju ohutum kui kõigi asjade korraga juurutamine, nagu toimub praegu.

Uued pakettide versioonid ja standardraamatukogu

Kui värskendate paketti Darkis, ei asenda me kohe iga funktsiooni või tüübi kasutamist kogu koodibaasis. See ei ole ohutu. Kood jätkab sama versiooni kasutamist, mida ta kasutas, ja te värskendate funktsioonide ja tüüpide kasutamist uue versiooni jaoks igas eraldi juhtumis lülitite abil.

Kuidas Dark käivitab koodi 50 ms jooksul
Ekraanipilt osast automatiseeritud protsessist Darkis, mis näitab kahte versiooni funktsioonist Dict::get. Dict::get_v0 tagastas tüübi Any (mille kasutamisest me loobume), kuid Dict::get_v1 tagastab tüübi Option.

Meie standardraamatukogus pakume sageli uusi funktsioone ning välistame vanad versioonid. Vanade versioonidega kasutajad saavad endiselt neile juurde pääseda, kuid uued kasutajad ei saa neid. Kavatseme pakkuda tööriistu, et aidata vanade versioonide kasutajatel uutele versioonidele üleminekul ühe sammu teha, samuti lülitite abil.

Dark pakub ka ainulaadset võimalust: kuna me täidame teie töökoode, saame ise testida uusi versioone, võrreldes väljundit uute ja vanade päringute jaoks, et teavitada teid muudatustest. Lõppkokkuvõttes esindab pakettide värskendamine, mida tihti tehakse orienteerumata (või mis nõuab põhjalikku testimist turvalisuse nimel), palju vähem riske ja võib toimuda automaatselt.

Uued versioonid Dark

Üleminek Python 2-lt Python 3-le kestis kümme aastat ja on endiselt probleem. Kuna me loome Darki pidevaks tarnimiseks, tuleb neid keele muudatusi arvesse võtta.

Kui me teeme keeles väikseid muudatusi, loome uue versiooni Dark. Vana kood jääb vanasse versiooni Dark, samas kui uus kood kasutatakse uues versioonis. Uuele versioonile ülemiseks saab kasutada vahetuslüliteid või funktsiooniversioone.

See on eriti kasulik, arvestades, et Dark on ilmunud suhteliselt hiljuti. Paljud keele või teeki muudatused võivad osutuda ebaõnnestunuks. Ahnede versioonide kasutamine võimaldab meil teha väikesi uuendusi, st me ei pea kiirustama ja saame paljusid otsuseid keele kohta edasi lükata, kuni meil on rohkem kasutajaid ja seega rohkem teavet.

Andmebaasi migreerimine

Ohutuks andmebaasi migreerimiseks on olemas standardne valem:

  • Koodi ümberkirjutamine uute ja vanade formaatide toetamiseks
  • Kõik andmed uude vormingusse konverteerimine
  • Vana andmete juurde pääsu eemaldamine

Lõppkokkuvõttes pikendab andmebaasi migreerimine aega ja nõuab palju ressursse. Meil kogunevad vananenud skeemid, kuna isegi lihtsad ülesanded, nagu tabeli või veeru nime muutmine, ei ole vaeva väärt.

Darkil on tõhus andmebaasi migreerimise platvorm, mis (loodame) muudab protsessi nii lihtsaks, et te ei karda seda enam. Kõik Darki andmesalvestid (võtme-väärtuse paaride salvestid või püsivad hash-tabelid) on tüübiga. Andmesalvestuse üleviimiseks määrate lihtsalt uue tüübi ning funktsiooni väärtuste konverteerimiseks kahe tüübi vahel.

Andmete salvestamise süsteemid Darkis on ligipääsetavad versioonitud muutujanimede kaudu. Näiteks andmehoidla Users kannab algselt nime Users-v0. Kui luuakse uus versioon teistsuguse tüübiga, siis muudetakse nimeks Users-v1. Kui andmed on salvestatud Users-v0 kaudu ja te pöördute nende poole Users-v1 kaudu, rakendatakse taastamisfunktsiooni. Kui andmed on salvestatud Users-v1 kaudu ja te pöördute nende poole Users-v0 kaudu, rakendatakse tagasiulatuva funktsiooni.

Kuidas Dark käivitab koodi 50 ms jooksul
Andmebaasi migratsiooniekraan koos vana andmebaasi välja nimedega, taastamis- ja tagasiulatuvate väljenditega ning juhistega migreerimise võimaldamiseks.

Kasutage funktsioonide lüliteid, et suunata kutsed Users-v0 versiooni Users-v1. Seda saab teha ühe HTTP käitleja korraga, et vähendada riske, ning lülitid töötavad ka eraldi kasutajate jaoks, et saaksite kontrollida, et kõik töötab ootuspäraselt. Kui Users-v0 kasutajaid enam ei jää, konverteerib Dark kõik ülejäänud andmed taustal vanast formaadist uude. Te ei märkagi seda.

Testimine

Dark on funktsionaalne programmeerimiskeel staatilise tüpiseerimisega ja muutumatute väärtustega, seega on selle testimise ulatus oluliselt väiksem võrreldes objektorienteeritud dünaamilise tüpiseerimisega keeltega. Kuid testimist on siiski vaja.
Darkis käivitab redaktor taustal automaatselt moodulitestid muudetud koodi jaoks ja vaikimisi läbiviib neid teste kõigi funktsioonide lülitite jaoks. Tulevikus tahame staatiliste tüpiseerimise abil automaatselt koodifuzzimist teostada, et leida vigu.

Lisaks rakendab Dark teie infrastruktuuri tootmisrežiimis, mis avab uusi võimalusi. Salvestame automaatselt HTTP päringud Dark infrastruktuuris (praegu salvestame kõiki päringuid, kuid hiljem plaanime liikuda valimise suunal). Testime nende põhjal uut koodi ja viime läbi mooduliteste, ning soovi korral saate hõlpsasti muuta huvitavad päringud moodulitestideks.

Mille me kõrvaldame

Kuna meil ei ole juurutamist, vaid on funktsioonide lülitid, jääb umbes 60% juurutuse protsessist kõrvale. Me ei vaja git harusid ega tõmbepäringuid, taustades ressursside ja konteinerite koostamist, ressursside ja konteinerite saatmist registritesse ega juurutamisprotsesside samme Kubernetesis.

Kuidas Dark käivitab koodi 50 ms jooksul
Tavaline pidev tarnetoru võrrelduna Darkiga (vasakul) ja pidev tarnetoru Darkis (paremal). Darkis tarnetoru koosneb 6 sammust ja ühest tsüklist, samas kui traditsiooniline versioon hõlmab 35 sammu ja 3 tsüklit.

Darkis on kõigest 6 sammu ja 1 tsükkel (sammud, mis korduvad mitu korda) juurutamises, samas kui tänapäeva pidev tarnetoru koosneb 35 sammust ja 3 tsüklist. Darkis käivitatakse testid automaatselt, ja te ei märkagi seda; sõltuvused installitakse automaatselt; kõik, mis on seotud git või Githubiga, pole enam vajalik; Docker konteinerite kogumine, testimine ja saatmine pole enam vajalik; Kuberneteses juurutamine ei ole enam vajalik.

Ievenenud sammud Darkis on lihtsamad. Kuna funktsioonide lülititega saab hallata ühe tegevusega, pole vaja uuesti läbida kogu juurutustoru, et eemaldada vana kood.

Oleme koodi tarnimist niipalju lihtsustanud, et vähendasime pideva tarnimise aega ja riske. Lisaks oleme oluliselt lihtsustanud pakettide uuendamist, andmebaaside migreerimist, testimist, versioonihaldust, sõltuvuste installimist, arenduskeskkonna ja tootmiskeskkonna võrdset kohtlemist ning kiireid ja turvalisi keeleversioonide uuendusi.

Vastan sellele küsimusele HackerNewsis.

Darki seadme kohta rohkem teada saamiseks lugege artiklit Darkist, järgige meid Twitteris (või minu) või registreerige betaversiooni ja saage teateid järgmiste postituste kohta. Kui külastate StrangeLoopi septembris, tulge meie käivitamisele.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster