Bedste fremgangsmåder til AWS Lambda Container Genbrug

Optimering af varme starter, når AWS Lambda forbindes til andre tjenester

AWS Lambda giver høj skalerbarhed på grund af at være serverløs og statsløs, så mange kopier af lambda-funktionen kan gydes øjeblikkeligt (som beskrevet her). Når du skriver applikationskode, vil du sandsynligvis have adgang til nogle statlige data. Dette betyder at oprette forbindelse til en datastore, såsom en RDS-instans eller S3. Forbindelse til andre tjenester fra AWS Lambda tilføjer dog tid til din funktionskode. Der kan også være bivirkninger fra høj skalerbarhed, såsom at nå det maksimale antal tilladte forbindelser til en RDS-instans. En mulighed for at imødegå dette er at bruge genanvendelse af containere i AWS Lambda for at fortsætte forbindelsen og reducere lambda-køretid.

Der er nogle nyttige diagrammer her til at forklare livscyklussen for en lambda-anmodning.

Følgende opstår under en kold start, når din funktion påberåbes for første gang eller efter en periode med inaktivitet:

  • Koden og afhængighederne downloades.
  • En ny container startes.
  • Runtime er bootstrapped.

Den sidste handling er at starte din kode, der sker hver gang lambda-funktionen påberåbes. Hvis containeren genbruges til en efterfølgende påkaldelse af lambda-funktionen, kan vi springe videre til start af koden. Dette kaldes en varm start, og dette er det trin, vi kan optimere, når vi opretter forbindelse til andre tjenester ved at definere forbindelsen uden for omfanget af handler-metoden.

Forbindelse til andre AWS-tjenester fra Lambda

Eksempel: Opret forbindelse til RDS-forekomst, AWS-ikoner hentet herfra

Vi har et grundlæggende og fælles eksempel at køre igennem - vi vil oprette forbindelse til en containerressource for at hente berigelsesdata. I dette eksempel kommer en JSON nyttelast ind med et ID, og ​​Lambda-funktionen opretter forbindelse til en RDS-forekomst, der kører PostgreSQL for at finde det tilsvarende navn på ID, så vi kan returnere den berigede nyttelast. Da lambda-funktionen opretter forbindelse til RDS, der bor i en VPC, er lambda-funktionen nu nødt til at leve i et privat undernet. Dette tilføjer et par trin til den kolde start - en VPC elastisk netværksgrænseflade (ENI) skal vedhæftes (som nævnt i Jeremy Dalys blog, dette tilføjer tid til dine kolde starter).

Bemærk: vi kunne undgå at bruge en VPC, hvis vi skulle bruge en nøgle / værdi-lagring med DynamoDB i stedet for RDS.

Jeg vil gå over to løsninger på denne opgave, den første er min 'naive' løsning, hvorimod den anden løsning optimerer til varme starttider ved at genbruge forbindelsen til efterfølgende påkaldelser. Så sammenligner vi effektiviteten af ​​hver løsning.

Valgmulighed 1 - Opret forbindelse til RDS i håndtereren

Dette kodeeksempel viser, hvordan jeg naivt kan nærme sig denne opgave - databaseforbindelsen er inden for behandlingsmetoden. Der er en simpel udvælgelsesforespørgsel for at hente navnet på ID'et, før du returnerer nyttelasten, som nu inkluderer navnet.

Lad os se, hvordan denne mulighed fungerer under en lille test med et burst af 2000 påkaldelser med en samtidighed af 20. Den mindste varighed er 18 ms med et gennemsnit på 51ms og lidt over 1 sekund (den kolde startvarighed).

Lambda Varighed

Grafen herunder viser, at der er et maksimalt antal på otte forbindelser til databasen.

Antal forbindelser til RDS-database i et 5 minutters vindue.

Valgmulighed 2 - Brug en global forbindelse

Den anden mulighed er at definere forbindelsen som en global uden for håndteringsmetoden. Derefter tilføjer vi inden i behandleren en check for at se, om forbindelsen findes, og kun oprette forbindelse, hvis den ikke gør det. Dette betyder, at forbindelsen kun oprettes en gang pr. Container. Indstilling af forbindelsen på denne måde med den betingede på plads betyder, at vi ikke behøver at oprette en forbindelse, hvis ikke det kræves af kodelogikken.

Vi lukker ikke længere forbindelsen til databasen, så forbindelsen forbliver til en efterfølgende påkaldelse af funktionen. Genbrug af forbindelsen reducerer den varme startvarighed betydeligt - den gennemsnitlige varighed er cirka 3 gange hurtigere og minimum er 1 ms i stedet for 18 ms.

Lambda Varier

Det er en tidskrævende opgave at oprette forbindelse til en RDS-instans, og at det ikke er nødvendigt at oprette forbindelse til hver opfordring til fordel for ydelsen. Når vi opretter forbindelse til databasen til en simpel databaseforespørgsel, opnår vi et maksimalt antal af databaseforbindelser på 20, der matcher niveauet for samtidighed (vi foretog 20 samtidige invokationer x 100 gange). Når udbruddet af opkald stopper, lukkes forbindelserne gradvist.

Nu, hvor AWS har øget lambda-varighedstilladelsen til 15 minutter, betyder det, at databaseforbindelser kan vare længere, og du kan være i fare for at nå RDS-maxforbindelsesnummeret. Standardmaksforbindelserne kan overskrives i RDS-parametergruppeindstillingerne, selvom at øge det maksimale antal forbindelser kan resultere i problemer med hukommelsestildeling. Mindre forekomster kan have en standardværdi for max_forbindelser på mindre end 100. Vær opmærksom på disse grænser, og tilføj kun applikationslogik for at oprette forbindelse til databasen, når det er nødvendigt.

Brug af en global forbindelse til andre opgaver

Lambda Tilslutning til S3

En fælles opgave, vi muligvis skal udføre med Lambda, er at få adgang til statlige data fra S3. Kodestykket nedenfor er en AWS leveret Python Lambda Function-plan - som du kan navigere til ved at logge ind på AWS-konsollen og klikke her. I koden kan du se, at S3-klienten er fuldt ud defineret uden for behandleren, når containeren er initialiseret, mens den globale forbindelse til RDS-indstillingen blev indstillet inde i behandleren. Begge fremgangsmåder sætter de globale variabler, så de kan være tilgængelige til efterfølgende påkaldelser.

s3-get-object lambda blueprint-kodestykket https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/new?bp=s3-get-object-python

Dekryptering af miljøvariabler

Lambda-konsollen giver dig mulighed for at kryptere dine miljøvariabler for yderligere sikkerhed. Følgende kodestykker er et AWS-forudsat Java-eksempel på et hjælpescript til dekryptering af miljøvariabler fra en Lambda-funktion. Du kan navigere til kodestykket ved at følge denne tutorial (specifikt trin 6). Da DECRYPTED_KEY er defineret som en global klasse, kaldes decryptKey () -funktionen og logikken kun én gang pr. Lambda-container. Derfor vil vi se en betydelig forbedring i varme startvarigheder.

https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions og https://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html

Brug af globale variabler i andre FaaS-løsninger

Denne tilgang er ikke isoleret til AWS Lambda. Metoden til at bruge en global forbindelse kan også anvendes til andre cloud-udbyders serverløse funktioner. Google Cloud-funktioner tip og tricks-side giver en god forklaring på ikke-dovne variabler (når variablen altid initialiseres uden for behandlingsmetoden) versus dovne variabler (den globale variabel indstilles kun efter behov) globale variabler.

Andre bedste fremgangsmåder

Her er nogle andre bedste fremgangsmåder, du skal huske på.

Test

Brug af FaaS letter det at have en mikroservicearkitektur. Og at have små, diskrete funktionalitetsstykker går hånd i hånd med effektiv enhedstest. For at hjælpe dine enhedsforsøg:

  • Husk at ekskludere testafhængigheder fra lambda-pakken.
  • Adskill logik væk fra handler-metoden, som du ville gøre med en hovedmetode i et program.

Afhængigheder og pakkestørrelse

At reducere størrelsen på implementeringspakken betyder, at download af koden vil være hurtigere ved initialisering og derfor vil forbedre dine kolde starttider. Fjern ubrugte biblioteker og død kode for at reducere ZIP-filstørrelsen. AWS SDK leveres til Python- og JavaScript-driftstider, så det er ikke nødvendigt at inkludere dem i din installationspakke.

Hvis Node.js er din foretrukne Lambda-runtime, kan du anvende minification og uglification for at reducere størrelsen på din funktionskode og minimere størrelsen på din implementeringspakke. Nogle men ikke alle aspekter af minificering og forgrening kan anvendes til andre driftstider, f.eks. du kan ikke fjerne whitespace fra python-kode, men du kan fjerne kommentarer og forkorte variabelnavne.

Indstilling af hukommelsen

Eksperimentér for at finde den optimale mængde hukommelse til Lambda-funktionen. Du betaler for hukommelsestildeling, så fordobling af hukommelsen betyder, at du skal betale dobbelt pr. Millisekund; men beregningskapaciteten øges med den tildelte hukommelse, så det potentielt kan reducere køretiden til under halvdelen af ​​det, det var. Der er allerede nogle nyttige værktøjer til at vælge den optimale hukommelsesindstilling for dig som denne.

At afslutte ...

Én ting at overveje er, om det er nødvendigt at anvende forbindelsesgenbrugsmetoden. Hvis din lambda-funktion kun kaldes sjældent, f.eks. En gang dagligt, vil du ikke drage fordel af at optimere til varme starter. Der er ofte en afvejning at foretage mellem at optimere for ydeevne kontra læsbarhed af din kode - udtrykket "uglification" taler for sig selv! Derudover kan tilføjelse af globale variabler til din kode for at genbruge forbindelser til andre tjenester potentielt gøre din kode vanskeligere at spore. To spørgsmål kommer i tankerne:

  • Forstår et nyt teammedlem din kode?
  • Vil du og dit team kunne fejlsøge koden i fremtiden?

Men chancerne er, at du har valgt Lambda for dens skala og ønsker høj ydeevne og lave omkostninger, så find den balance, der passer til dit teams behov.

Disse udtalelser er forfatterens. Medmindre andet er angivet i dette indlæg, er Capital One ikke tilknyttet, og det er heller ikke godkendt af nogen af ​​de nævnte virksomheder. Alle varemærker og anden intellektuel ejendom, der bruges eller vises, er deres respektive ejers ejerskab. Denne artikel er © 2019 Capital One.