메뉴

문서정보

목차

AWS Lambda

HTTP 기반의 REST API 서버의 경우, stateless하게 개발을 한다. Stateless는 서버로의 모든 요청과 응답이 다른 요청 혹은 응답과 독립적으로 이루어지는 것을 의미한다. 서버는 상태를 저장할 필요가 없으므로 요청처리부가 단순해지고, 요청을 자유롭게 분산할 수 있다. 각 요청이 독립적으로 실행이된다면, 클라이언트와 서버간의 요청&처리 프로세스는 함수의 실행으로 추상화 할 수 있을 것이다. 실제 REST API에서 제공하는 API는 독립적인 핸들러로 만들어지는 경우가 많고, 이 핸들러는 길어도 수백라인 내외의 단일 함수나 마찬가지이다.

AWS 람다는 MSA 모델을 따르는 stateless한 서비스를 함수단위에서 개발할 수 있도록 도와주는 서비스다.

AWS Lambda의 장점과 단점

단순함. 서버 전개, 애플리케이션 개발환경 설정, CI/CD 파이프라인 설계 및 구축, 가용성/확장성 구성을 신경쓸 필요 없다. 개발자는 코드만 만들면 된다.

사용한 만큼만 돈을 낸다. 인터넷 서비스는 바쁜시간과 그렇지 않은 시간이 있다. 보통은 가장 바쁜 시간으로 인스턴스 갯수를 맞출테고, 컴퓨팅 자원을 낭비하는 구간이 생기게 된다. 오토 스케일링을 이용해서 인스턴스를 줄이고 늘이면 될거라고 생각할 수 있겠지만 이게 생각처럼 쉬운 것도 아니고, 그렇게 하더라도 낭비는 막을 수 없다. 람다는 호출 건당 과금이 효과적으로 비용을 관리할 수 있다.

장애 복원에 대해서 신경쓸 필요가 없다. 모든 위협을 AWS에 위임한다.

물론 단점도 있긴 하다. 람다는 5분 이상 걸리는 작업은 실패하고 자동으로 폐기된다. 오랜 시간을 요구하는 작업은 적합하지 않다. 엄밀히 따지자면 이건 단점이라기 보다는 제약사항이라고 봐야 할 것 같다. 애초에 HTTP API를 대신하는게 주요 목적인데, 5분이상 걸리는 요청 처리는 람다의 목적에 맞지 않다고 봐야 할 것이다. 이미지나 동영상 프로세싱 같은 시간이 많이 걸리는 작업은 다른 서비스를 이용해야 할 것이다.

아키텍처

API Gateway와 람다를 이용한 모바일 서버리스 아키텍처 예제다.

 람다 아키텍처

 람다 아키텍처

API Gateway는 API 호출을 읽어서 람다를 호출하는 일을 한다. 유저인증 요청의 경우, 람다 함수는 AWS 코그니토를 호출해서 인증을 처리한다. 비지니스 로직을 처리하는 람다 함수는 DynamoDB, RDS, S3, ElasticCache등을 호출한다. 위 아키텍처를 보면, 코드들이 람다로 만들어지면서 어떠한 인스턴스도 필요 없음을 알 수 있다.

PING REST API Service

PING REST API 서비스를 개발하기로 했다. 이 서비스는 API Gateway와 Lambda의 조합으로 구성한다.

Ping Lambda 함수 개발

AWS 람다는 Java, Python, Node.js, golang를 지원한다. 나는 아래의 이유로 go를 이용해서 개발하기로 했다.

가장 중요한 이유는 Go를 좋아하기 때문이다. 두번째 이유 Go는 정적으로 링크된 바이너리를 만든다. Node나 Python같은 소스 레벨 코드 또는 .NET 과 Java같은 컴파일된 바이트코드를 올리는 것과는 대조적이다. 여기에는 몇 가지 중요한 장점이 있다.

정적링크(Static link)는 배포시 다른 종속성을 제거한다. 소스 레벨 코드 혹은 바이트코드를 배포 할 때, 종속성은 배포 스택의 상당 부분을 차지한다. Go는 프로그램 실행에 필요한 모든 것들이 컴파일 시간이 링크되므로, 프로젝트의 레이아웃, 경로, 요구하는 라이브러리나 파일들을 고려할 필요가 없다. 즉 One File 배포가 가능하다.

또한 정적 바이너리 배포는 순방향 호환성을 보장한다. Go의 새로운 버전이 출시되더라도 그것이 작동할지를 걱정할 필요가 없다. 그냥 작동한다. 예를 들어 Node의 경우 awync/await를 사용하기 위해서 주의를 기울여야 하겠지만 Go는 그냥 새로 컴파일해서 밀어 넣기만 하면 된다. 람다언어로 go를 선택 할 경우 단지 1.x 하나의 버전만 있는데, 이는 1.0에서 2018년 3월 현재 최신버전인 1.10부터 향후 개발될 버전에 상관없이 모두 작동한다는 것을 의미한다.

아래와 같은 ping 예제 프로그램을 만들었다.
package main

import (
    "log"
  
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
)

// Handler는 람다함수함수를 호출 할 때 실행되는 코드다.
// AWS API Gateway의 요청과 응답 처리 매커니즘은 aws-lambda-go/envents 패키지가 제공한다.
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

    // 표준출력과 표준에러는 AWS CloudWatch 로그로 전송된다.
    log.Printf("Ping request %s\n", request.RequestContext.RequestID)

    // pong 메시지와 함께
    // HTTP 200 OK를 반환한다.
    return events.APIGatewayProxyResponse{
        Body:       "Pong",
        StatusCode: 200,
    }, nil

}

func main() {
    lambda.Start(Handler)
}

 create a function - 1

 create a function - 1

빌드 성공했다면, 컴파일된 실행 파일을 람다에 등록하면 된다. 람다 서비스 페이지로 이동해서 Create a function을 선택한다.

 create a function - 2

 create a function - 2

람다함수의 세부 스펙을 설정한다. Author from scratch, Blueprints, Serverless Application Repository 3가지 방식으로 함수를 만들 수 있다. Author from scratch 방식으로 만들었다. 이제 빌드한 람다 실행파일을 올리면 된다.

 함수 올리기

 함수 올리기

다양한 기능들이 있는데, 람다 파일을 올리고 테스트하는 핵심 기능만 살펴보겠다.

Function code섹션에서 람다 실행파일을 올릴 수 있다. ZIP, 혹은 S3에 있는 파일을 올릴 수 있다. 실제 환경에서라면 S3를 사용해야 겠지만 테스트이니만큼 ZIP을 올리기로 했다. Runtime은 Go 1.x이다. 핸들러는 실행할 파일의 이름이다. 빌드한 파일을 zip으로 압축했다.
# zip ping.zip ping
  adding: ping (deflated 66%)

이제 테스트를 해보자 오른쪽 상단의 Test버튼을 클릭해서 테스트를 등록 할 수 있다.

 Configuration test envent

 Configuration test envent

Create new test event를 선택해서, 테스트를 만든다. Event name은 pingTest로 했다. 테스트를 하면 아래와 같은 결과를 확인 할 수 있다.

 테스트 결과

 테스트 결과

람다 실행은 CloudWatch로 모니터링 할 수 있다.

 CloudWatch

 CloudWatch

API-GW와 Lambda 연동

API Gateway 를 만들어보자. 이 API Gateway는 "GET /ping"하나만 제공한다.

 API Gateway Start

 API Gateway Start

Get started를 클릭하면 API 설정화면으로 넘어간다.

 API Create

 API Create

3가지 방식으로 만들 수 있다. RegionalEdge optimized 두가지 Endpoint Type이 있다. 특정 지역(리전)에서 서비스하고 싶다면 Regional을 선택하자. 글로벌하게 서비스를 하고 싶다면 Edge optimized를 선택한다. Edge optimized를 선택하면, 각 리전에 알아서 배포를 해준다. 성능은 Regional이 더 좋은걸로 알려져 있으니, Route 53을 비롯한 관리 능력이 있다면 Regional을 선택하는게 유리하다.

 API 생성

 API 생성

 Resource 설정

 Resource 설정

다음 리소스에 대한 Method를 설정한다.

 Test

 Test

이렇게 ping API를 ping 람다에 연결했다. 여기에서 TEST를 수행 할 수도 있다.

 Deploy API

 Deploy API

AWS API Gateway는 stage라는 개념이 있다. Stage는 Alpha-test, Beta, Staging, Operation과 같은 배포 단계를 의미한다. Stage 값을 입력하고 Deploy 버튼을 누르면 Invoke URL이 만들어지고 인터넷에서 호출할 수 있게 된다.

 Stage Deploy

 Stage Deploy

Invoke URL로 테스트를 해보자.
# curl https://api-id.execute-api.ap-northeast-2.amazonaws.com/alpha/ping -i
HTTP/1.1 200 OK
Date: Sat, 31 Mar 2018 07:28:24 GMT
Content-Type: application/json
Content-Length: 4
Connection: keep-alive
x-amzn-RequestId: 18b77044-34b5-11e8-8e3e-1f37b3e8c6c0
x-amz-apigw-id: EmXHzEfboE0FgGQ=
X-Amzn-Trace-Id: sampled=0;root=1-5abf3898-52a9a658c2d01b0d0657714e

{"statusCode":200,"headers":null,"body":"pong"}

SAM Local Lambda 테스트 프레임워크

AWS SAM이라고 하는 로컬기반 서버리스 애플리케이션 테스트 및 개발도구가 있다. S3, DynamoDB, Kinesis, SES 뿐만 아니라 AWS API Gateway까지 시뮬레이션 할 수 있다. 이거 사용해봐야 겠다.

glide로 프로젝트 관리

Glide를 이용한 Go 패키지 관리. Makefile과 잘 엮어서 개발하면 쓸만하겠다.

서비스 개발 & 배포 프로세스

 서비스 배포 프로세스

개발한 테스트하고 Git에 올린다. 젠킨스는 코드를 빌드하고 테스트 한후, s3의 적당한 스테이지에 업로드한다. aws cli를 이용해서 s3에 있는 파일로 부터 람다를 생성한다. 이 후에 aws cli를 이용 api gateway를 람다에 연결해 주면 된다.

참고