Serverlös datoranvändning med AWS Lambda, del 1

Serverlös databehandling kan vara det hetaste i cloud computing idag, men vad är det exakt? Denna tvådelade handledning börjar med en översikt över serverlös dator - från vad det är, till varför det anses störande för traditionell molnbearbetning och hur du kan använda det i Java-baserad programmering.

Efter översikten får du en praktisk introduktion till AWS Lambda, som av många anses vara den främsta Java-baserade lösningen för serverlös dator idag. I del 1 använder du AWS Lambda för att bygga, distribuera och testa din första Lambda-funktion i Java. I del 2 integrerar du din Lambda-funktion med DynamoDB och använder sedan AWS SDK för att åberopa Lambda-funktioner i ett Java-program.

Vad är serverlös databehandling?

Förra året pratade jag med en företagspraktikant om olika arkitektoniska mönster och nämnde serverlös arkitektur. Han noterade snabbt att alla applikationer kräver en server och inte kan köras i luften. Praktikanten hade en poäng, även om han saknade min. Serverlös dator är inte en magisk plattform för att köra applikationer.

I själva verket innebär serverlös dator helt enkelt att du, utvecklaren, inte behöver ta itu med servern. En serverlös datorplattform som AWS Lambda låter dig bygga din kod och distribuera den utan att behöva konfigurera eller hantera underliggande servrar. Din distributionsenhet är din kod; inte behållaren som är värd för koden eller servern som kör koden utan bara själva koden. Ur produktivitetssynpunkt finns det uppenbara fördelar med att ladda ner detaljerna om var kod lagras och hur körningsmiljön hanteras. Serverlös databehandling prissätts också baserat på exekveringsmått, så det finns också en ekonomisk fördel.

Vad kostar AWS Lambda?

När detta skrivs är AWS Lambdas prisnivå baserat på antal avrättningar och exekveringstid:

  • Dina första miljoner avrättningar per månad är gratis, sedan betalar du 0,20 dollar per miljon avrättningar därefter (0,0000,002 USD per förfrågan).
  • Varaktigheten beräknas från det att din kod börjar köra tills den returnerar ett resultat, avrundat till närmaste 100 ms. Det belopp som debiteras baseras på mängden RAM som tilldelats funktionen, där kostnaden är $ 0,00001667 för varje GB-sekund.

Prisdetaljer och kostnadsnivåer är lite mer komplicerade än översikten antyder. Besök prisnivån för att gå igenom några prissättningsscenarier.

För att få en uppfattning om hur serverlös databehandling fungerar, låt oss börja med den serverlösa datorkörningsmodellen, som illustreras i figur 1.

Steven Haines

Här är den serverlösa exekveringsmodellen i ett nötskal:

  1. En klient gör en begäran till den serverlösa datorplattformen om att utföra en specifik funktion.
  2. Den serverlösa datorplattformen kontrollerar först om funktionen körs på någon av dess servrar. Om funktionen inte redan körs laddar plattformen funktionen från ett datalager.
  3. Plattformen distribuerar sedan funktionen till en av dess servrar, som är förkonfigurerade med en exekveringsmiljö som kan köra funktionen.
  4. Den utför funktionen och fångar resultatet.
  5. Det returnerar resultatet tillbaka till klienten.

Ibland kallas serverlös databehandling Funktion som en tjänst (FaaS), eftersom kornens detaljerighet är en funktion . Plattformen kör din funktion på sin egen server och ordnar processen mellan funktionsförfrågningar och funktionssvar.

Nanotjänster, skalbarhet och pris

Tre saker har verkligen betydelse för serverlös dator: dess nanoservicearkitektur; det faktum att det är praktiskt taget oändligt skalbart; och prissättningsmodellen associerad med den nära oändliga skalbarheten. Vi gräver i var och en av dessa faktorer.

Nanotjänster

Du har hört talas om mikrotjänster och du känner antagligen till applikationer med 12 faktorer, men serverlösa funktioner tar paradigmet att bryta ner en komponent till dess beståndsdelar till en helt ny nivå. Uttrycket "nanotjänster" är inte ett branschkänt begrepp, men tanken är enkel: varje nanotjänst bör genomföra en enda åtgärd eller ett ansvar. Till exempel, om du ville skapa en widget, skulle skapelsen vara sin egen nanotjänst; om du ville hämta en widget skulle hämtningen också vara en nanotjänst; och om du ville göra en beställning för en widget skulle den beställningen vara ännu en nanotjänst.

En nanotjänstarkitektur låter dig definiera din applikation på en mycket finkornig nivå. I likhet med testdriven utveckling (som hjälper dig att undvika oönskade biverkningar genom att skriva din kod på nivå med individuella tester), uppmuntrar en nanotjänstarkitektur att definiera din applikation när det gäller mycket finkorniga och specifika funktioner. Detta tillvägagångssätt ökar tydligheten om vad du bygger och minskar oönskade biverkningar från ny kod.

Mikrotjänster vs nanotjänster

Microservices uppmuntrar oss att dela upp en applikation i en samling tjänster som var och en utför en specifik uppgift. Utmaningen är att ingen riktigt har kvantifierat omfattningen av en mikrotjänst. Som ett resultat definierar vi mikrotjänster som en samling relaterade tjänster, som alla interagerar med samma datamodell. Konceptuellt, om du har lågnivåfunktion som interagerar med en viss datamodell, bör funktionaliteten gå in i en av dess relaterade tjänster. Interaktioner på hög nivå bör ringa till tjänsten snarare än att fråga direkt i databasen.

Det pågår en kontinuerlig debatt i serverlös databehandling om huruvida man ska bygga Lambda-funktioner på nivån av mikrotjänster eller nanotjänster. Den goda nyheten är att du ganska enkelt kan bygga dina funktioner i antingen granularitet, men en mikrotjänststrategi kräver lite extra routningslogik i din begäranhanterare.

Ur ett designperspektiv bör serverlösa applikationer vara väldefinierade och rena. Från ett distributionsperspektiv måste du hantera betydligt fler distributioner, men du kommer också att ha möjlighet att distribuera nya versioner av dina funktioner individuellt utan att påverka andra funktioner. Serverlös databehandling är särskilt väl lämpad för utveckling i stora team, där det kan göra utvecklingsprocessen enklare och koden mindre felbenägen.

Skalbarhet

Förutom att introducera ett nytt arkitektoniskt paradigm, erbjuder serverlösa datorplattformar praktiskt taget oändlig skalbarhet. Jag säger "praktiskt taget" för det finns inget sådant som verkligenoändlig skalbarhet. För alla praktiska ändamål kan dock serverlösa dataleverantörer som Amazon hantera mer belastning än du skulle kunna kasta på dem. Om du skulle hantera uppskalning av dina egna servrar (eller molnbaserade virtuella maskiner) för att möta ökad efterfrågan, måste du övervaka användningen, identifiera när du ska starta fler servrar och lägga till fler servrar i ditt kluster vid rätt tidpunkt. På samma sätt, när efterfrågan minskade, skulle du behöva skala ner manuellt. Med serverlös dator berättar du din serverlösa datorplattform om det maximala antalet samtidiga funktionsförfrågningar du vill köra och plattformen gör skalningen åt dig.

Prissättning

Slutligen låter den serverlösa databehandlingsprismodellen dig skala din molnräkning baserat på användning. När du har lätt användning kommer din räkning att vara låg (eller ingen om du stannar i det fria utbudet). Naturligtvis kommer din faktura att öka med användning, men förhoppningsvis kommer du också att få nya intäkter för att stödja din högre molnräkning. Om du däremot skulle hantera dina egna servrar måste du betala en baskostnad för att köra det minsta antal servrar som krävs. När användningen ökade skulle du öka i steg om hela servrar, snarare än steg för enskilda funktionssamtal. Den serverfria databehandlingsmodellen är direkt proportionell mot din användning.

AWS Lambda för serverlös databehandling

AWS Lambda är en serverlös datorplattform implementerad ovanpå Amazon Web Services-plattformar som EC2 och S3. AWS Lambda krypterar och lagrar din kod i S3. När en funktion ombeds att köras skapar den en "container" med dina runtime-specifikationer, distribuerar den till en av EC2-instanserna i dess beräkningsfarm och kör den funktionen. Processen visas i figur 2.

Steven Haines

When you create a Lambda function, you configure it in AWS Lambda, specifying things like the runtime environment (we'll use Java 8 for this article), how much memory to allocate to it, identity and access management roles, and the method to execute. AWS Lambda uses your configuration to setup a container and deploy the container to an EC2 instance. It then executes the method that you've specified, in the order of package, class, and method.

At the time of this writing, you can build Lambda functions in Node, Java, Python, and most recently, C#. For the purposes of this article we will use Java.

What is a Lambda function?

When you write code designed to run in AWS Lambda, you are writing functions. The term functions comes from functional programming, which originated in lambda calculus. The basic idea is to compose an application as a collection of functions, which are methods that accept arguments, compute a result, and have no unwanted side-effects. Functional programming takes a mathematical approach to writing code that can be proven to be correct. While it's good to keep functional programming in mind when you are writing code for AWS Lambda, all you really need to understand is that the function is a single-method entry-point that accepts an input object and returns an output object.

Serverless execution modes

While Lambda functions can run synchronously, as described above, they can also run asynchronously and in response to events. For example, you could configure a Lambda to run whenever a file was uploaded to an S3 bucket. This configuration is sometimes used for image or video processing: when a new image is uploaded to an S3 bucket, a Lambda function is invoked with a reference to the image to process it.

I worked with a very large company that leveraged this solution for photographers covering a marathon. The photographers were on the course taking photographs. Once their memory cards were full, they loaded the images onto a laptop and uploaded the files to S3. As images were uploaded, Lambda functions were executed to resize, watermark, and add a reference for each image to its runner in the database.

All of this would take a lot of work to accomplish manually, but in this case the work not only processed faster because of AWS Lambda's horizontal scalability, but also seamlessly scaled up and back down, thus optimizing the company's cloud bill.

In addition to responding to files uploaded to S3, lambdas can be triggered by other sources, such as records being inserted into a DynamoDB database and analytic information streaming from Amazon Kinesis. We'll look at an example featuring DynamoDB in Part 2.

AWS Lambda functions in Java

Now that you know a little bit about serverless computing and AWS Lambda, I'lll walk you through building an AWS Lambda function in Java. 

ladda ner Skaffa koden Källkod för exempelapplikationen för den här självstudien "Serverless computing with AWS Lambda." Skapad av Steven Haines för JavaWorld.

Implementering av Lambda-funktioner

Du kan skriva en Lambda-funktion på ett av två sätt:

  • Funktionen kan ta emot en ingångsström till klienten och skriva till en utgångsström tillbaka till klienten.
  • Funktionen kan använda ett fördefinierat gränssnitt, i vilket fall AWS Lambda automatiskt avserialiserar ingångsströmmen till ett objekt, skickar den till din funktion och serierar din funktions svar innan den returneras till klienten.

Det enklaste sättet att implementera en AWS Lambda-funktion är att använda ett fördefinierat gränssnitt. För Java måste du först inkludera följande AWS Lambda-kärnbibliotek i ditt projekt (notera att detta exempel använder Maven):

 com.amazonaws aws-lambda-java-core 1.1.0  

Next, have your class implement the following interface:

Listing 1. RequestHandler.java

 public interface RequestHandler { /** * Handles a Lambda function request * @param input The Lambda function input * @param context The Lambda execution environment context object. * @return The Lambda function output */ public O handleRequest(I input, Context context); } 

The RequestHandler interface defines a single method: handleRequest(), which is passed an input object and a Context object, and returns an output object. For example, if you were to define a Request class and a Response class, you could implement your lambda as follows:

 public class MyHandler implements RequestHandler { public Response handleRequest(Request request, Context context) { ... } } 

Alternatively, if you wanted to bypass the predefined interface, you could manually handle the InputStream and OutputStream yourself, by implementing a method with the following signature:

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

The Context object provides information about your function and the environment in which it is running, such as the function name, its memory limit, its logger, and the amount of time remaining, in milliseconds, that the function has to complete before AWS Lambda kills it.