Lab 3: Serverless - Faas Service targeting DB service

Ouvert le : mardi 23 novembre 2021, 18:58
À remettre : mardi 30 novembre 2021, 18:30

Exercise: Serverless - Faas Service targeting DB service

Introduction and Prerequisites

This exercise is to:

  • Become familiar with a Function-as-a-Service platform,
  • Learn how to deploy and monitor a function,
  • Compare latencies in the case of warm start and cold start.

In this exercise you will use three different public cloud providers to deploy a function in an FaaS service. The function is triggered by HTTP requests and returns an HTTP response. The function reads data from a DB and returns it in its response.

You will then run load tests using the JMeter tool on your local machine and measure the latencies of function execution.

The following resources and tools are required for this exercise session:

  • Account on AWS Academy
  • Account on Azure Cloud
  • Account on Google Cloud Platform

Please respect the case of the DB table names given or the functions will may not work.

Task 1 - Using AWS

Task 1.1 - Create DynamoDB table

Using the AWS Management Console create a table in DynamoDB. Use the guide Getting Started with DynamoDB and follow the instructions for Step 1: Create a Table.

Add the following items to your database :

{
    "Artist": "No One You Know",
    "SongTitle": "Call Me Today",
    "AlbumTitle": "Somewhat Famous",
    "Awards": 1
}
{
    "Artist": "Acme Band",
    "SongTitle": "Happy Day",
    "AlbumTitle": "Songs About Life",
    "Awards": 10
}

There are two options for creating items: Form and JSON. We recommend the JSON option. Items must be created one by one.

Task 1.2 - Create a function Lambda on AWS

We will a create function that accesses DynamoDB to read data.

To create and deploy the function we will use an AWS-provided blueprint that will not only create and deploy a ready-made function, but also:

  • configure the necessary access control rights so that the function is able to access DynamoDB,
  • deploy an API on the API Gateway service so that an HTTP request to the API gateway triggers the execution of the function, and
  • configure the necessary access control rights for API Gateway.

Create a Lambda function (from Lambda service) with an API Gateway using a blueprint called microservice-http-endpoint-python. Fill in the following fields and leave the rest at their default settings:

  • Basic information

    • Function name: myfunc
    • Check Create a new role from AWS policy templates.
    • Role name: put a random name
    • Policy templates: Simple microservice permissions DynamoDB
  • API Gateway trigger

    • Create a new API
    • API type: HTTP API
    • Security: Open

Create the function.

In the function panel, in the code editor, replace the function code with the following :

import boto3
import json

print('Loading function')
dynamo = boto3.client('dynamodb')


def respond(err, res=None):
    return {
        'statusCode': '400' if err else '200',
        'body': err.message if err else json.dumps(res),
        'headers': {
            'Content-Type': 'application/json',
        },
    }


def lambda_handler(event, context):
    '''Demonstrates a simple HTTP endpoint using API Gateway. You have full
    access to the request and response payload, including headers and
    status code.

    To scan a DynamoDB table, make a GET request with the TableName as a
    query string parameter. To put, update, or delete an item, make a POST,
    PUT, or DELETE request respectively, passing in the payload to the
    DynamoDB API as a JSON body.
    '''
    print("Received event: " + json.dumps(event, indent=2))

    operations = {
        'DELETE': lambda dynamo, x: dynamo.delete_item(**x),
        'GET': lambda dynamo, x: dynamo.scan(**x),
        'POST': lambda dynamo, x: dynamo.put_item(**x),
        'PUT': lambda dynamo, x: dynamo.update_item(**x),
    }

    operation = event['requestContext']['http']['method']
    if operation in operations:
        payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body'])
        return respond(None, operations[operation](dynamo, payload))
    else:
        return respond(ValueError('Unsupported method "{}"'.format(operation)))

Click on Deploy Button. 

The complete URL (available through the API gateway view) will looks like :

https://s0z5ibz1wf.execute-api.us-east-1.amazonaws.com/[nameOfTheFunction]?TableName=Music

Test the newly deployed function by entering the complete URL in the address bar of your web browser. You are now experiencing a function cold start. After some seconds, you should see a response containing the data from the database.

Task 2 - Using Google Cloud Platform

Task 2.1 - Create a Datastore

Go to Datastore service

Create a datastore on GCP and create the equivalent of AWS DynamoDB created on task 1.1, and add the same entries with the kind "Music".

Task 2.2 - Create a Cloud Function on GCP

We will a create a function that accesses the Datastore to read data.

Go to Cloud Functions service.

Create a Cloud function on GCP, on Europe region, HTTP trigger type and allowing unauthenticated invocations. Select python 3.9 runtime and paste the following code in the editor and change they entry point with the correct function name :

main.py:

from google.cloud import datastore
import json

def query(request):
    """Responds to any HTTP request.
    Args:
        request (flask.Request): HTTP request object.
    Returns:
        The response text or any set of values that can be turned into a
        Response object using
        `make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
    """
    l = list()
   
    client = datastore.Client()
    query = client.query(kind='Music')
    l = query.fetch()
    l = list(l)
    print(l)
    print(l)
    return json.dumps(l)

Add google-cloud-datastore to the requirements.txt file.

Retrieve the URL of your function from the Trigger view for testing it in your browser.

Task 3 - Using Azure Cloud

Task 3.1 - Create CosmosDB database

Go to Azure Cosmos DB

Create a CosmosDB account by choosing the Core (SQL) API option, on Switzerland North region.

When the account is created, go in the ressource and go to Data explorer on the left menu. Then create a new database named serverless-db and a container named Music. Finally add the two items of task 1.1 in the Items part of Music container.

On the left panel : Go in Settings > Keys and copy the PRIMARY CONNECTION STRING in a Notepad. This data is needed during the next task.

Task 3.2 - Create a Function App on Azure cloud

Go to Function App Service

Create a new Function App on python 3.9 and Switzerland North region. Go to the new resource created.

Create a new function : Functions > Functions > Create and follow the tutorial from Azure for creating function in your Code editor. Tip : Use the Visual Studio Code add-on it will be simpler for you.

For this part create an HTTP Trigger function without any authentication needed.

In your editor, once the function is created, fill the following files :

__init.py__:

import logging
import json
import azure.functions as func

def main(req: func.HttpRequest, doc:func.DocumentList) -> func.HttpResponse:
    
    logging.info('Python HTTP trigger function processed a request.')
 
    entries_json = []

    for entry in doc:
        entry_json = {
            "id": entry['id'],
            "AlbumTitle": entry['AlbumTitle'],
            "Artist": entry['Artist'],
            "SongTitle": entry['SongTitle'],
            "Awards": entry['Awards'],
        }
        entries_json.append(entry_json)

    return func.HttpResponse(
            json.dumps(entries_json),
            status_code=200,
            mimetype="application/json"            
    )

function.json:

{
    "scriptFile": "__init__.py",
    "bindings": [{
            "authLevel": "anonymous",
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": [
                "get",
                "post"
            ],
            "route": "music/list"
        },
        {
            "type": "cosmosDB",
            "direction": "in",
            "name": "doc",
            "databaseName": "serverless-db",
            "collectionName": "Music",
            "createIfNotExists": "true",
            "connectionStringSetting": "AzureCosmosDBConnectionString",
            "sqlQuery": "SELECT * from c"
        },
        {
            "type": "http",
            "direction": "out",
            "name": "$return"
        }
    ]
}

For locally testing purposes, the local.settings.json need to looks lie this. Replace "INSERT HERE PRIMARY CONNECTION STRING" by your PRIMARY CONNECTION STRING saved earlier :

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "",
        "FUNCTIONS_WORKER_RUNTIME": "python"
    },
    "ConnectionStrings": {
        "AzureCosmosDBConnectionString": "INSERT HERE PRIMARY CONNECTION STRING"
    }
}

After deploying your function on Azure Cloud, this won't work directly because the CosmosDB service is not linked to your function App. To resolve this, you need to go to your Function App Resource panel > Settings > Configuration.

Then add a "New connection string" > Name : AzureCosmosDBConnectionString > Value : Your PRIMARY CONNECTION STRING > Type : Custom.

Retrieve the URL from the HTTP Trigger view and test it in your browser.

Task 4 - Measure latency of warm sandboxes and cold start

You need to do this task for each provider.

In this task you will performance test the Lambda platform with a load generator. You will compare the performance of request processing when the function is already deployed in sandboxes ("warm sandboxes") and request processing when the function code hasn't been deployed yet ("cold start").

  1. Download and install on your local machine JMeter from http://jmeter.apache.org/.

  2. First test the performance of normal request processing with warm sandboxes.

    • Open JMeter and create a new test plan. Add a Thread Group under the test plan and add a HTTP Request to this Thread Group. In the HTTP Request sampler you configure the function's invoke URL (plus the query string). You have to split it into the Server name or IP part and the Path part.
    • Find the correct(s) listener(s) to see your tests results (Graph Result)
    • Open the provider's metrics dashboard of your function: called Monitor on AWS, Metrics on Google and Azure.
    • Run a test with 1 user and a loop count of 10.
    • Observe the requests in the dashboard and in JMeter. What do you see? What is the function latency in the case of warm sandboxes?
  3. To test cold start latency modify the code of the function slightly to create a new version (e.g., add a print statement) and deploy it. This invalidates the previous version deployed in the sandboxes and forces the platform to load the new version. Repeat the JMeter test and observe the latency of the first request and the subsequent requests. What do you see?

Deliverables (D1):

  • For each performance test, copy a screenshot of the JMeter Graph Results listener and the Metrics graphs of the dashboard view into the report.
  • Compare the response times shown by JMeter and the Management Console. Explain the difference.
  • How much resources have you used running these tests? How many invocations and how many Gigabyte-seconds of execution? Does your resource usage remain within the free tier?

Task 5 - Comparative study between Azure, GCP, AWS

In addition of the metrics you've done, Perform a comparative study of the three tools based on the following criteria:

  1. Concurrency
  2. Asynchronous calls
  3. Programming flexibility. As example, AWS Lambda functions support container images, layers and extensions. The user hase the possibility to choose and/or combine these features according to his needs.
  4. Cold/warm start

Delivrables (D2): One-page document detailing the advantages and disadvantages of each provider with respect to these three criteria.

Please combine D1 and D2 in one document.

Cleanup

After you have finished this exercise, for each provider:

  • Delete the databases
  • Delete the function
  • Delete the API Gateway (AWS)

Remember that every resource left may cost you and drain your credit.

If you have any questions related to AWS Amazon, contact francisco(dot)mendonca(at)hesge(dot)ch

If you have any questions related to Google or Azure, contact guillaume-auguste(dot)riondet(at)hesge(dot)ch