본문 바로가기

취미

AWS DynamoDB, Lambda를 이용한 auto scaling #1

AWS에서 DynamoDB 완벽하게 관리되는 NoSQL Database 원할한 확장성과 빠르고 예측 가능한 성능을 제공한다.

DynamoDB 분산 데이터베이스를 운영하는데 관리 운영 부담을 줄이고 하드웨어 프로비저닝, 샤딩, 소프트웨어 패치 등등 알아서 관리된다.

그리고 AWS Management Console 통해 리소스 사용률과 성능을 모니터링 있다.

외에 모든 데이터가 SSD 저장되고 여러 AWS 가용영역에 자동 복제되어 높은 가용성과 데이터 내구성을 보장한다.

이러한 여러 장점 덕분에 소수의 인원으로 데이터베이스를 관리 운영할 있다.

DynamoDB 과금체계는 프로비저닝된 처리용량과 인덱싱된 데이터,  데이터 스트림에 따라 요금이 부과된다.

2016 12 26 기준으로 처리용량에 따른 요금은 서울리전을 기준으로

  • 쓰기 처리량: $0.007049 쓰기 용량 10단위에 대해 시간당
    (
    시간당 36,000개의 쓰기 작업을 수행할 있는 용량)*
  • 읽기 처리량: $0.007049 읽기 용량 50단위에 대해 시간당
    (
    시간당 180,000개의 Strongly Consistent Read 또는 360,000개의 Eventually Consistent Read 수행할 있는 용량)*

인덱싱된 데이터 스토리지 요금은

  • First 25 GB stored per month is free
  • $0.25 월별 GB(초과분)

데이터 스트림 요금은

  • Every month, the first 2.5 million DynamoDB Streams read request units are free
  • $0.02166 per 100,000 DynamoDB Streams read request units thereafter

아직 트래픽이 많이 생기지 않은 상황에서 가장 요금이 나가는 부분은 프로비저닝된 처리유닛에 따른 과금이였다. GlobalSecondaryIndex 생성하면 거기에 따른 프로비저닝 유닛이 추가되니..

그리고 프로비저닝 유닛은 자동으로 조절되지 않고 사용자가 설정해야 하는데

읽기 유닛을 50 주고 디비를 사용하지 않아도 유닛에 따른 시간당 과금은 적용된다.

그래서 자동으로 프로비저닝된 유닛을 조절할 있는 방법에 대해서 알아보기로 하였다.

첫번째로 찾은 방법은 AWS Blog 나와있는 Dynamic DynamoDB였다.

Cloud Formation template 제공해줘서 구현할 있게 해주었다.

EC2 인스턴스에 Dynamic DynamoDB 설치하고 Auto scale그룹을 묶는 방식이였다.

템플릿을 제공하여 구성하기는 간단했지만 AWS에서 제공하는 DynamoDB 사용하는 장점인 간편한 관리 운영의 장점이 많이 줄어들 같다는 생각을 하여서 구성은 포기하고 다른 방법을 찾아보았다.

두번째 방법으로는 lambda 이용해서 Consumed capacity Units 따라 lambda에서 프로비저닝 처리유닛을 자동으로 조절할 있는 방법을 찾아보았다.

역시 누군가가 Github 오픈소스로 구현해놓았었다.  dynamodb-lambda-autoscale

 

Node.js 이용해서 만들었는데 설치방법과 사용법이 간단해서 적용해보았다.

여러가지 설명이 있지만 간단하게 말하면 Cloud Watch DynamoDB 모니터링 하다가 사용자가 설정해놓은 임계값에 다달하면 알람이 울린다. 알람은 SNS topic으로 전달되고 SNS topic lambda함수를 등록하여 알람 값에 따라서 처리유닛을 조정하고 알람 임계값을 조절하는 방식이다.

일단 npm 설치하고 하라는데로 DynamoDB 대해서 설정도 하고 lambda 함수로 등록했다.

처음 테스트를 해보았는데 요청 증가에 따라서 프로비저닝 유닛수도 같이 증가하였다. 매우 흡족했다.

근데 내가 설정을 잘못한 같아서 그런것 같긴 한데 몇가지 문제가 발생했다.

첫번째로 Global Secondaryindex 처리유닛이 증가 하지 않았다. GlobalSecondaryIndex에서 알람이 울리면 해당 테이블의 처리유닛이 올라가고 알람값은 GlobalSecondaryIndex 알람값이 변경되어서 꼬이고 꼬였다.

두번째로 처리유닛이 감소되는 기능이 없었다(아마 내가 못한걸수도)

 

그래서 이럴바에 내가 직접 lambda 함수를 만들어보기로 했다.

lambda 함수에서 지원하는 언어는 C#, JAVA 8, Node.js 4.3, Edge Node.js 4.3, Python 2.7 지원한다고 되어있다.

그중에서 가장 익숙한 python 2.7 이용해서 구현해보기로 했다.

최근(?) 나름 최근에 Python AWS SDK boto3 공개되었기 때문에 Boto3 사용해서 구현해보기로 했다.

AWS 에서는 DynamoDB 처리유닛 감소를 테이블 하루에 4번으로 제한을 두고있다.

그래서 처리유닛 증가는 기존 위에 언급된 Node.js 이용해 만든 dynamodb-lambda-autoscale 소스를 보고 기능을 Boto3 그대로 구현하면서 GlobalSecondaryIndex 처리유닛까지 증가할수 있도록 수정하고

처리유닛 감소는 특정시간마다 Event Scheduler 발생하여 lambda 실행하도록 하고 Boto3 이용해 설정한 리전에 존재하는 모든 테이블과 테이블에 존재하는 GlobalSecondaryIndex 대해서 프로비저닝된 유닛과 Consumed capacity Units(소비중인 유닛?) 가져와서 적정한 프로비저닝 유닛수로 변경하는 코드를 짯다.

간단하게 만들기 위해 복잡한 설정 필요없이 알람이 울린 테이블에 대해서 30% 유닛을 증가시키고

감소할때는 현재 사용량의 30% 가량 여유를 두고 프로비저닝 유닛을 조절하거나 사용량이 없을경우 최소값으로 설정되게 하였다.

Node.js 구현된 파일을 lambda 업로드할 때는 용량이 1.7메가 가량이였는데 python 소스코드파일은 파일 하나 4kb이다.

Python 에서 임포트 하는 json, boto3, math 라이브러리는 같이 올리지 않고 그냥 임포트해서 사용하면 된다.

 

먼저 유닛 증가 함수를 만들어보겠다.

먼저 AWS managment console에서 lambda 들어가서 Create a Lambda function 클릭한다.

 

 

 

그리고 SNS-message-python 클릭한다. 사실 이건 크게 중요하지 않다. 시작 코드를 쳐주는 정도이다.

트리거에서 SNS 선택하고 dynamodb topic 선택한다. 아마 DynamoDB에서 테이블을 생성하면 자동으로 생성되는 Topic 것이다. 없으면 SNS 가서 Topic 먼저 생성하고 알람을 해당 Topic으로 가도록하면 될것이다. Enable trigger 체크하고 Next!

 

 

 

 

 

대충 이름과 설명을 적고 Runtime Python 2.7 선택하고 Code entry type Edit code inline 선택하여 여기에 직접 코딩하겠다.

기본적인 코드가 있는데 lambda_handler aws에서 실행하는 함수이다. main이라고 보면됨

event 여러 정보들이 있고 SNS 메세지 변수가 자동으로 생성되어 있다.

message json뷰어로 살펴보았다. 알람이 발생한 테이블이름과 GlobalsSecondaryIndex 인덱스이름도 있고 알람이 어떤 Metric에서 발생했는지 등에 대한 여러 정보들이 담겨져 있다.

 

아래 설정에는 먼저 role 설정해줘야한다. 없으면 만들면 되고 있으면 사용하면된다.

나는 DynamoDB, cloudwatch, SNS Access 있는 권한을 주었다.

그리고 메모리와 Timeout시간을 설정해야 하는데 메모리는 최솟값 그대로 두고 Timeout 10 정도 주었다 넉넉하게

DLQ Resource lambda함수에서 처리 실패하면 SQS 또는 SNS 보낼 있는데 지금은 설정하지 않았다.

DynamoDB 대한 lambda함수이므로 VPC 설정하지 않고 넘어갔다.

 

 

 

먼저 message 파싱할 사용하는 json AWS python sdk boto3 그리고 변경할 처리량을 계산할 math 라이브러리를 임포트한다.

그리고 30% 유닛이 증가, 새로운 알람은 프로비저닝 유닛수의 80% 도달하면 알람이 울리도록 변수를 잡는다.

그리고 lambda_handler함수 위에 2개의 함수를 만들었다. 하나는 update_table 인자값으로 table객체와 변경할 유닛수, GlobalSecondaryIndex 경우 인덱스 이름을 넣어서 해당 테이블의 처리량을 업데이트 한다.

 

 

다른 하나는 알람의 임계값을 변경해주는 함수이다. 성공적으로 table 업데이트 되었다면 새로운 알람 임계값으로 변경한다.

watch 객체와 어떤 테이블인지 알기위해 SNS Topic 에서 받은 message 변수에 있던 dimension값을 집어넣고 어떤 알람이 울렸는지 알기위해 알람 Metric 새로 업데이트 테이블의 유닛값을 집어 넣는다.

alarm 객체를 가져올 dimension, Metric 인자를 집어넣어서 찾아 올수 있는데 SNS Topic에서 받은 message에는 dimension name value 앞글자가 소문자인데 알람을 가져올땐 대문자만 인식해서 변경해주었다.

알람 객체를 가져왔으면 새로운 알람을 추가하는데 기존의 그대로 유지하면서 Threshold 값만 변경해서 추가하면 기존의 알람을 대체하게 된다.

lambda_handler에서는 message 테이블의 객체를 가져와서 프로비저닝된 유닛을 가져와서  30% 증가된 값으로 테이블을 업데이트함수와 알람 업데이트 함수를 실행한다.

'취미' 카테고리의 다른 글

AWS DynamoDB, Lambda를 이용한 auto scaling #2  (2) 2017.02.20
JWT(JSON Web Token)  (0) 2017.02.20
아이폰 MAC address 랜덤화  (3) 2016.04.09
802.11 Management Frame Format  (0) 2016.02.15
파이썬 scapy로 AP 만들기 - WEP 구현  (0) 2016.02.15