Daylogs/DB

DynamoDB: 고민했던 것들에 대한 정리

ohgyun 2021. 3. 14. 13:51

발생일: 2021.03.14

키워드: DynamoDB, 다이나모디비

문제:

다이나모디비를 써보면서 헷갈렸던 것들, 생각과 달랐거나 고민했던 내용, 중요하다고 생각되는 것들에 대한 정리

 

해결:

 

<비용>

 

핫파티션은 프로비저닝 모드에서만 해당됨

- 과금 체계는 프로비저닝 모드와 온디맨드 모드가 있고

- 프로비저닝 모드

    - 프로비저닝 모드는 RCU와 WCU를 직접 설정하는데, '초당 처리량' 기준임

    - 핫파티션 이슈는 프로비저닝 모드에서만 해당됨

        - 초당 요청이 할당 받은 처리량을 초과하지 않게 하기 위해 설계해야 함

    - 예약 요금은 프로비저닝 모드에서 쓸 RCU,WCU를 미리 사두는 개념

- 온디맨드 모드

    - 사용한 RCU와 WCU 만큼 과금하는 모델

    - 사용한 만큼 과금되기 때문에, 처리량의 한계와 핫파티션 이슈가 없음

    - 더 비쌈. 비용 절감을 위해 서비스가 안정화되면 프로비저닝 모드로 전환하는 게 필요하다고 함

 

파티션 설계를 할 때 중요한 것은 '처리량'의 분산 (프로비저닝 모드만)

- 내가 설정한 처리량을 최대한 활용하는 것이 좋음

- '저장공간'이 아니라 '처리량'이 분산되도록 하는 것이 중요

- 물론, 프로비저닝 모드인 경우에 해당됨

- 설정한 RCU/WCU 는 파티션 별로 골고루 할당됨

    - 예: 100RCU 에 파티션이 5개라면, 각 파티션에 20RCU 씩 분산됨

    - 특정 파티션에 20RCU 요청를 초과하는 요청이 들어오면(핫파티션) 병목이 생기고 전체 테이블에 영향이 감

- 경우에 따라 다르겠지만, 상시 요청이 오는 서비스라면 (온디맨드로 시작하더라도) 결국 비용 절감을 위해 프로비저닝으로 변경해야 할 것 같음. 즉, 고민해두긴 해야 함

 

한 번 요청에 여러 RCU가 소진될 수 있음

- eventual consisten 기준으로 4K 당 0.5RCU 가 소진됨 (즉, 8K 당 1RCU)

- 스캔이나 쿼리로 한 번 읽어올 때 최대 1MB 까지 가능한데, 1MB를 읽어왔다면 1024 / 8 = 128RCU를 소진하는 셈

 

scan() 으로 테이블을 읽어오면 문제가 없을까? 과금 모델에 따라 다름

- 전체 테이블을 scan() 하면서 한 번에 1MB를 읽어왔다면, 128RCU 를 소진함

- 프로비저닝 모드라면,

    - 초당 처리량이 문제가 될 수 있으므로, 적당히 나눠서 요청하는 것이 필요함

    - 예: 100RCU 를 설정해뒀는데, 한 번에 1MB 씩 읽어오면 이미 테이블 처리량을 초과하게 됨.

    - 이럴 땐, 1초에 10RCU(80K)만 쓰게 나누는 식으로 분산

- 온디맨드 모드라면, 걱정 없이 그냥 읽어오면 됨

- 병렬 스캔을 하면(TotalSegments, Segmant 파라미터), 빨리 가져올 수 있음

    - 처리량이 크거나 온디맨드 모드라면(= 돈 걱정이 없다면),

    - 테이블이 커도 세그먼트 수를 늘려서(예: 10만개) 수초 만에 가져올 수 있음

 

Projection 을 해도 비용은 동일함

- 쿼리나 스캔할 때, Projection 을 설정해 특정 속성만 가져오도록 하더라도 RCU 비용은 동일함

- 네트워크 비용이 줄어들지만 뭔가 속은 느낌-_-

 

LSI를 설정하지 않으면 파티션 사이즈를 고민하지 않아도 됨

- 파티션 최대 크기에 대한 문서가 조금 애매하긴 하지만, LSI를 설정하지 않으면 파티션 크기는 고민하지 않아도 되는 듯

- LSI를 설정한 경우, 파티션의 최대 크기가 10GB로 제한됨

- LSI는 대체로 잘 활용하지 않는 것 같음. 리인벤트 강의를 여러 개 들어봤는데, 아무도 LSI의 활용에 대해서는 언급하지 않았음 (GSI를 잘 설계하면 될 듯)

- LSI를 설정하지 않은 상태에서 10GB를 넘으면?

    - 문제 없는 것으로 파악함

    - 명시되어 있진 않은데 내부적으로 처리하지 않을까 예상해봄

    - 파티션 1개의 크기에 한계가 있더라도 정렬키가 명확하니까 처리 자체가 복잡하지 않을 듯

 

 

<싱글 테이블 디자인>

 

싱글 테이블 디자인에서 테이블을 나누는 기준

- (아직 확신이 없지만, 적어도 지금까지는) 전부 싱글 테이블로 해도 괜찮을 것 같음

- 다만, MSA 로 서비스를 나눈다고 가정했을 때 완전 다른 도메인은 별도로 분리해도 좋을 듯

 

싱글 테이블 설계에서 데이터를 가져올 땐, "시간복잡도"를 줄이는 것이 중요

- 스케일이 커지더라도 시간 복잡도를 줄이는 것이 강점

- 복잡한 키 설계를 통해, 여러 타입의 데이터를 한 번에 가져올 수 있는 것이 장점

 

싱글 테이블인데 다른 엔터티를 함께 읽지 않으면 비효율

- 작업하다보니 싱글 테이블의 아이템을 조회할 때, 습관적으로 RDS에서 했던 것처럼 별개로 조회하고 있었음

- 여러 타입의 아이템을 한 번에 가져올 수 있게 GSI를 설계하는 것이 중요할 듯

 

자주 변경되지 않는 데이터는 중복하고 변경될 때 업데이트함

- 참조하는 아이템의 중복을 얼마나 허용해야 할까? (예: 유저 닉네임)

- 빈번하게 참조하는 대상도 중복해야 할까?

- 싱글 테이블의 베스트 프랙티스에서는 바뀌지 않거나(immutable) 자주 변경되지 않으면 중복해서 넣으라고 함

- 여기서 자주는 하루에 1~2번 정도. 발표자는 1천번까지도 괜찮다고 생각한다고 함

- 중복하더라도 스토리지를 조금 더 쓸 뿐이라고. 스토리지는 저렴함.

- 중복 데이터는 스트림과 람다를 활용해서 업데이트 하면 되고, 예전처럼 고통스럽지 않을 거라고 함

- 지금은 1980년대가 아니라면서...

- 참고: AWS re:Invent 2020: Amazon DynamoDB advanced design patterns



반응형