
회사에서 주로 No-SQL 데이터 베이스인 DynamoDB를 이용중이다.
실무에서 자주 봤는데 생소했던 개념 공부를 해보자.
1. 인덱스
2. 쓰로틀링
공식 문서를 참고했다. 너무 추상적인 내용이라 헷갈렸다.
DynamoDB
비 관계형 데이터 베이스 시스템에서 데이터 조회,저장,수정,삭제 등
정형화 되지 않은 구조 사용
대규모 대용량 동시 서비스가 필요한 곳에서 사용
- 입력시 필드만 추가하면 됨
- 조회방법에는 변화가 없음
작동 방식
- 모든 규모에서 고성능 애플리케이션을 실행하도록 설계된 no-sql 데이터베이스
- 보안 지속적인 백업, 자동화된 다중 리전 복제, 인메모리 캐시 및 내보내기 도구
- Serverless 가 가장 큰 장점
- 테이블과 각 row는 파티션이라는 공간에서 구성된다. 이 공간을 검색하는 가상의 키가 파티션 키.
- 해시 구조로 파티션 키를 해싱해서 저장함.
인덱스
최대 20개의 글로벌 인덱스, 5개의 로컬 인덱스를 보유할 수 있다.
1. 로컬 인덱스(LSI)
- 가장 대표적인 예시가 정렬 키
- 개별 파티션 키 값 마다 크기 제한이 (10GB) 있음
- hot key를 방지하기 위해 사용함. 동일한 파티션 키라도 정렬키를 같이 선언하면 트래픽이 분산 될테니깐 마치 복합키
- 같이 저장될 항목을 지정할 수 있음(속성 프로젝션)
- KEYS_ONLY (인덱스와 같은 Key만)
- INCLUDE (같이 포함될 항목 지정 name,phone 등등)
- ALL (모든 정보)
로컬 인덱스를 사용할 때는 프로비저닝된 처리량과 스토리지 비용을 고려해야 한다.
로컬 인덱스인 걍우 프로젝션 되었기 때문에 프로비저닝된 처리량을 추가로 소비하지 않는다.
따라서 자주 읽는 속성이라면 인덱스에 같이 프로젝션 시킨다.
인덱스가 작을 수록 비용이 절감된다.
2. 글로벌 보조 인덱스(GSI)
- Global secondary index
- 파티션 키와 정렬키가 아니라 별도의 테이블에 저장되는 인덱스
- 글로벌 인덱스 테이블에는 파티션키, 보조 인덱스가 들어감
- 같이 저장될 항목을 지정할 수 있음(속성 프로젝션)
- KEYS_ONLY (인덱스와 같은 Key만)
- INCLUDE (같이 포함될 항목 지정 name,phone 등등)
- ALL (모든 정보)
- Query, Scan 에 사용 가능, BatchGetItem에는 사용 불가
예시로 다음과 같은 키로 구성한 기본 테이블이 있다고 치자
userId : 파티션 키
nickName : 글로벌 인덱스 , 속성 프로젝션 - KEYS_ONLY
createdAt : 정렬키
속성 | userId | name | phone | nickName | createdAt |
파티션 키 | 글로벌 인덱스 | 정렬 키 |
그러면 KEYS_ONLY의 경우 글로벌 인덱스의 테이블은 다음과 같을 것이다.
nickName | userId | createdAt |
글로벌 인덱스 | 파티션 키 | 정렬키 |
ALL의 경우는 모든 속성을 가지게 될 것이다.
근데 궁금증이 있었다.
1. nickName 인덱스에 INCLUDE(phone) 속성을 가지고 있다면, name같이 포함하지 않은 데이터는 조회되지 않나?
A : 포함 안된다.
실제 다음과 같이 조회를 하면
const AWS = require('aws-sdk');
AWS.config.update({ region: 'ap-northeast-1' });
const dynamodb = new AWS.DynamoDB();
async function get() {
const data = await dynamodb
.query({
TableName: 'test',
KeyConditionExpression: '#n = :nickName',
ExpressionAttributeNames: { '#n': 'nickName' },
ExpressionAttributeValues: { ':n': { S: '테스트' } },
IndexName: 'nickName-index',
})
.promise();
console.log(data.Items[0]);
}
get();
{
Items: [
{
nickname: [Object], //글로벌 인덱스
phone: [Object], // INCLUDE 속성
userId: [Object], //파티션키
}
],
Count: 1,
ScannedCount: 1
}
INCLUDE 외의 속성은 포함 되지 않는다.
2. 글로벌 인덱스 테이블과 기본 테이블의 데이터 동기화?
- 공식 문서를 보면, 밀리초 수준으로 비동기적으로 업데이트가 된다.
- 간혹 장애 발생으로 지연 발생할 수 있음. -> 최신이 아닌 결과를 반환할 수도 있음.
- 글로벌 인덱스가 있으면 쓰기 비용이 증가됨
- 모든 기본 테이블의 용량을 상속
글로벌 인덱스를 쓰면 따로 저장이 되는 것이기 떄문에 용량적 측면에서 비용이 많이 발생 가능
쓰로틀 (Throttling)
서비스 리소스의 사용이 제한되거나 제어되는 것을 말함.
DynamoDB와 쓰로틀
DynamoDB는 여러 파티션으로 구성되어 있으며, 각 파티션은 정해진 읽기 용량(Read Capacity)과 쓰기 용량(Write Capacity)을 가지고 있음.
예를 들어, DynamoDB의 읽기 용량이 50이고 두 개의 파티션으로 나뉘어져 있다면 각 파티션은 25씩 나눠 가짐. 이 용량을 초과해서 읽거나 쓰려 하면 쓰로틀링이 발생함.
ProvisionedThroughputExceededException
예외가 발생함.
온디맨드 모드 vs 프로비저닝 모드
- 온디맨드 모드: 사용한 만큼 비용이 발생함. 갑작스러운 트래픽 증가에 대비할 수 있음.
- 프로비저닝 모드: 미리 예약한 용량만큼 사용함. 갑작스러운 트래픽 증가 시 제한이 발생함.
이 제한을 쓰로틀링(throttling)이라고 함. 각 모드별로 공식 문서에서 자세히 설명하고 있음.
프로비저닝 모드
기본적으로 미리 예약한 프로비저닝 용량(RCU, WCU)을 초과하면 쓰로틀링이 발생함.
1. 예약된 용량이 있는데 쓰로틀링이 발생함
DynamoDB 테이블에 충분한 프로비저닝 용량이 있지만 요청이 쓰로틀링될 수 있음.
가능한 상황:
- DynamoDB는 CloudWatch로 분 단위로 리포팅하지만 초 단위로 제한을 적용함. 분당 많은 요청이 들어오면 쓰로틀링이 발생할 수 있음.
- 예: 60 WCU(Write Capacity)는 1분에 3600번 쓰기 요청을 처리할 수 있지만, 1초에 3500번 요청이 들어오면 남은 59초 동안 쓰로틀링이 발생함.
해결 방법:
- Jitters나 Backoff를 추가해서 모니터링 가능
2. 오토 스케일링이 가능한데 쓰로틀링이 발생함
가능한 상황:
- 스파이크 트래픽으로 인해 발생함.
- 오토스케일링이 되는데 몇 분이 걸림. 이 업데이트 동안 이전 프로비저닝 용량은 유지되기 때문에 이를 초과하는 모든 요청이 쓰로틀링됨.
3. Hot Key 발생
파티션 키의 카디널리티가 낮아 몇 개의 파티션에만 요청이 집중될 수 있음. 결과적으로 핫 파티션이 초당 3000 RCU 또는 10000 WCU의 파티션 한도를 초과하면 제한이 발생할 수 있음.
진단 도구:
- CCI 사용
온디맨드 모드
갑작스러운 트래픽 증가에 대비할 수 있으며, 자동으로 조정됨. 하지만 100% 대비는 아님
- CloudWatch: 각 테이블의 읽기 및 쓰기 요청을 모니터링함.
- 요청 분산: 핫 파티션 키가 분산되도록 요청을 분산시킴.
- 핫 키 이슈 해결: 위에서 말한 이슈와 동일
인덱스와 쓰로틀링 관련 경험한 이슈
회사에서 인덱스와 쓰로틀링을 경험했었다.
- 인덱스 비용 증가:
- 인덱스가 모든 데이터를 프로젝션하여 읽고 쓸 때 비용이 증가했음.
- 인덱스 프로젝션 속성을
KEYS_ONLY
로 설정하여 파티션 키만 사용하도록 했음. - 운영 서버를 모니터링하여 변경했음.
- 쓰로틀링:
- 특정 피크에만 쓰로틀링이 발생하여 Redis로 이관하여 정보를 저장했음.
- AWS DynamoDB의 비용을 늘려 용량을 확보하는 대신, 다른 인프라를 고려한 점이 인상 깊었다.