대메뉴 바로가기 본문 바로가기

데이터 기술 자료

데이터 기술 자료 상세보기
제목 서버 없는 클라우드 프로그래밍 도전기 - 자바와 스칼라로 AWS Lambda 함수 만들기
등록일 조회수 5930
첨부파일  

서버 없는 클라우드 프로그래밍 도전기

자바와 스칼라로 AWS Lambda 함수 만들기



이 글에서는 AWS Lambda를 지원하는 두 언어 중 가장 범용적이고 많은 개발자 커뮤니티를 가지고 있는 자바 언어로 람다 함수를 어떻게 만드는지 살펴본다. 기존의 자바 IDE와 AWS 커맨드라인 인터페이스(Command Line Interface, CLI)를 통해 민첩하고 빠른 자바 기반의 람다 함수 배포 방법도 알아본다.



시작하기에 앞서 먼저 간단하게 자바로 람다 함수를 하나를 만들어 보자. 첫 회에서 다뤘듯 aws-lambda-java-core라는 함수 핸들러, 콘텍스트 객체 그리고 aws-lambda-java-events라는 AWS 리소스의 이벤트를 정의하는 두 가지 라이브러리를 사용해야 한다.



<리스트 1> 간단한 로그를 출력하는 자바 기반 람다 함수 package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; public class Hello { public String myHandler(int myCount, Context context) { LambdaLogger logger = context.getLogger(); logger.log("received : " + myCount); return String.valueOf(myCount); } }



자바 람다 함수의 프로그래밍 모델은 크게 두 가지다. 객체를 입출력하는 높은 수준의 모델(Java POJO나 프리미티브 입출력 형식 사용 가능)이 대표적이다. POJO를 사용하지 않거나 Lambda 시리얼리제이션 모델이 요구를 충족하지 않는 경우 스트림 모델을 쓸 수 있다. 자바 IDE로 프로젝트와 코드를 생성했다면, 람다 함수 배포는 .jar 혹은 .zip으로 만들어 하면 된다. 익숙한 빌드 및 패키징 도구나 이클립스(Eclipse)나 메이븐(Maven)을 이용해도 무방하다. 그렇게 만든 패키지는 <그림 1>처럼 람다 함수를 업로드해 바로 실행해 볼 수 있다.



이제 화면에서가 아니라 여러 AWS 서비스를 커맨드라인에서 관리하고 스크립트를 통해 자동화할 수 있는 AWS CLI로 람다 함수를 실행해 보자. AWS CLI는 파이썬(Python) 2.6.5 이상에서 pip를 통해 설치할 수 있다. 간단하고 직관적인 명령어 방식으로 AWS 서비스 대부분을 손쉽게 제어 가능하다.



<리스트 2> AWS CLI 설치 및 실행 $ pip install awscli $ aws help $ aws s3 cp ./ s3://mybucket/file --recursive upload: ./file1.txt to s3://mybucket/file/file1.txt upload: ./sub/file1.txt to s3://mybucket/file/sub/file1.txt



<리스트 3>처럼 AWS CLI로 자바 함수를 만들 수 있다. 먼저 제공할 리전 및 함수 이름 그리고 올릴 자바 패키지 등을 지정한다. AWS 역할(Role)에는 람다 함수의 실행 권한을 지정해야 하는데, 기존에 만들어진 것을 사용해도 된다. Handler에는 자바 코드에 있는 클래스 명을 넣자.



<리스트 3> AWS CLI로 자바 기반 람다 함수 배포하기 $ aws lambda create-function --region us-west-2 --function-name lambda-function-in-java --zip-file fileb://deployment-package (zip or jar) path --role arn:aws:iam::account-id:role/lambda_basic_execution --handler example.Hello::myHandler --runtime java8 --timeout 15 --memory-size 512 < 실행 결과> { "FunctionName": "getting-started-lambda-function-in-java", "CodeSize": 22617, "MemorySize": 512, "FunctionArn": "arn:aws:lambda:us-west-2:account-id:function:lambda-function-in-java", "Handler": "example.Hello::handler", "Role": "arn:aws:iam::account-id:role/lambda_basic_execution", "Timeout": 15, "LastModified": "2015-05-30T23:15:26.716+0000", "Runtime": "java8", "Description": "" }



지금부터는 CLI를 통해 람다 함수를 테스트해 보자. AWS 관리 콘솔에서 샘플 데이터를 입력하면 테스트 가능하지만, CLI를 통해서도 빠르고 쉽게 할 수 있다. <리스트 4> 명령어로 123이라는 숫자를 입력하면 로그에 그대로 출력된다. AWS CLI를 사용하는 람다 함수 실행 및 테스트에는 자바 패키지뿐만 아니라 Node.js 코드도 그대로 이용 가능하다.



<리스트 4> AWS CLI로 람다 함수 테스트하기 aws lambda invoke --region us-west-2 --function-name lambda-function-in-java --payload 123 --invocation-type RequestResponse /tmp/response



람다 함수로 아마존 다이나모DB 이벤트 처리하기

지금부터는 람다 함수를 통해 AWS의 매니지드 NoSQL 서비스 ‘다이나모DB(Amazon DynamoDB)’에서 오는 이벤트들을 처리해 보자. DynamoDB는 데이터가 추가, 삭제, 업데이트 등의 모든 이벤트를 스트림(Streams)라는 방식을 통해 모니터링 할 수 있다. 새로운 데이터가 추가됐을 때 람다 함수를 실행하고, AWS Cloud Watch라는 로그 서비스에 데이터를 넘겨주는 간단한 클라우드 기반 코드를 작성할 수 있다.



<리스트 5> 자바로 다이나모DB 스트림을 처리하는 람다 함수 만들기 package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.DynamodbEvent; import com.amazonaws.services.lambda.runtime.events.DynamodbEvent.DynamodbStreamRecord; public class DDBEventProcessor implements RequestHandler< DynamodbEvent, String> { public String handleRequest(DynamodbEvent ddbEvent, Context context) { LambdaLogger logger = context.getLogger(); for (DynamodbStreamRecord record : ddbEvent.getRecords()){ logger.log(record.getEventID() + " "); logger.log(record.getEventName() + " "); logger.log(record.getDynamodb().toString() + " "); } return "Successfully processed " + ddbEvent.getRecords().size() + " records."; } }



<리스트 5>의 handleRequest는 람다 함수를 실행하고 이벤트 데이터를 제공한다. 이를 위해 미리 선언한 DynamodbEvent를 사용해 aws-lambda-java-events 클래스를 정의한다. 만약 핸들러가 정상적으로 작동하면 람다 함수는 입력 레코드의 배치를 실행해 스트림에 새로운 레코드가 있는지 읽기 시작한다. 예외 처리가 되면 레코드 입력 배치가 실행되지 않고 다시 한번 실행하게 된다.

람다 함수가 실행된 후에는 다이나모DB에 새로 들어온 이벤트와 레코드를 읽어 Amazon CloudWatch 로그로 남긴다. 같은 로그가 관리 콘솔의 Execution logs에도 보인다. 자바 코드로 람다 함수를 만들려면 앞의 예제를 기반으로 작성하면 되는데, 패키지에 aws-lambda-java-core와 aws-lambda-java-events 라이브러리를 포함시켜야 한다. 또한 example.DDBEventProcessor (package.class) 방식으로 핸들러를 지정하고, DynamoDB event stream role을 추가해야 한다.

마지막으로 사용할 다이나모DB 테이블의 스트림 기능을 켜고, 다이나모DB의 이벤트에 람다 함수를 추가한다. 이렇게 되면 람다 함수의 이벤트 소스에서 다이나모DB 테이블을 확인할 수 있다.







스칼라로 람다 함수 만들기

AWS 람다 함수는 자바를 지원하기 때문에 JVM(Java Virtual Machine) 기반의 언어 역시 이용 가능하다. 따라서 스칼라(Scala)를 통해 손쉽게 람다 함수를 만들 수 있다. 스칼라에 익숙하지 않더라도 간단한 샘플 코드를 통해 어떻게 구동되는지 쉽게 이해할 수 있을 것이다. 먼저 스칼라 빌드 도구인 sbt를 다운로드하자. 맥에서는 $ brew install sbt 또는 $ port install sbt를 입력해 설치하면 된다. 윈도우나 리눅스라면 JVM과 sbt-launch.jar를 통해 실행 가능하다.

Sbt를 실행하면 스칼라 프로젝트가 자동으로 만들어진다. Project 디렉토리 하위에 srcmainscalaexample 구조인데, Project 디렉토리 밑에 plugins.sbt를 만들고, addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")라는 내용을 입력하자. 그리고 src 디렉토리의 build.sbt에는 <리스트 6>을 입력한다.



<리스트 6> 스칼라 함수 빌드 설정하기 javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-Xlint") lazy val root = (project in file(".")). settings( name := "lambda-demo", version := "1.0", scalaVersion := "2.11.4", retrieveManaged := true, libraryDependencies += "com.amazonaws" % "aws-lambda-java-core" % "1.0.0", libraryDependencies += "com.amazonaws" % "aws-lambda-java-events" % "1.0.0" ) mergeStrategy in assembly < { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } }



자! 이제 스칼라로 람다 함수를 만들 준비가 모두 끝났다. 우리가 만들 람다 함수는 AWS의 객체 스토리지인 S3(Simple Storage Service)에서 객체 이름을 받아 오는 간단한 기능을 수행한다. S3 버킷에 담긴 파일의 목록을 받아오는 간단한 동작 등 원하는 기능을 추가하면 S3 관리 기능을 만들 수 있을 것이다. 지금부터 <리스트 7> 코드를 작성해 src/main/scala/exampleadd/main.scala를 만들어 보자.



<리스트 7> 스칼라 함수 빌드 설정 package example; import scala.collection.JavaConverters._ import java.net.URLDecoder import com.amazonaws.services.lambda.runtime.events.S3Event class Main { def decodeS3Key(key: String): String = URLDecoder.decode(key.replace("+", " "), "utf-8") def getSourceBuckets(event: S3Event): java.util.List[String] = { val result = event.getRecords.asScala.map(record => decodeS3Key(record.getS3.getObject.getKey)).asJava println(result) return result } }



작성된 코드를 sbt를 통해 ‘assembly’, ‘compile’ 명령을 실행하면, targetscala-2.11lambda-demo-assembly-1.0.jar 파일이 만들어진다. 실행 환경에 따라 조금 다를 수는 있으니 참고하자. 이렇게 만들어진 jar 파일을 이제껏 해왔듯 관리 콘솔 혹은 AWS CLI 도구를 이용해서 업로드하고 테스트한다.



핸들러에 example.Main::getSourceBuckets를 입력해야 함에 유의하자. 만들어진 람다 함수를 실행하려면 Amazon S3에 이미지를 올리는 이벤트 발생 시 람다 함수가 실행된 결과를 CloudWatch 로그를 통해 보여준다.



이제 스칼라 샘플 코드를 확장해 다양한 이벤트 기반의 클라우드 기능을 동작시켜보자. AWS 자원을 용이하게 제어할 수 있을 것이다.



서버 없는 마이크로 서비스 만들기

지금까지 살펴본 람다 함수는 AWS 자원의 이벤트를 감지해 다양한 기능을 수행한다. 굳이 서버가 필요하지 않는 단순한 기능들을 더 빠르게 구현할 수 있다. 예컨대 S3에 이미지가 업로드됐을 때 썸네일을 만드는 함수를 생각해 보자. 이렇게 구현하면 기존에 서버를 만들어 업로드를 하고 썸네일을 생성한 후 S3에 저장하는 애플리케이션 기능은 더 이상 필요 없을 것이다. 따라서 부가적인 기능보다는 좀 더 핵심적인 기능을 개발에 더 많은 노력을 기울일 수 있다.

하지만 AWS 자원의 변화에 따른 동작뿐 아니라 모든 외부 요청 즉, API 호출에 직접 람다 함수를 실행할 수 있다면 그 가능성은 훨씬 커질 것이다. 이를 보완하기 위해 2015년 7월에 AWS는 Amazon API Gateway라는 서비스를 내놨다. API Gateway는 현대적인 애플리케이션에서 보편적으로 이용하고 있는 REST API로 동작하며 API 프록시, 캐싱 및 API 키 인증, 보안 그리고 SDK 자동 생성 등 다양한 기능을 제공하는 API 백엔드 서비스다.

API Gateway에서는 외부 REST 호출에 따라 여러 기능을 동작시킬 수 있다. 그 중 하나가 바로 람다 함수다. 따라서 사용자가 웹 사이트에서 데이터를 생성 및 삭제, 변경하기 위해 API 호출을 하는 경우에도 람다 함수를 실행할 수 있다.



<그림 5>는 SquirrelBin 샘플 구성도다. 웹사이트나 모바일 앱에서의 API 호출에 따라 다이나모DB에 직접 데이터 입출력을 가능한 클라우드 아키텍처로 설계돼 있다. 이렇게 되면 굳이 서버 인프라를 설치하고 운영하는 비용 부담 없이 밀리세컨드 단위의 과금 체계로 애플리케이션을 비용 효율적으로 실행할 수 있다.

API Gateway와 연동한 간단한 샘플 코드를 운영해 보고 싶다면, AWS Lambda 관리 콘솔에 있는 다양한 예제 중 microservices -http-endpoint를 실행해 보자. 지금까지 3회에 걸쳐 AWS 람다 함수에 대해 살펴봤다. AWS 람다 함수의 기본적인 소개부터 모바일 앱에서의 연동, 자바 함수 생성, 서버 없는 클라우드 서비스 등을 알아봤다. AWS Lambda가 서비스된지는 아직 1년이 채 되지 않았다. 계속되고 있는 기능 추가로 서비스 혁신을 가져오고 있다. 앞으로 AWS Lambda는 클라우드 기반의 서버 없는 애플리케이션 개발이 가능한지에 대한 시금석이 될 것이다.



출처 : 마이크로소프트웨어 10월호

제공 : 데이터 전문가 지식포털 DBguide.net