이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
공부 › DB › 확장과 분산
샤딩
데이터를 여러 DB에 나누면 생기는 일
테이블 하나가 DB 한 대로 감당할 수 없을 만큼 커지면, 행을 여러 DB(샤드)에 나눠 담습니다. 어느 행이 어느 샤드로 갈지는 샤드 키와 나누는 규칙이 정합니다.
실행으로 대조 · 같은 데이터를 자바로 따로 계산해 대조
이 실습에 나오는 개념
- 샤딩과 파티셔닝
- 파티셔닝은 큰 테이블을 날짜 범위 등의 기준으로 여러 조각으로 나눠 관리하는 것이다. 샤딩은 데이터를 여러 데이터베이스 서버에 나눠 저장하는 것으로, 한 서버로 감당할 수 없는 쓰기 부하나 데이터 양을 분산한다. 샤딩을 하면 서버에 걸친 조인이나 트랜잭션이 어려워진다.
- 스케일 업과 스케일 아웃
- 스케일 업은 서버 한 대의 사양(CPU, 메모리)을 높여 처리 능력을 키우는 것이고, 스케일 아웃은 서버의 수를 늘려 부하를 나누는 것이다. 스케일 업은 간단하지만 한계와 비용 문제가 있고, 스케일 아웃은 유연하게 확장할 수 있지만 서버가 상태를 갖지 않도록 설계하고 요청을 분산할 장치가 필요하다.
- 레플리케이션(복제)
- 원본 데이터베이스(source이며 primary라고도 부른다)의 변경 내용을 다른 데이터베이스(replica)에 계속 복사해 같은 데이터를 유지하는 것이다. 읽기 요청을 복제본으로 분산해 부하를 줄이고, 원본에 장애가 나면 복제본을 원본으로 승격해 서비스를 이어 갈 수 있다. 복제에는 약간의 지연이 있어 방금 쓴 데이터가 복제본에서 바로 보이지 않을 수 있다.
이렇게 바꿔 보세요
- 처음 설정으로 — 회원 번호를 4로 나눈 나머지로 분배. 고르게 퍼집니다.
- 주문 번호 구간으로 나누면 — 새 주문은 전부 마지막 샤드로 갑니다.
- 특정 회원의 주문이 많으면 — 그 회원이 속한 샤드만 커집니다.
- 해시 방식에서 샤드 추가 — 4개에서 5개로. 대부분의 데이터가 이사해야 합니다.
- 범위 방식에서 샤드 추가 — 기존 데이터는 그대로 두고 새 구간만 받습니다.
처음 설정으로 실행하면
- 주문 120건을 샤드 4개에 나눠 담습니다. 주문의 회원 번호를 샤드 수(4)로 나눈 나머지가 샤드 번호입니다. 같은 회원의 주문은 항상 같은 샤드에 모입니다.
- 분배 결과입니다. 가장 많은 샤드는 30건, 가장 적은 샤드는 30건입니다. 회원 번호가 고르게 퍼져 있어 샤드별 건수가 비슷합니다.
- 새 주문은 주문한 회원의 번호에 따라 여러 샤드로 흩어집니다. 쓰기 부하가 분산됩니다.
- "회원 7번의 주문 목록" 조회: 7 % 4 = 3번 샤드만 보면 됩니다. 반대로 "어제 주문 전체"처럼 회원 번호 없이 찾는 조회는 모든 샤드에 질의해야 합니다.
실행 결과
- 샤드 키는 한 번 정하면 바꾸기 매우 어렵습니다. 가장 자주 쓰는 조회 조건이 샤드 키여야 한 샤드만 보고 끝납니다. 샤드 키가 없는 조회, 샤드에 걸친 조인과 트랜잭션은 어려워집니다.
- 샤딩은 쓰기와 데이터 양을 나누는 마지막 수단입니다. 그 전에 인덱스와 쿼리 개선, 캐시, 읽기 전용 복제본, 오래된 데이터 분리를 먼저 검토합니다.
코드
// 회원 번호를 샤드 수로 나눈 나머지로 샤드를 정한다
int shardOf(long memberId) {
return (int) (memberId % 4);
}
// 조회할 때도 같은 계산으로 샤드를 찾는다
DataSource ds = shards.get(shardOf(memberId));
이 모형의 전제
주문 120건, 회원 40명의 작은 예입니다. 회원 번호는 주문에 고르게 배정했고, "주문 많은 회원" 설정에서는 주문 세 건 중 한 건을 회원 7번의 것으로 두었습니다. 샤드 수가 바뀔 때 이동하는 비율은 이 데이터로 실제 계산한 값입니다. 샤드마다 복제본을 두는 구성이나 샤드 위치를 관리하는 라우터는 생략했습니다. 샤드 수 2~6개에서 하나를 늘릴 때 옮겨야 하는 건수를 자바에서 따로 계산해 화면의 값과 일치하는 것을 확인했습니다.
앞 실습: 복제 지연과 CAP · 다음 실습: 파티셔닝