Programmering

Serverløs databehandling med AWS Lambda, del 1

Serverløs databehandling er kanskje den hotteste tingen innen cloud computing i dag, men hva er det egentlig? Denne todelte opplæringen starter med en oversikt over serverløs databehandling - fra hva det er, til hvorfor det anses å være forstyrrende for tradisjonell cloud computing, og hvordan du kan bruke det i Java-basert programmering.

Etter oversikten får du en praktisk introduksjon til AWS Lambda, som av mange regnes som den første Java-baserte løsningen for serverløs databehandling i dag. I del 1 bruker du AWS Lambda til å bygge, distribuere og teste din første Lambda-funksjon i Java. I del 2 vil du integrere Lambda-funksjonen din med DynamoDB, og deretter bruke AWS SDK til å påkalle Lambda-funksjoner i et Java-program.

Hva er serverløs databehandling?

I fjor snakket jeg med en bedriftspraktikant om forskjellige arkitektoniske mønstre og nevnte serverløs arkitektur. Han var rask med å merke seg at alle applikasjoner krever en server, og kan ikke kjøre i luften. Praktikanten hadde et poeng, selv om han manglet mitt. Serverløs databehandling er ikke en magisk plattform for å kjøre applikasjoner.

Faktisk, serverløs databehandling betyr ganske enkelt at du, utvikleren, ikke trenger å gjøre det ta hånd om serveren. En serverløs databehandlingsplattform som AWS Lambda lar deg bygge koden din og distribuere den uten å måtte konfigurere eller administrere underliggende servere. Din distribusjonsenhet er koden din; ikke beholderen som er vert for koden, eller serveren som kjører koden, men bare selve koden. Fra et produktivitetssynspunkt er det åpenbare fordeler ved å laste ned detaljene om hvor koden lagres og hvordan kjøringsmiljøet administreres. Serverløs databehandling er også priset basert på utførelsesberegninger, så det er også en økonomisk fordel.

Hva koster AWS Lambda?

I skrivende stund er AWS Lambdas prisnivå basert på antall henrettelser og utførelsesvarighet:

  • Dine første millioner henrettelser per måned er gratis, deretter betaler du 0,20 dollar per million henrettelser deretter (0,0000,002 dollar per forespørsel).
  • Varigheten beregnes fra det tidspunktet koden begynner å kjøres til den returnerer et resultat, avrundet til nærmeste 100 ms. Beløpet som belastes er basert på mengden RAM som er tildelt funksjonen, hvor kostnaden er $ 0,00001667 for hvert GB-sekund.

Prisdetaljer og gratis nivånivåer er litt mer kompliserte enn oversikten tilsier. Besøk prisnivået for å gå gjennom noen få prisscenarier.

For å få en ide om hvordan serverløs databehandling fungerer, la oss starte med den serverløse databehandlingsutførelsesmodellen, som er illustrert i figur 1.

Steven Haines

Her er den serverløse kjøringsmodellen i et nøtteskall:

  1. En klient ber en anmodning til den serverløse databehandlingsplattformen om å utføre en bestemt funksjon.
  2. Den serverløse databehandlingsplattformen sjekker først om funksjonen kjører på noen av serverne. Hvis funksjonen ikke allerede kjører, laster plattformen funksjonen fra et datalager.
  3. Plattformen distribuerer deretter funksjonen til en av serverne, som er forhåndskonfigurert med et kjøringsmiljø som kan kjøre funksjonen.
  4. Den utfører funksjonen og fanger resultatet.
  5. Det returnerer resultatet tilbake til klienten.

Noen ganger kalles serverløs databehandling Funksjon som en tjeneste (FaaS), fordi detaljene til koden du bygger er en funksjon. Plattformen utfører funksjonen din på sin egen server og orkestrerer prosessen mellom funksjonsforespørsler og funksjonsresponser.

Nanotjenester, skalerbarhet og pris

Tre ting har virkelig betydning for serverløs databehandling: dens nanotjenestearkitektur; det faktum at den praktisk talt er uendelig skalerbar; og prismodellen assosiert med den nær uendelige skalerbarheten. Vi skal grave i hver av disse faktorene.

Nanotjenester

Du har hørt om mikrotjenester, og du vet sannsynligvis om 12-faktor applikasjoner, men serverløse funksjoner tar paradigmet med å bryte en komponent ned til dens bestanddeler til et helt nytt nivå. Uttrykket "nanotjenester" er ikke et næringsgjenkjent begrep, men ideen er enkel: hver nanotjeneste bør implementere en enkelt handling eller et ansvar. Hvis du for eksempel ønsket å opprette en widget, ville opprettelsen være sin egen nanotjeneste; hvis du ønsket å hente en widget, ville henting også være en nanotjeneste; og hvis du ønsker å bestille en widget, vil bestillingen være enda en nanotjeneste.

En nanotjenestearkitektur lar deg definere applikasjonen på et veldig finkornet nivå. I likhet med testdrevet utvikling (som hjelper deg med å unngå uønskede bivirkninger ved å skrive koden din på nivå med individuelle tester), oppfordrer en nanotjenestearkitektur til å definere applikasjonen din når det gjelder veldig finkornede og spesifikke funksjoner. Denne tilnærmingen øker klarheten om hva du bygger og reduserer uønskede bivirkninger fra ny kode.

Mikrotjenester vs nanotjenester

Microservices oppfordrer oss til å dele en applikasjon ned i en samling tjenester som hver utfører en spesifikk oppgave. Utfordringen er at ingen virkelig har kvantifisert omfang av en mikroservice. Som et resultat definerer vi mikrotjenester som en samling relaterte tjenester, som alle samhandler med den samme datamodellen. Konseptuelt, hvis du har funksjonalitet på lavt nivå som interagerer med en gitt datamodell, bør funksjonaliteten gå inn i en av de relaterte tjenestene. Interaksjoner på høyt nivå bør ringe til tjenesten i stedet for å spørre databasen direkte.

Det er en pågående debatt i serverløs databehandling om det skal bygges Lambda-funksjoner på nivå med mikrotjenester eller nanotjenester. Den gode nyheten er at du ganske enkelt kan bygge funksjonene dine i begge granulariteter, men en mikrotjenestestrategi vil kreve litt ekstra rutinglogikk i forespørselsbehandleren din.

Fra et designperspektiv bør serverløse applikasjoner være veldig veldefinerte og rene. Fra et distribusjonsperspektiv må du administrere betydelig flere distribusjoner, men du vil også ha muligheten til å distribuere nye versjoner av funksjonene dine individuelt, uten å påvirke andre funksjoner. Serverløs databehandling er spesielt godt egnet for utvikling i store team, der det kan bidra til å gjøre utviklingsprosessen enklere og koden mindre feilutsatt.

Skalerbarhet

I tillegg til å introdusere et nytt arkitektonisk paradigme, gir serverløse databehandlingsplattformer praktisk talt uendelig skalerbarhet. Jeg sier "praktisk" fordi det ikke er noe som heter virkelig uendelig skalerbarhet. For alle praktiske formål kan imidlertid serverløse databehandlere som Amazon takle mer belastning enn du muligens kan kaste på dem. Hvis du skulle klare å skalere opp dine egne servere (eller skybaserte virtuelle maskiner) for å møte økt etterspørsel, må du overvåke bruken, identifisere når du skal starte flere servere og legge til flere servere i klyngen din til rett tid. På samme måte, når etterspørselen minket, må du manuelt redusere. Med serverløs databehandling forteller du den serverløse databehandlingsplattformen det maksimale antallet samtidige funksjonsforespørsler du vil kjøre, og plattformen gjør skaleringen for deg.

Priser

Til slutt lar den serverløse databehandlingsprismodellen deg skalere skyregningen din basert på bruk. Når du har lett bruk, vil regningen være lav (eller null hvis du holder deg i fritt område). Selvfølgelig vil regningen din øke med bruken, men forhåpentligvis vil du også få nye inntekter for å støtte din høyere skyregning. Hvis du derimot skulle administrere dine egne servere, må du betale en basiskostnad for å kjøre det minste antallet servere som kreves. Etter hvert som bruken økte, vil du øke i trinn på hele serverne, i stedet for trinn på individuelle funksjonsanrop. Den serverfrie databehandlingsmodellen er direkte proporsjonal med bruken din.

AWS Lambda for serverløs databehandling

AWS Lambda er en serverløs databehandlingsplattform implementert på toppen av Amazon Web Services-plattformer som EC2 og S3. AWS Lambda krypterer og lagrer koden din i S3. Når en funksjon blir bedt om å kjøre, oppretter den en "container" ved hjelp av kjøretidsspesifikasjonene dine, distribuerer den til en av EC2-forekomster i databehandlingsgården og utfører den funksjonen. Prosessen er vist i figur 2.

Steven Haines

Når du oppretter en Lambda-funksjon, konfigurerer du den i AWS Lambda, og spesifiserer ting som kjøretidsmiljøet (vi bruker Java 8 for denne artikkelen), hvor mye minne du skal tildele det, identitets- og tilgangsstyringsroller og metoden til henrette. AWS Lambda bruker konfigurasjonen din til å sette opp en container og distribuere containeren til en EC2-forekomst. Deretter kjører metoden du har spesifisert, i rekkefølgen av pakke, klasse og metode.

I skrivende stund kan du bygge Lambda-funksjoner i Node, Java, Python og sist C #. I forbindelse med denne artikkelen vil vi bruke Java.

Hva er en Lambda-funksjon?

Når du skriver kode designet for å kjøre i AWS Lambda, skriver du funksjoner. Begrepet funksjoner kommer fra funksjonell programmering, som har sitt utspring i lambdakalkulus. Den grunnleggende ideen er å komponere et program som en samling funksjoner, som er metoder som godtar argumenter, beregner et resultat og ikke har noen uønskede bivirkninger. Funksjonell programmering tar en matematisk tilnærming til å skrive kode som kan bevises å være riktig. Selv om det er bra å huske på funksjonell programmering når du skriver kode for AWS Lambda, er alt du virkelig trenger å forstå at funksjonen er et inngangspunkt med en metode som godtar et inngangsobjekt og returnerer et utgangsobjekt.

Serverløse kjøringsmoduser

Mens Lambda-funksjoner kan kjøres synkront, som beskrevet ovenfor, kan de også kjøre asynkront og som svar på hendelser. For eksempel kan du konfigurere en Lambda til å kjøre når en fil ble lastet opp til en S3-bøtte. Denne konfigurasjonen brukes noen ganger for bilde- eller videobehandling: når et nytt bilde lastes opp til en S3-bøtte, blir en Lambda-funksjon påkalt med en referanse til bildet for å behandle det.

Jeg jobbet med et veldig stort selskap som utnyttet denne løsningen for fotografer som dekker et maratonløp. Fotografene var på kurset og tok bilder. Når minnekortene var fulle, lastet de bildene på en bærbar datamaskin og lastet opp filene til S3. Etter hvert som bilder ble lastet opp ble Lambda-funksjoner utført for å endre størrelse, vannmerke og legge til en referanse for hvert bilde til løperen i databasen.

Alt dette ville ta mye arbeid å utføre manuelt, men i dette tilfellet ble ikke arbeidet behandlet raskere på grunn av AWS Lambdas horisontale skalerbarhet, men også sømløst skalert opp og ned, og dermed optimalisert selskapets skyregning.

I tillegg til å svare på filer lastet opp til S3, kan lambdas utløses av andre kilder, for eksempel poster som settes inn i en DynamoDB-database og analytisk informasjonsstrømming fra Amazon Kinesis. Vi ser på et eksempel med DynamoDB i del 2.

AWS Lambda fungerer i Java

Nå som du vet litt om serverløs databehandling og AWS Lambda, vil jeg lede deg gjennom å bygge en AWS Lambda-funksjon i Java.

last ned Få koden Kildekode for eksempelapplikasjonen for denne opplæringen, "Serverless computing with AWS Lambda." Skapt av Steven Haines for JavaWorld.

Implementering av Lambda-funksjoner

Du kan skrive en Lambda-funksjon på en av to måter:

  • Funksjonen kan motta en inngangsstrøm til klienten og skrive til en utgangsstrøm tilbake til klienten.
  • Funksjonen kan bruke et forhåndsdefinert grensesnitt, i hvilket tilfelle AWS Lambda automatisk deserialiserer inngangsstrømmen til et objekt, sender den til din funksjon og serierer funksjonens respons før den returneres til klienten.

Den enkleste måten å implementere en AWS Lambda-funksjon på er å bruke et forhåndsdefinert grensesnitt. For Java må du først ta med følgende AWS Lambda-kjernebibliotek i prosjektet ditt (merk at dette eksemplet bruker Maven):

 com.amazonaws aws-lambda-java-core 1.1.0 

La klassen din implementere følgende grensesnitt:

Oppføring 1. RequestHandler.java

 offentlig grensesnitt RequestHandler {/ ** * Håndterer en Lambda-funksjonsforespørsel * @param-inngang Lambda-funksjonens inngang * @param-kontekst Kontekstobjektet Lambda-kjøringsmiljø. * @return Lambdafunksjonens utgang * / offentlig O handleRequest (I input, Context context); } 

De RequestHandler grensesnitt definerer en enkelt metode: handleRequest (), som sendes et inngangsobjekt og en Kontekst objektet, og returnerer et utgangsobjekt. For eksempel hvis du skulle definere en Be om klasse og en Respons klasse, kan du implementere lambdaen din på følgende måte:

 offentlig klasse MyHandler implementerer RequestHandler {public Response handleRequest (Request request, Context context) {...}} 

Alternativt, hvis du vil omgå det forhåndsdefinerte grensesnittet, kan du manuelt håndtere InputStream og OutputStream deg selv, ved å implementere en metode med følgende signatur:

 public void handleRequest (InputStream inputStream, OutputStream outputStream, Context context) kaster IOException {...} 

De Kontekst objektet gir informasjon om funksjonen din og miljøet den kjører i, for eksempel funksjonsnavnet, minnegrensen, loggeren og gjenværende tid, i millisekunder, som funksjonen må fullføre før AWS Lambda dreper den.