[DB] 알아두면 좋은 데이터베이스 설계 지식 (파티셔닝, 레플리케이션, 클러스터링)

2022. 10. 13. 14:34[ Basic ]/# 데이터베이스

DB Partitioning

- 서비스의 크기가 점점 커지고 데이터의 규모 또한 커지면서, DB 시스템의 용량(storage)의 한계와 성능(performance)의 저하를 유발하게 되었다.
- 이에 대한 해결책으로 테이블을 파티션이라는 단위로 나눠어 관리하게 되었으며 이러한 과정을 DB 파티셔닝이라고 한다.

- 이러한 관점에서 보았을 때 데이터베이스 정규화(Normalization)도 일종의 파티셔닝으로 볼 수 있지만 파티셔닝은 성능 향상을 목적으로 하며 정규화는 중복된 데이터 방지 및 이상현상(Anomaly) 예방을 목적으로 한다. 

 

 

1. Vertical Partitioning (수직 파티셔닝)

말 그대로 테이블의 컬럼을 기준으로 수직으로 파티셔닝 하는 것을 의미한다.

 

예시

게시글 데이터를 의미하는 article 테이블이 아래와 같이 설계되었다고 가정하자.

 

[article table]

id title writer_id created_at view_cnt comment_cnt content

 

여기서 수직 파티셔닝이 필요한 부분을 정리해 보자면 아래와 같이 3가지 경우가 있을 것이다. 물론 그 이유는 더 다양할 수도 있다.

 

1) 특정 컬럼의 데이터 용량이 클 경우

- 데이터들은 HDD 또는 SSD에 저장되기 때문에 무거운 용량의 데이터를 조회하는 것은 부담스러운 disk I/O 작업을 초래한다. 일반적으로 content의 용량은 어느 정도 크게 설정되기 때문에(또는 그런 가정이 있다고 하면) content 컬럼을 따로 분리하여 설계하는 것이 disk I/O에 대한 부담을 줄일 수 있을 것이다.

 

2) 컬럼의 사용 빈도에 따라

- 비즈니스 요구사항에 따라 다르겠지만, 만약 게시글 '목록'을 조회하는 쿼리에 content가 필요하지 않다고 가정해 보자. 쉽게 말하면 게시글 목록 조회 API에 content에 대한 응답은 필요하지 않은 경우이다. content는 게시글 상세보기 쿼리 또는 API에만 포함되면 된다. 이 경우에도 마찬가지로 굳이 용량이 큰 content를 쿼리 결과에 포함시키는 것은 좋지 않을 것이다. 즉, 컬럼 조회 필요성의 빈도에 의해서도 수직 파티셔닝이 필요할 수도 있다.

- 참고로 select 문의 조회할 컬럼 목록에 content를 명시하지 않더라도 content 컬럼이 article 테이블에 포함되면 같은 disk I/O에 포함된다. 즉, 'select id, title, writer_id from article;'과 같은 쿼리처럼 select 할 컬럼에 content가 없더라도 disk I/O 발생시점에는 우선 해당 row를 모두 가져온 뒤 필요한 데이터만 filtering 한다.

 

3) 특정 컬럼이 민감한 데이터를 의미할 경우

- 만약 content 컬럼이 민감한 데이터를 포함하여 특정 DBMS 유저에게만 접근 권한을 부여(grant 쿼리)한다고 가정해 보면 테이블 별 접근 권한을 설정하기 위해 해당 민감 데이터를 포함하는 컬럼에 수직 파티셔닝을 적용할 수도 있다.

 

 

아무튼 위와 같이 1~3가지 이유로 인해 content 컬럼에 수직 파티셔닝을 적용하여 테이블을 분리해 볼 수 있다.

 

[article table]

id title writer_id created_at view_cnt comment_cnt

 

[article_content table]

article_id content

 

 

수직 파티셔닝의 장단점

1) 장점

- Disk I/O 오버헤드 감소로 인한 read / write 연산에서 모두 성능 향상

- 민감 데이터 분리

 

2) 단점

- Join 발생 빈도 증가

 

 

 

2. Horizontal Partitioning (수평 파티셔닝)

- row를 기준으로 데이블을 나누는 방식이다. 따라서 수직 파티셔닝과 다르게 테이블의 스키마는 그대로 유지된다.

- 테이블 레벨의 scale-out이라고 생각할 수 있다.

 

예시

게시글 좋아요에 대한 기록을 관리하는 테이블이 아래와 같이 설계되었다고 가정하자.

 

[like_article]

user_id article_id created_at

 

위 테이블이 가질 수 있는 최대 row의 개수는 '사용자 수 X 게시글 수'이다. 즉, 모든 유저가 모든 게시글을 좋아요했을 경우이다. 만약 사용자 수가 100만 명이고 게시글이 1000개라면 위 테이블의 최대 row 개수는 10억이 된다.

 

 

발생할 수 있는 문제점: 빈번한 인덱스 재구조화

인덱스가 적절하게 설정되었다고 하더라도 데이터가 많아질수록 효율성은 낮아진다. 뿐만 아니라 좋아요는 빈번하게 발생한다는 점에서(즉, 해당 테이블에 대한 빈번한 insert, delete 작업 발생) 인덱스에 대한 재구조화 작업 역시 빈번하게 발생하여 결국 서비스 자체의 성능에 문제가 될 수 있다.

 

 

따라서 위와 같은 특징을 가진 테이블에는 row를 기준으로 수평 파티셔닝을 적용할 수 있다.

 

 

2-3) 수평 파티셔닝의 종류

- Range Partitioning

동일한 범위로 파티셔닝 한다. 예를 들어 id가 1~10,000, 10,001~20,000과 같은 방식으로 나눌 수 있다. 숫자나 날짜와 같이 연속적이라는 특징을 가진 데이터에 적용할 수 있다. (아래 예시 참고)


- List Partitioning

특정 컬럼이 고정된 값을 가진다는 가정이 있어야 적용할 수 있다. 예를 들어 지역이라는 컬럼이 서울, 부산, 대구 값만 가질 수 있다고 가정하면 해당 3가지 값에 따라 파티셔닝을 진행한다.


- Hash Partitioning

해시 함수의 값에 따라 파티션에 포함할지 여부를 결정한다. 위 예시 상황에서를 예시로 들자면, user_id를 해쉬 함수의 입력으로 주고 출력의 범위를 0과 1로 정의했다면 파티션 될 테이블은 총 2개가 된다. 파티션 할 테이블 개수에 따라 해쉬 함수의 출력 범위를 결정하면 된다. 여기서 user_id를 partition key라고 한다.

 

cf. Hash Partitioning 주의사항

만약 특정 article을 좋아요한 모든 유저를 조회하고 싶다면 이 경우엔 모든 파티션을 찾아봐야 한다. 따라서 이러한 경우를 방지하기 위해 partition key를 무엇으로 설정하느냐가 매우 중요하다. 일반적으로 가장 많이 사용되는 경우를 고려하여 partition key를 정한다. 또한 해쉬 함수의 결과에 따라 각 파티션이 가지는 용량이 천차만별로 달라질 수 있기 때문에 최대한 균등하게 파티션을 구성할 수 있도록 해쉬 함수를 결정해야 한다. 한 번 결정한 설계를 바꾼다는 것은 굉장히 비용이 큰 작업이다. 특히나 수평 파티셔닝은 대용량 데이터를 분산하기 위한 것을 목적으로 하기 때문에 초기에 파티셔닝을 구성할 때 어떻게 하느냐가 굉장히 굉장히 중요하다. 특히 무중단 서비스에서는 더더욱 그럴 것이다.


- Composite Partitioning

상기 기술을 결합하는 것을 의미하며, 예를 들면 먼저 범위 분할하고, 다음에 해시 분할 같은 것을 생각해 볼 수 있다.

 

 

cf. Range 수평 파티셔닝 예제

아래는 BusinessCard 테이블을 생성하고 연도 컬럼을 기준으로 Range 파티셔닝을 구축하는 예제이다. MySQL의 InnoDB엔진을 기준으로 했으며 파티셔닝은 MySQL5부터 지원되고 있다.

CREATE TABLE BusinessCard(
	ID INT NOT NULL, 
	NAME varchar(255), 
	Address varchar(255),
	Telephone varchar(255), 
	creationTime Date
) partition by range (year(CreationTime))(
	partition p0 values less than(2013),
	partition p1 values less than(2014),
	partition p2 values less than(2015),
	partition p3 values less than MAXVALUE
)

RANGE (YEAR(CreationTime))을 통해 CreationTime컬럼의 연도를 기준으로 range기반 파티션을 정의하고 partition ~ value less then 문에서 총 4개의 파티션을 생성한다. 이렇게 파티션을 나눠두면 이후 BusinessCard 테이블에 Insert해도 DB 내부적으로 파티션에 들어가게 된다. (샤드의 경우에는 다름)

 

아래는 이미 구축한 파티셔닝을 추가하거나 삭제하는 예제이다.

-- 파티션 추가/삭제
ALTER TABLE BusinessCard ADD PARTITION(PARTITION p4 VALUES LESS THAN (2005));
ALTER TABLE BusinessCard DROP PARTITION p4;

 

아래는 파티션을 분할하거나 합병하는 예제이다.

-- 파티션 분할/병합
ALTER TABLE BusinessCard 
	REORGANIZE PARTITION p3 INTO (
		PARTITION p3 VALUES LESS THAN (2015),
		PARTITION p4 VALUES LESS THAN MAXVALUE
	);

ALTER TABLE BusinessCard 
	REORGANIZE PARTITION p2,p3 INTO (
		PARTITION p23 VALUES LESS THAN (2014)
	);

 

 

 

cf. 수평 파티셔닝과 샤딩(Sharding)

샤딩은 수평 파티셔닝의 일종이지만 수평 파티셔닝과의 주요 차이점은 파티션을 분산 배치하느냐 그렇지 않느냐에 있다. 샤딩은 쪼개진 파티션(샤드)들을 서로 다른 노드(DBMS)에 분산 배치하여 '트래픽을 분산하는 목적'을 기반으로 하지만 수평 파티셔닝은 좀 더 넓은 의미의 개념으로 같은 DBMS에 분산배치할 수도 있다. 일반적인 수평 파티셔닝의 문제점 중 하나로 결국 요청이 밀려오게 될 때 단일 DB서버에 과부하가 유발되기 때문에 응답 지연이 발생할 수 있다는 점이다. 따라서 이 경우를 고려한다면 샤딩을 적용하는 것이 방법이 될 수 있다. 샤딩은 서로 다른 DB서버에 분산 배치되기 때문에 외래키 사용 등에 대한 제약이 발생하며 샤드 간 트랜잭션을 필요로 할 경우엔 2PC 개념이 필요하다.

 

 


 

DB Replication과 DBMS Clustering

(DB에만 사용되는 용어는 아님) 데이터베이스 레플리케이션과 클러스터링은 모두 시스템 고가용성(HA) 및 Fail-over 처리를 달성하기 위해 사용되지만 서로 다른 방식으로 작동한다.

 

Replication과 Clustering의 차이점

레플리케이션은 DBMS 같은 프로세스나 애플리케이션 또는 데이터 자체를 그대로 사하는 기술 또는 복사한 데이터를 동기화하는 기술 자체를 의미한다. 이에 반해 클러스터링은 여러 DBMS와 같은 프로세스나 애플리케이션을 서로 '연결'하여 하나의 논리적인 엔티티로 동작하도록 하는 기술을 의미한다. 예를 들어 Single Master-Slave 구조로 DB 서버들이 클러스터를 구성하고 있다고 가정했을 때, Master에 장애가 발생했을 경우 새로운 Master를 선출하는 과정은 클러스터링의 개념이지 레플리케이션의 개념이 아니다.

 

 

1. DB Replication

데이터 그 자체에 대해 레플리케이션을 적용할 경우, 데이터 복사 과정은 동기식 또는 비동기식으로 수행할 수 있다. 동기식으로 수행할 경우 데이터의 모든 복사본이 항상 제때에 서로 동기화되도록 하고 비동기식은 복사본 간에 약간의 지연을 허용한다. DBMS를 레플리케이션 할 경우 DBMS 자체적으로 제공되는 기술을 사용하거나 그 외 다른 툴을 사용하여 구축할 수 있다.

 

2. DBMS Clustering

각 DBMS는 replication 되어 서로 같을 수도 있고 아닐 수도 있다. 클러스터로 구축된 각 DBMS는 아래와 같은 방식을 통해 서로 연결되어 하나의 엔티티처럼 동작한다.

 

1) Active-Passive (또는 Active-Standby) Clustering

들어오는 모든 요청을 Active서버가 처리한다. 다른 서버는 Passive(standby) 서버로 지정되어 휴면 상태이며 Active 서버에 장애가 발생할 때에만 동작한다. 

 

2) Active-Active Clustering

클러스터의 모든 서버는 Active 상태이며 들어오는 요청을 동시에 처리한다. 이를 통해 '로드 밸런싱'이 가능하고 성능 향상을 기대할 수 있다. 

 

3) Master-Slave (Primary-Secondary, Leader-Follower) Clustering

각 클러스터는 서로 다른 역할을 수행하도록 구성되어 있는 것을 전제로 한다. 하나 이상의 서버가 Leader 서버로 지정되어 들어오는 모든 요청(read-write)을 처리하고 데이터베이스에 기록한다. 다른 서버는 Follower 서버로 지정되어 Leader에서 업데이트를 수신하고 읽기 전용(read only)으로만 사용할 수 있다. 이러한 클러스터 구조는 read 요청을 secondary로 분산시켜 트래픽이 몰릴 경우, 부하 분산에 유용하다는 장점이 있다.

 

 

 

 

 

한 줄 요약

- 파티셔닝은 DB 시스템의 용량과 성능 향상을 목적으로 데이터를 파티션 단위로 쪼개는 개념이다.

- 수직 파티셔닝은 컬럼을 기준으로 테이블을 분리하며 아래와 같은 경우에 사용될 수 있다.

    1) 특정 컬럼의 데이터 용량이 클 경우 무거운 disk I/O를 피하기 위해

    2) 특정 컬럼의 사용 빈도가 크거나 적을 경우 무거운 disk I/O를 피하기 위해

    3) 특정 컬럼이 민감한 데이터를 다룰 경우 테이블에 대한 접근 권한을 분리하기 위해

- 수평 파티셔닝은 row를 기준으로 분리하며 DBMS에서 지원되는 기술이다.

- 샤딩은 수평 파티셔닝의 일종으로 각 파티션을 같은 DBMS에 저장하는 일반적인 수직 파티셔닝과 다르게 각 파티션을 서로 다른 DBMS에 분산 배치하여 부하를 분산시킨다.

- 클러스터링과 레플리케이션은 HA 시스템 구축을 위한 목적으로 사용되는 기술이다.

    1) 클러스터링: 서로 분산된 프로세스 간 서로 연결되어 하나의 엔티티처럼 역할을 하기 위한 기술

    2) 레플리케이션: 데이터 또는 프로세스를 그대로 복제하는 기술로 데이터를 복제할 경우 이들 간 동기화 기술을 제공

 

 

 

Reference

- YouTube 쉬운코드, https://youtu.be/P7LqaEO-nGU

- DB 파티셔닝이란, https://gmlwjd9405.github.io/2018/09/24/db-partitioning.html

- How Database Replication Works, https://betterprogramming.pub/how-database-replication-works-a92ad191df20