본문 바로가기
Database

데이터베이스의 꽃, 샤딩(Sharding)

by !!e!! 2021. 11. 17.

이전에 사내의 한 도메인에서 사용하는 DB 용량의 86% 정도를 사용함에 따라 성능 저하가 발생하기 시작했다. 그래서 샤딩 도입을 고려하게 되었고 이에 대한 세미나를 들은적이 있었다. 당시 기억으로는 샤딩을 도입전에 것이 고려해야할 것도 많고, 성능 향상도 크게 기대하기 어려워 샤딩 도입을 신중히 해야한다는 결론이었다. 이번에는 샤딩을 고려하기까지의 과정, 화려한 샤딩 기술과 한계가 무엇인지 정리해보도록 하겠다.

 

샤딩은 DB 클러스터링(동기 복제방식)과 리플리케이션(비동기 복제방식)에 뒤이어 서비스의 전성기~성숙기 시기에 고려하게되는 Scale-out 솔루션이다.



DB 관점에서의 서비스 성장 과정

 

single_storage



초기의 서비스는 규모도 작고 트래픽도 많지 않기 때문에 단일 DB로 구성할 수도 있다. 하지만 서비스 초기에는 사용자들과 신뢰를 쌓게 되는 시기이기도 하기 때문에, 데이터 유실과 무중단 서비스(고가용성)를 위한 최소한의 대비를 하는것이 좋다. 그래서 서비스 초기이더라도 대부분 DB는 클러스터링(이중화)으로 구성하게 된다.


 

cluster



DB 트랜잭션은 ACID를 만족해야하기 때문에 데이터가 영속적으로 보관되어야 하고, 필연적으로 디스크에 쓰고 읽는 행위를 하게 된다. 디스크 처리 속도는 애플리케이션이 수행되는 CPU와 메모리 처리 속도보다 현저하게 느리기 때문에 DB와 애플리케이션 사이에서 구조적으로 병목이 생길수 밖에 없다.

이때 서비스에 트래픽이 많아지기 시작하면 DB에 대한 접근도 증가하게 되고 DB 접근에서 발생하는 병목에 의해 보다 빠른 서비스를 제공하기 어려워진다.


cache



이를 해결하기 위해 우선적으로 캐시를 도입하게 된다. 메모리에서 동작하는 캐시는 디스크 보다는 월등히 빠르기 때문에 상당수의 경우 캐시만으로도 서비스 트래픽을 충분히 커버할수있다.


core_to_disk



하지만 캐시는 접근시 매번 바뀌는 데이터이거나 데이터 양이 매우 많은 경우에는 큰 효과를 보지 못한다. 또한 캐시 데이터에 의미에는 유실될 가능성을 내포하고 있기 때문에 DB를 대체할 수도 없다. 캐시로도 수많은 트래픽을 해결하기 어려운 경우에 고려하는 것이 바로 리플리케이션(Replication)이다.

 

replication



리플리케이션은 부하 분산, 백업 등을 위해 DB를 복제해 Master-Slave 구조로 구성하는 Scale-Out 솔루션이다. 앞서 등장한 클러스터링과 같은 동기방식으로 부하분산을 하게되면 데이터 정합성을 보장하고자 각 트랜잭션 내에서 다른 DB와 동기화하기 때문에 또다른 병목이 발생하게 된다.

단계적으로 보았을때 리플리케이션을 고려한다는 것은 결국 수많은 트래픽을 해결하기 위한것이기 때문에 동기방식보다 저지연성에 중점을 둔 비동기 방식이나 반동기 방식을 선호할 수 밖에 없다. 비동기, 반동기 방식은 DB 접근의 대부분이 조회작업이라는 점을 이용하여 메인 DB 에서 쓰기 작업을 하고 복제 DB에서 조회작업을 하도록 부하를 분산하여 수많은 트래픽에 대응하도록 한다.

서비스가 계속해서 성장해서 대규모 서비스가되면 데이터 양 자체가 너무 많아서 읽기, 쓰기 모두 느려지는 경우가 발생한다. 리플리케이션을 통해 읽기 로드를 분산한다고 하더라도 쓰기 같은 경우는 로드가 분산되지 않는다. 이러한 경우에는 어떻게 해야할까?


파티셔닝 (Partitioning = 단편화)

앞서 이야기한것 처럼 서비스가 활발한 전성기를 지나 성숙기가 되는 과정에서는 데이터의 양 자체가 너무 많아 성능이 크게 저하되게 된다. 특히 이 상황에서 수많은 쓰기 트래픽은 리플리케이션으로 해결할 수 없다. 이때 각각의 DB에 데이터 일부분을 나누어 가지도록 분리하여 구성하는데 이것을 파티셔닝(단편화)이라고 한다. (같은 테이블에 대한 데이터를 나누어 각 DB가 가지는 것이 파티셔닝이다)

장점

  • 쿼리의 성능을 향상 시킨다 (부분적으로)
  • 물리적으로 데이터를 분산시켜 전체 데이터 훼손 가능성이 줄어든다 (가용성)
  • 정비 용이성 파티션 단위 데이터 백업 가능하다

단점

  • 테이블간 조인 비용 증가한다
  • 테이블과 인덱스를 별도로 파티셔닝 할 수 없다


파티셔닝 종류

수직 단편화 (Vertical Partitioning)

tdk



영화 [ 더 수어사이드 스쿼드 ] 에 보면 T.D.K 라는 팔을 분리해 움직일 수 있는 능력의 괴상하고 징그러운(?) 캐릭터가 등장한다. 수직 단편화는 T.D.K 라는 캐릭터 처럼 테이블을 유사한 엔티티(팔, 몸과 같은 도메인)끼리 묶어 분류하는 것을 의미한다.



수평 단편화 (Horizontal Partitioning = 샤딩(Sharding))

 

groot



수평 단편화의 경우 [ 가디언즈 오브 갤럭시 ] 시리즈에 등장하는 그루트 처럼 분리(파괴)된 이후에도 이전과 동일한 스키마(형태)를 가지도록 수평적으로 분리하는 것을 의미한다. 즉, 테이블을 동일한 스키마로 각각의 DB에 분리하는 것을 수평 단편화라고 하고 이 수평 단편화가 바로 샤딩이다.




샤딩(sharding)


앞서 이야기한것 처럼 수직 파티셔닝을 샤딩이라고한다. 샤딩은 같은 테이블 스키마를 가진 데이터를 여러 DB로 분산하는 것이기 때문에 운영적인 측면에서 복잡도가 높아지게 된다. 분산된 DB에 어떻게 접근하여 조회할 것인지, 분산된 DB에 어떻게 분산하여 저장할 것인지 크게 2가지로 나누어 생각해봐야한다. 데이터가 고루 분산되지 않거나 특정 DB에 접근하는 빈도가 많아진 다면 또다른 병목을 만들 수 있기 때문에 로드를 균일하게 분산하는것이 핵심이라고 할 수 있다.

샤딩의 종류

Key(Hash) Based Sharding

 

key_based_sharding


  • Shard key를 Hash 함수에 넣어 나오는 값을 기준으로 분할한다
  • Hash 결과가 균등하도록 Hash 함수를 정해야 한다
    • ex) id % 4 -> 0 ~ 3 의 결과값으로 분산

장점

  • 데이터가 균등하게 분산된다

단점

  • 추가 증축을 위해 고비용의 데이터 재분배 작업을 해야한다 (기존 데이터까지 함께 ReSharding 필요)
  • Hash 값으로 분산되기 때문에 공간에 대한 효율은 고려되지 않는다


Range(Dynamic) Sharding

 

range sharding


  • 특정 feature의 범위 별로 분할한다
  • 추가 증축하더라도 기존의 Shard Key 변경 없이 Locator에서 추가하면 된다
  • 범위에 따라 데이터를 나누기에 데이터 분할 방법이 예측 할 수 있는 것이어야 한다
    • ex) 인덱스, 생성 날짜, 우편 번호 등

장점

  • 추가 증축에 데이터 재분배 작업이 필요 없다

단점

  • 데이터가 골고루 분배되지 않기 때문에 노드간 트래픽 불균등 발생한다
  • 데이터 재분배 시 Locator의 Shard Key 테이블에도 동기화해야 한다 (관리포인트 증가)
  • 성능상의 이슈로 캐싱을 하더라도 Locator에 의존해야만 한다 (결국 동기화 과정 필요)

 

 

 

샤딩을 적용하기 전에..


개발, 운영 복잡도가 높아지기 때문에 가능하다면 샤딩을 피하거나 지연시키는 것이 우선이다. 복잡한 쿼리에 큰 제약이 생기기 때문이다. 그래서 샤딩을 적용하기 전에 반드시 다음 사항을 우선적으로 고려해야 한다.


  • (비용적으로 가능한 범위 내에서) 더 좋은 HW 스펙으로 교체 (Scale-Up)
  • 트래픽이 문제인 경우 캐시를 사용하거나 리플리케이션(Replication) 활용
  • 테이블 일부 컬럼을 자주 사용하면 Vertical Partition 고려 (일반적인 경우에는 샤딩이 더 좋은 성능을 보이는 편임)



샤딩을 적용해야 한다면

 

  • 샤딩 키를 이용한 단순한 쿼리만 사용하도록 모델링
  • 샤딩 테이블과 관련없는 쿼리는 일반 Datasource를 사용하여 처리
    • 미지원 쿼리 존재로 복잡한 쿼리 실행 보장 X

 

샤딩은 DB 기술의 꽃이라 불릴 만큼 화려한 기술이라 할수 있지만, 모든 기술이 그러하듯 Trade-Off 가 있다. 샤딩은 Locator 와 동기화해야하는 과정이 필연적으로 발생하게 되어 또 다른 병목이 발생할 수 있다. 또한 조인과 같은 복잡한 쿼리가 발생하는 경우 샤딩 이전 환경의 쿼리보다 느리고 에러 발생 빈도도 높아질 위험이 있다. 그리고 무엇보다도 샤딩은 유지보수, 확장 관점에서도 복잡도가 매우 높아진다.


이번에 샤딩에 대해 학습하면서 느낀것은 생각보다 많은 글에서 샤딩 도입에 대해 회의적으로 이야기 한다는 것이었다. 무조건 샤딩을 도입하기 보다 Scale-Up 할수 있는지, 비즈니스 적으로 해결할 수 있는 지를 먼저 고려하고 샤딩을 도입하더라도 조인이 없는 단순한 경우에 적용할 것을 권하고 있다.


참고링크


Understanding Database Sharding | DigitalOcean
(번역) Database sharding이란? 🔨
Clustering vs Replication vs Sharding
Database의 샤딩(Sharding)이란?