3 Ağustos 2021 Salı

Amazon Web Service (AWS) Lambda

Giriş
2014 yılında piyasaya sürüldü.  Function As A Service (FAAS) hizmeti verir. Event'lere bağlanabilen fonksiyonlar yazarak, servisleri çağırabilmemize sağlar. Açıklaması şöyle"Google Cloud Run" sanırım aynı işlevi görüyor.
AWS Lambda lets you execute code without having to provision and manage any underlying server resources. The solution is based on events, which are configurable using Lambda functions. 

Each Lambda function is triggered in response to either an AWS event or an API call made by the AWS API Gateway. You can also trigger events by setting up manual invocations via the user interface. It is also possible to schedule Lambda functions.
Hangi Dilleri Destekler
Açıklaması şöyle
It supports major programming languages such as C#, Python, Java, Ruby, Go, and Node.js. It also supports custom runtime.
Ücretlendirme
Açıklaması şöyle. Lambda'nın kaç milisaniye çalıştığına göre ücretlendiriliyor. Lambda en fazla 15 dakika çalışabilir
The pricing is based on milliseconds of usage, rounding off to the nearest millisecond.
Hangi Kaynaklara Bağlanabilir
Açıklaması şöyle. Lambda, DynamoDB, S3 gibi şeylere bağlanabilir.
AWS Lambda is a compute service that runs your code in response to events, for example, when data is inserted in a DynamoDB table or when a file is uploaded to S3 or whenever a request hits one of the API endpoints and automatically manage the compute resources for you, making it easy to build applications that respond quickly to new information.

Lambda Core Features:

- Runs code on demand.
- No Servers: Servers, OS Maintenance, Scaling, Provisioning, and Deployment is managed for you.
- Code starts running within milliseconds of receiving the event trigger.
Adımlar şöyle. Burada Lambda, bir SNS kuyruğuna bağlanıyor. Lambda için IAM Role seçiliyor
- From Services, click on Lambda
- In Dashboard, click on Create Function button.
- Fill in the needed information and do not forget to select an existing role, which is the one we created.
- In the designer part, click on Add Trigger.
- In trigger configuration, search for SNS and then look for the SNS topic we created earlier.
- Done! This function will be triggered whenever SNS topic receives messages.
Bir örnek burada

AWS Lambda vs AWS Fargate
Temel fark şöyle. AWS Lambda kısa süreli, daha az bellek gerektiren işler içindir. AWS Fargate ise daha fazla kaynak gerektiren ve sürekli çalışan sunucular gibi işlere uygundur

Lambda Bileşenleri
3 bileşenden oluşur. Açıklaması şöyle
1) Function: A function is a piece of code written by developers to perform a task. The code also contains the details of the runtime environment of the function. The runtime environments are based on Amazon Linux AMI and contain all required libraries and packages. Capacity and maintenance are handled by AWS.

a. Code Package: The packaged code containing the binaries and assets required for the code to run. The maximum size is 250 MB or 50 MB in a compressed version.
b. Handler: The starting point of the invoked function running a task based on parameters provided by event objects.
c. Event Object: A parameter provided to the Handler to perform the logic for an operation.
d. Context Object: Facilitates interaction between the function code and the execution environment. The data available for Context Objects include:
 i. AWS Request ID
 ii. Remaining time for the function to time out
 iii. Logging statements to CloudWatch

2) Configuration: Rules that specify how a function is executed.

a. IAM Roles: Assigns permissions for functions to interact with AWS services.
b. Network Configuration: Specifies rules to run functions inside a VPC or outside a VPC.
c. Version: Reverts functions to previous versions.
d. Memory Dial: Controls resource allocations to functions.
e. Environment Variables: Values injected into the code during the runtime.
f. Timeout: Time for a function to run.

3) Event Source: The event that triggers the function.
a. Push Model: Functions triggered via S3 objects, API Gateway and Amazon Alexa.
b. Pull Model: Lambda pulls events from DynamoDB or Kinesis.

AWS Lambda Cold Start Problem
AWS Lambda Cold Start yazısına taşıdım

Cross-Region Lambda Invocation in AWS
Bu mümkün. Bir örnek burada

REST Yerine Lambda Kullanılmamalı
Açıklaması şöyle
Lambdas are great for the following tasks:
- Serving/Redirecting requests to CloudFront.
- Reacting to events from SNS or SQS — Small asynchronous tasks such as Image transformation (write to S3), OCR, and ETL (When volume is small and you can batch process).

Lambda is horrible for:
A replacement for REST API endpoints.
Take an example of online book shopping REST api:
/api/v1/books — GET/POST/PUT/DELETE
/api/v1/users — GET/POST/PUT
/api/v1/carts — GET/POST/PUT/DELETE
/api/v1/search — GET
/api/v1/stats — GET
… Many more.
A mature internal REST API endpoints can and will have hundreds of REST routes.
...
With the Lambda server-less paradigm, you end up with 1 lambda function per route.
AWS Lambda Planes
AWA Lambda 2 tane düzlemden ibarettir. Açıklaması şöyle
The Lambda service is divided into two planes: The control plane and the data plane. The former being responsible for the function management API (UpdateFunctionCode, CreateFunction, DeleteFunction, etc) and the latter being responsible for the invocation API that invokes Lambda functions.
AWS Lambda Invocation
Açıklaması şöyle
The Lambda invocation flow is a whole set of services working together to provide the complete range of functionality that Lambda provides. These services are:

Worker — A secure environment for customers to execute their code in. This is the service responsible for downloading your code package and executing it in an environment.

Worker Manager — As you might have guessed, this manages workers. It tracks the usage of resources and execution environments and handles the assignments of requests.

Frontend Worker — This receives function invocation requests, validates them and dispatches the requests to the Worker Manager.

Load Balancer — Distributes invocation requests to multiple frontend invokers in different availability zones. When AZ failures are detected, requests are routed to alternate AZ’s automatically.

There is also a Placement Service to manage the packing density of sandboxes on Workers and a Counter Service that’s responsible for tracking usage as well as concurrency limits.

To put the above services into some sort of flow to understand how they’d interact with one another, it would look a bit like this:
1. Incoming invocation requests are passed by a Load Balancer to a selected Frontend Worker
2. The Frontend Worker validates the quests and asks the Worker Manager for a sandboxed function that will handle the function invocation
3. The Worker Manager either finds a pre-existing Worker or it creates one
4. Function code is executed by a Worker
AWS Eventbridge ve AWS Lambda
Açıklaması şöyle. Yani AWS Lambda artık scheduler ile kullanılabilir
We can create a lambda function and that can be triggered by AWS eventbridge with the scheduled events.
..

It is good to use Schedulers over AWS Eventbridge…

1. If the execution time of scheduler function is more than 15 mins (Because lambda function won’t run more than 15mins)
2. If the shceduler will invoke 3rd party apis or database queries that take more than 15 mins to complete.
3. If you don’t have any dynamic data to be passed to the scheduler function like current time etc. (If you have a scheduler that will depend on dynamic data, you have to use AWS eventbridge to send that data with the event)
4. Apart from time, if your scheduler doesn’t need to be triggered by external events, like AWS RDS database events, AWS SQS events, AWS Api gateway events, etc.

AWS Üzerinde Geliştirme İçin Şunlar Kullanılabilir
Açıklaması şöyle
1. Serverless Framework
2. Terraform
3. AWS SAM (Serverless Application Model) - AWS’s response to Serverless Framework.
4. Cloudformation - AWS specific alternative to Terraform
Deployment
Adımları burada aldım
1. Docker image oluştur
Şöyle yaparız
FROM public.ecr.aws/lambda/java:11

# Copy function code and runtime dependencies from Maven layout
COPY target/classes ${LAMBDA_TASK_ROOT}
COPY target/dependency/* ${LAMBDA_TASK_ROOT}/lib/

# Set the CMD to your handler (could also be done as a parameter override outside of the
# Dockerfile)
CMD [ "com.shady.GreetingsHandler::handleRequest" ]
2. Amazon Elastic Container Registry (ECR) üzerinde yeni bir repository oluştur. Buraya Docker image'ları depolanacak
3. AWS Lambda oluştur ve ECR'a erişmesi için izinleri ayarla, ECR'daki image'i seç
4. Docker image'i ECR'a yükle

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-lambda-java-core</artifactId>
  <version>1.2.1</version>
</dependency>
Örnek - Thread
Thread'lerin bitmesini beklemek gerekir. Şöyle yaparız
import com.amazonaws.services.lambda.runtime.Context;

public static String handleRequest(String input, Context context) 
  throws InterruptedException {
  
  int numberOfPages = 3;
  CountDownLatch latch = new CountDownLatch(numberOfPages);

  for (int i = 0; i < numberOfPages; i++) {
    new Thread(new DataDownloader(i, latch)).start();
  }

  latch.await();
  
}
Örnek - Serverless Framework
Spring için şu satırı dahil ederiz
aws-serverless-java-container-spring
Şöyle yaparız
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import javax.ws.rs.core.Application;

public class LambdaHandler implements RequestStreamHandler {
  private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse>
    handler;
  static {
    try {
      handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(
        SpringBootServerlessApplication.class);
    } catch (ContainerInitializationException e) {
      // Re-throw the exception to force another cold start
      e.printStackTrace();
      throw new RuntimeException("Could not initialize Spring Boot application", e);
    }
  }
  @Override
  public void handleRequest(InputStream inputStream, OutputStream outputStream,
    Context context) throws IOException {
    handler.proxyStream(inputStream, outputStream, context);
    // just in case it wasn't closed by the mapper
    outputStream.close();
  }
}
Açıklaması şöyle
The getAwsProxyHandler method is expecting a WebApplicationInitializer class parameter . Since the SpringBootServletInitializer class implement the WebApplicationInitializer interface, we can update the SpringBootServerlessApplication class to extend the SpringBootServletInitializer on startup to configure the things.
serverless.yaml şöyle
service: spring-boot-serverless
provider:
  name: aws
  runtime: java11
package:
  artifact: build/distributions/spring-boot-serverless-0.0.1-SNAPSHOT.zip
functions:
  springBootServerless:
    handler: com.poc.springbootserverless.LambdaHandler::handleRequest
    events:
      - http:
          path: /users
          method: get
    timeout: 30

Örnek - Java ve Static Initialization
Şu satırı dahil ederiz
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-lambda-java-core</artifactId>
  <version>${aws.lambda.java.core.version}</version>
</dependency>

<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-lambda-java-events</artifactId>
  <version>${aws.lambda.java.events.version}</version>
</dependency>
Şöyle yaparız. Gelen veri DynamoDb'ye yazılıyor
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;

public class BookHandler implements
RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

  @Override
  public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent
apiGatewayProxyRequestEvent, Context context) {
    return ENHANCED_REQUEST_DISPATCHER.dispatch(apiGatewayProxyRequestEvent);
  }
}
Örnek - Java ve Static Olmayan Initialization
Şöyle yaparız. Bu kod Static Initialization kullanan koda göre daha yavaş olabilir.
public class BookHandler implements
  RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

  private static final String TABLE_NAME = "books";
  private final RequestDispatcher requestDispatcher;

  public BookHandler() {
    DynamoDbEnhancedClient dynamoDbEnhancedClient = DynamoDbEnhancedClient.create();
    DynamoDbTable<Book> dynamoDbTable = dynamoDbEnhancedClient
      .table(TABLE_NAME, TableSchema.fromBean(Book.class));
    requestDispatcher = new RequestDispatcher(
      new EnhancedClientBookStorage(dynamoDbTable), new ObjectMapper());
  }


  @Override
  public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent
    apiGatewayProxyRequestEvent, Context context) {
    return requestDispatcher.dispatch(apiGatewayProxyRequestEvent);
  }
}
Örnek - GraalVM
Bir örnek burada

Örnek - Micronaut
Repository şöyle olsun
@Repository
public interface OrderRepository extends JpaRepository<Order, Long>{ }
application.yml şöyle olsun
datasources:
default: url: jdbc:mysql://foo.rds.amazonaws.com:3306/ORDERS_DB?characterEncoding=UTF-8 username: admin password: nopass driverClassName: com.mysql.cj.jdbc.Driver jpa: default: properties: hibernate: hbm2ddl: auto: update show_sql: true dialect: org.hibernate.dialect.MySQL8Dialect
Şöyle yaparız
@Introspected
public class OrderRequestHandler extends MicronautRequestHandler<Order, Order> {

  @Inject
  private OrderRepository orderRepository;

  @Override
  public Order execute(Order input) {
    Order saved = this.orderRepository.save(input);
    return saved;
  }
}

Hiç yorum yok:

Yorum Gönder