Distribuerede systemer: Hvornår skal du bygge dem, og hvordan skaleres. En trinvis vejledning.

Foto af Jeremy McKnight på Unsplash

Det slår mig altid, hvor mange juniorudviklere der lider af impostor-syndrom, da de begyndte at oprette deres produkt.

Jeg forstår det, der er mange sindblæsende eksempler på topfirmaer med utroligt komplekse distribuerede systemer, der kan tackle milliarder af anmodninger, yndefuldt opgradere hundreder af applikationer uden driftsstop, komme sig efter katastrofe på få sekunder, frigive hvert 60 minut og have lyshastighed responstider fra hvor som helst i verden.

Disse forventninger kan være temmelig overvældende, når du starter dit projekt. Men som mange af jer allerede ved, er et flertal af disse virksomheder startet med et minimalt levedygtigt system og en meget dårlig teknologistapel. Der er en simpel grund: De havde ikke brug for det, da de startede. Brug af mere tid på at designe dit system i stedet for kodning kan faktisk få dig til at mislykkes.

Denne artikel er et trin for trin til vejledning. Jeg vil vise dig, hvordan vi hos Visage startede med det mindste system nogensinde og bygget et grundlæggende skalerbart distribueret system med høj tilgængelighed. Dette er en reel case study for at fjerne dine komplekser, hvis du aldrig har haft mulighed for at gøre det selv.

Da jeg først ankom Visage som CTO, var jeg den eneste ingeniør. Jeg vidste intet om tech-stakken, men jeg kom med, fordi jeg virkelig kunne godt lide ideen om at kunne rekruttere uden interne rekrutterere eller en HR-service. Dette var kerneideen bag Visage: crowddsourcing drevet af en masse usynlige rekrutterere, der arbejder sammen om dine roller assisteret af kunstig intelligens, der ville lede efter det mest passende talent for dig i løbet af få dage. Så engagerer du dig direkte med dem, ingen middelmand.

"Publikum" i crowddsourcing udløste øjeblikkeligt min ingeniørhjerne: der kommer mange mennesker, der arbejder samtidigt og forventer god ydelse overalt i verden. Jeg kunne godt lide udfordringen.

Men systemvise, tingene var dårlige, virkelig dårlige. Dette var, hvad jeg fandt, da jeg ankom:

  • En kompromitteret Wordpress-instans, der kører hundredvis af forældede fejlbehæftede plugins, der kører i en VM på en delt server
  • Kompromitterede postkasser
  • Et stykke ton af Google Dokumenter og regneark.

Og dette er helt normalt. Igen var der ikke noget teknisk medlem på holdet, og jeg havde forventet noget lignende. Stadig havde teamet fokuseret på en forretningsmulighed og fået produktet til at virke som om det fungerede magisk, mens det gjorde alt manuelt! (Falske det, indtil du gør det). Og det var, hvad der virkelig var fantastisk.

Vores første system (Ja, det sugede, men det gjorde jobbet)!

Det var ikke overraskende, at min første opgave var at genoprette VM, geninstallere en opdateret Wordpress-version, sørge for, at alle ændrer deres adgangskoder, etablerer en adgangskodepolitik og fjerner snesevis af malware på virksomhedens computere ... men lad os gå videre til systemovervejelser.

Fra Wordpress til en webapplikation

Dit første fokus, når du begynder at opbygge et produkt, skal være data. Data er det, der driver din virksomheds værdi. Det vil være det, du bruger hver dag til at tage beslutninger, og hvad du viser til dine investorer for at demonstrere fremskridt.

Du er nødt til at give mening om dine data, og at indsamle dine data fra forskellige kilder med forskellige formater vil være et enormt spild af tid. Wordpress kan være et meget godt valg i mange tilfælde ved at spare temmelig meget teknisk tid, men til deres behov måtte Visage-teamet installere smarte plugins, der ikke blev opretholdt mere. Som et resultat havde vi ingen kontrol over den genererede datamodel, og data, der ikke kunne passe til modellen, var spredt over snesevis af dokumenter og regneark.

Så medmindre der er et produkt derude, der allerede passer til 90% af dine behov, skal du tænke på en ideel datamodel og designe og implementere et minimum levedygtigt produkt (MVP), der kan indeholde alle dine data.

Tænk derefter på API. Din ansøgning skal have en API, den vil være kritisk, når du til sidst sælger den. Skal ikke straks op, men kode med skalerbarhed i tankerne. Gør din API statsløs og så RESTfuld som du muligvis kan, da alle forventer at være i stand til at forespørge den ved hjælp af standard HTTP-metoder.

Vi valgte NodeJS i vores sag, fordi det meste af vores kode bare ville behandle input og output. NodeJS blokerer ikke og leveres med et bibliotek, der er praktisk at designe API'er: ExpressJS.

Hvis du har brug for en kunde, der står overfor webstedet, har du flere muligheder. Først kan du oprette et lag på din applikationsserver, der genererer dine sider, eller du kan opbygge en enkelt side Javascript-applikation, der vil blive betjent af en statisk webhostingserver.

Hos Visage gik vi til den anden mulighed og besluttede at oprette en applikation til brugere og en til administratorer. Dette var simpelthen fordi vi ville have meget større forventninger til brugere, end vi havde brug for med administratorer, og ønskede at holde begge codebases enkle (også af CORS-overvejelser senere). Sådan så vores system ud:

Alle data ét sted

Delegere følsom datalagring tidligt

Medmindre det er kritisk for din virksomhed, er der ingen god grund til at gemme følsomme personlige data i dine systemer. Sikkerhed er en kompleks sag, og hvis du ændrer din kode hver dag, indtil du finder dit produktmarked passende, vil det gå i stykker. Antag, at enhver, der ikke var ment, kunne overtræde din ansøgning, hvis de virkelig ville.

Nøglen her er at ikke indeholde data, der ville være en hurtig gevinst for en hacker. Ingen frarøver en bank, der ikke har penge. Hvis du designer et SaaS-produkt, har du sandsynligvis brug for godkendelse og online betaling. Der er mange tredjeparter, du kan integrere med, der vil håndtere det på en meget bedre måde, end du muligvis kunne.

Auth0, for eksempel, er den mest kendte tredjepart, der håndterer godkendelse. Stripe er også en god mulighed for online-betalinger. De vil afsætte alle deres ressourcer og de bedste sikkerhedsteknologiteam på planeten for at holde dine data sikre - eller de har ikke en forretning.

Faktisk skiltning på en bil i San Francisco

Cloud-tjenester er dine bedste venner

Så på dette tidspunkt havde vi en måde at gemme alle vores data, autentificering, online betaling og en web-app, som klienter kunne bruge sammen med et API, som vi kunne sælge til partnere til forskellige brugssager. Vores brugerbase voksede, og det blev tydeligt, at de ville være i stand til at få adgang til appen når som helst. Så det var tid til at tænke på skalerbarhed og tilgængelighed.

Vi var afhængige af én server, men den kunne kun håndtere så mange anmodninger, og at ændre servere eller frigive en ny version ville betyde, at applikationen blev fjernet under frigivelsen. Vores næste prioriteter var: belastningsbalancering, automatisk skalering, logning, replikering og automatiserede sikkerhedskopier. Hvis du er den eneste ingeniør i din virksomhed, ville det selvfølgelig være fuldstændig vanvid at prøve at tackle alle disse problemer på egen hånd.

Heldigvis lever vi i en tid, hvor bare en enkelt afrundet ingeniør let kan opbygge et sådant system i et par dage ved hjælp af Cloud-tjenester som Amazon Web Services, Google Cloud Services eller Azure. Vi besluttede at flytte vores systemer til AWS, fordi det på det tidspunkt var den mest komplette løsning, og vi havde 2 års gratis kreditter.

Dette er grunden til, at jeg for det meste vil tale om AWS-løsninger i dette indlæg, men der er tilsvarende tjenester på andre platforme. Dette er også det tidspunkt, vi valgte at begynde at køre vores moduler i Docker-containere af mange forskellige andre grunde, som ikke vil blive dækket i dette indlæg (du kan tjekke denne artikel for mere info: https://medium.freecodecamp.org / amazon-fargate-farvel-infrastruktur-3b66c7e3e413).

Hvordan du beslutter at køre dine applikationer afhænger virkelig af din brugssag, ligesom den fleksibilitet, du har brug for, mod den tid, du kan bruge på at administrere din infrastruktur.

Der er ikke noget godt eller dårligt svar.

Du kan vælge at containere alle dine moduler og bruge et containerstyringssystem som ECS / EKS i AWS eller Kubernetes motor i GCP. Hvis ikke, og du ikke ønsker at beskæftige dig med ting som automatisk skalering og belastningsbalance selv, kan du bruge Elastic Beanstalk eller App Engine.

Hvis du ønsker at gå fuld Serverless kan du også kombinere brugen af ​​Lambda-funktioner og API Gateway. Vi besluttede at gå til ECS. Vi distribuerede 3 forekomster på tværs af 3 tilgængelighedszoner, en belastningsbalance, opsætning af automatisk skalering afhængigt af CPU-brug, integreret alle vores containers logfiler med Cloudwatch og opsætningsmetriker for at se fejl, eksterne opkald og API-responstid.

Høj tilgængelighed: Vidste du, at giraffer næsten aldrig sover? 99% oppetid

Til vores database brugte vi MongoDB, fordi vores model passer godt til en NoSQL-database og for dens høje konsistens. Vi besluttede at drage fordel af MongoDB Atlas og indsatte 3 kopier for at give mulighed for høj tilgængelighed. Blandt andre tjenester leverer Atlas automatisk skalering, automatiske sikkerhedskopier og giver dig mulighed for at gå tilbage i tiden problemfrit i tilfælde af katastrofe.

Vi besluttede også at være vært for alle vores statiske webfiler i S3 og brugte Cloudfront som et CDN, så vores JS-apps kan indlæses meget hurtigt overalt i verden og blive serveret så mange gange som anmodet om. Cloudflare er også en god mulighed og tilbyder en DDOS-beskyttelse ud af kassen.

For enkelheds skyld besluttede vi at bruge Rute 53 som vores DNS ved at bruge deres navneservere til alle vores domæner. Dette er en af ​​mine foretrukne tjenester på AWS. Det gør dit liv så meget lettere. Hver gang du vil servere noget gennem et domænenavn, hvad enten det er en EC2-instans, en elastisk IP, en belastningsbalancer, en Cloudfront-distribution eller noget virkelig, privat eller offentligt, tager det dig minutter, fordi det er så godt integreret med alt det andre tjenester.

Kombiner det med Certificate Manager, der giver dig mulighed for at få SSL-certifikater (wildcards inkluderet) gratis på få minutter og distribuere dem på alle dine servere ved at markere en boks, og du har den hurtigste og mest pålidelige måde at aktivere HTTPS på alle dine moduler. Farvel “Lad os kryptere” SSL-certifikater, som jeg var nødt til at forny og installere på mine servere hver 3. måned eller deromkring .

Begynder at se anstændigt ud

Beslut om en cache-strategi

Alle hader cachehåndtering, cache kan ske i mange forskellige lag, og cache-relaterede problemer er svære at gengive og et mareridt at fejlsøge.

Desværre afhænger ydelsen af ​​distribuerede systemer stærkt på en god cache-strategi. Der er mange gode artikler om gode cache-strategier, så jeg vil ikke gå i detaljer. Bare ved, at hvis dine statiske web-ressourcer er tunge, vil du sandsynligvis have lyst til at drage fordel af din brugers browser-cache ved smart at bruge cache-kontrolhovedet.

Hvis din brugers vendende sider genereres på applikationsserverne igen og igen, skal du bruge en cache-proxy som Squid. Men vigtigst af alt er der en stor chance for, at du kommer med de samme anmodninger til din database igen og igen. Hvis du vil sænke din databasebelastning og gemme på dataoverførselstiden, skal du bruge et cache-cache-hukommelsessystem som memcached til objekter, der ofte bruges og sjældent opdateres.

Vi begyndte at overveje at bruge memcached, fordi vi ofte anmodede om de samme kandidatprofiler og jobtilbud igen og igen. Implementering af den på en hukommelsesoptimeret maskine øgede vores API-ydeevne med mere end 30%, når vi gennemsnit alle anmodningens svartider på en dag. Memcached distribueres også, så det kan køre på forskellige servere, men stadig fungere som det er bare en stor hukommelsesplads til at gemme dine objekter.

cache, cache overalt

Beliggenhed, beliggenhed, beliggenhed

Nu har vi et distribueret system, der ikke har et enkelt mislykkelsespunkt (hvis du overvejer AWS ELB'er og en distribueret memcached), og som kan automatisk skalere op og ned. Vi bruger også cache til at minimere netværksdataoverførsler. Ser temmelig godt ud. På det tidspunkt ønsker du sandsynligvis at revidere dine tredjeparter for at se, om de vil absorbere lasten så godt som dig.

Men stadig klagede nogle af vores brugere over, at appen var lidt langsommere for dem, især når de uploade filer. Selv hvis vores statiske webfiler blev cachelagret over hele verden (høflighed af CDN), blev alle vores applikationsservere kun installeret i det vestlige USA. Brugere fra Østasien oplevede meget mere forsinkelse især for store dataoverførsler.

Løsningen var let: implementer nøjagtigt den samme ECS-klynge på en ny region i Asien sammen med en ny belastningsafbalancering, og stol på Rute 53 Geoproximity Routing for at rute brugere til den ”nærmeste” belastningsbalancer. MongoDB Atlas giver dig også mulighed for at distribuere dine replikker på tværs af regioner, så der ikke var behov for yderligere arbejde.

Og her er vi! Vores distribuerede system er klar.

Konklusion

Selvom det distribuerede system, du ser her, er blevet forenklet til dette indlæg, har vi undersøgt de dele, du mest sandsynligt ser i mange moderne webapplikationer. Andre emner, der er relateret til, men ikke dækket, er mikroservices-arkitektur, fillagring og kryptering, databaseafskærmning, planlagte opgaver, asynkron parallel computing… måske i næste post!

Mit vigtigste punkt er: prøv ikke at opbygge det perfekte system, når du starter dit produkt. De fleste af dine designvalg styres af, hvad dit produkt gør, og hvem der bruger det. Du vil kun vide, at når du når produktmarkedets pasform og begynder at have et godt overblik over din brugerbase, og det kan tage måneder, år selv.

Fokuser på at finde ud af, hvad folk har brug for, og prøv at finde en løsning på deres problem, selvom det har en masse manuelle trin. Tænk derefter på måder at automatisere, bruge din tid på at kode og ødelægge og bruge tredjepart, hvor det er fornuftigt.

Må ikke skaleres, men tænk, kode og planlæg altid for skalering. Byg dit system trin for trin, adresser ikke systemdesignproblemer baseret på funktioner, der endnu ikke er modne, og prøv til sidst altid at finde den bedste kompromis mellem den tid, du vil bruge, og gevinsten i ydelse, penge og sænket risiko.

Hvis du kunne lide denne artikel og fandt, at noget af det var nyttigt, skal du trykke på klapknappen og følge mig for flere artikler om arkitektur og udvikling!