-
Sharding 만들어보기글또 2024. 11. 24. 17:11
들어가며
안녕하세요.
최근 Pinterest의 샤딩 관련 글을 읽고 흥미로운 점들이 많아 이를 계기로 샤딩에 대해 더 공부하게 되었습니다.
이 과정에서 우아한형제들의 기술 블로그 글도 접하게 되었고, 글에 소개된 코드를 바탕으로 직접 따라 만들어 보았습니다.
이 글은 샤딩에 대한 소개, 우아한형제들의 글 분석, 그리고 Pinterest의 글 분석 순으로 구성되어 있습니다.
샤딩(Sharding)
샤딩이란 무엇이며, 언제 필요할까?
서비스를 장기간 운영하거나 폭발적인 성장을 경험하면 데이터베이스(DB)에 저장된 데이터의 양이 급격히 증가합니다.
데이터가 많아지면 DB의 쓰기, 읽기 속도가 느려지고, 저장 용량 부족과 네트워크 병목 같은 문제가 발생할 수 있습니다.
이를 해결하기 위해 선택할 수 있는 확장 방법은 크게 두 가지입니다.
- 수직적 확장 (Vertical Scaling)
서버의 CPU, RAM 등 하드웨어를 업그레이드하여 성능을 향상하는 방식입니다. 구현이 비교적 간단하지만, 비용이 기하급수적으로 증가하며, 하드웨어의 물리적 한계에 다다르면 더 이상 확장이 불가능합니다. - 수평적 확장 (Horizontal Scaling)
더 많은 노드를 추가하여 데이터를 분산하는 방식입니다. 샤딩은 이 수평적 확장에 해당하며, 데이터를 여러 DB에 나누어 저장함으로써 성능과 확장성을 확보합니다.
샤딩의 장점
데이터 처리 능력
초기 데이터 저장소로 Hadoop이나 MongoDB, Cassandra를 사용했다면 대량의 비정형 데이터를 효율적으로 처리할 수 있습니다.
모두 사용자가 세부적으로 관리하지 않아도 자동으로 데이터를 분산하기때문입니다.그러나 RDB을 선택했다면 단일 DB에서는 성능 한계가 발생할 수 있습니다.
직접 샤딩을 구현하면 이러한 문제를 해결하며, 검색과 삽입 속도를 개선할 수 있습니다.단일 장애 지점 방지
데이터를 여러 노드에 분산 저장하므로 특정 노드에 장애가 발생해도 전체 시스템이 중단되지 않습니다.
일부 사용자나 기능만 영향을 받게 됩니다.
샤딩의 단점
복잡성 증가
관리해야 할 DB가 많아지면서 운영 부담이 커집니다. 예를 들어, 스키마 변경이 어려워지고 관리 포인트도 증가합니다.
데이터 불균형
샤딩 키 선택을 잘못하면 데이터와 부하가 특정 샤드에 쏠릴 수 있습니다.
예를 들어, 사용자의 성씨를 샤딩 키로 사용하면 특정 성씨가 몰리는 문제가 발생할 수 있습니다.
이를 데이터베이스 핫스팟이라 부릅니다.
이러한 문제가 발생하면 샤딩을 다시 설계해야 합니다.기능 제한
기본적으로 여러 DB간의 조인이나 트랜잭션 기능을 활용할 수 없으므로 애플리케이션에서 이를 구현해야 합니다.
샤딩 방법 선택
샤딩의 성공 여부는 데이터가 어떤 기준으로 분산 저장될지를 결정하는 샤딩 방법에 달려 있습니다.
다음은 대표적인 샤딩 방법입니다.
- 범위 기반 샤딩 (Range Sharding)
범위별로 데이터를 분산하지만, 특정 범위에 데이터가 몰릴 경우 핫스팟 문제가 발생할 수 있습니다. - 해시 기반 샤딩 (Hash Sharding)
해시 연산을 통해 데이터를 고르게 분산합니다. 다만, 새로운 샤드를 추가할 때 기존 데이터를 다시 해싱해야 하므로 다운타임이 발생할 수 있습니다. - 디렉토리 기반 샤딩 (Directory Sharding)
데이터가 저장될 샤드를 기록하는 테이블을 별도로 두는 방식입니다. 확장과 수정이 유연하지만, 디렉토리 테이블 자체가 단일 장애 지점이 될 수 있습니다. 이를 방지하려면 고가용성(HA)을 구축해야 합니다.
이처럼 샤딩은 데이터 라우팅, 샤드 키 설계 등 높은 복잡성과 비용을 수반합니다.
따라서 도입 전 캐시 활용, 서버 스케일 업, 복제 노드 추가 같은 대안을 우선 시도해볼 필요가 있습니다.
하지만 서비스가 일정 성장 한계를 넘어서면 이들만으로는 부족하며, 샤딩이 필요하게 됩니다.
우아한 형제들의 Sharding 구현
우아한 형제들의 기술 블로그에서는 Spring을 기반으로 샤딩을 구현한 방법을 소개하고 있었습니다.
핵심 아이디어는 데이터를 처리할 때 동적으로 적합한 데이터 소스(DataSource) 를 선택하는 데 있습니다.
이 과정에서 AbstractRoutingDataSource를 활용하여 샤딩 라우팅을 효율적으로 구현했는데, 개발자가 사전에 구성한 샤딩 방식(예: 범위 샤딩, 모듈러 샤딩)에 따라 알맞은 데이터 소스를 반환하도록 설정한 점이 흥미로웠습니다.
또한 각 샤드는 Master-Slave 구조로 구성되어 있었는데, 데이터 삽입과 업데이트 작업은 Master로, 조회 작업은 Slave로 라우팅하는 방식을 사용했습니다.
이를 통해 읽기와 쓰기 작업의 부하를 분리함으로써 성능을 최적화할 수 있었습니다.
샤드 키
데이터 분산을 할 때 기준이되는 키가 있어야합니다.
이 글에서는 특정 테이블만을 대상으로 샤딩을 했기때문에 샤딩키는 이미 존재하는 userid를 사용하고 있습니다.
이미 존재하는 키를 활용해 샤딩을 설계한 점은 간단하지만 효과적입니다.
데이터 생성 시점에 샤드 키가 없는 경우에는 샤드 키를 생성해야 할 필요가 있습니다.
Sample Code샘플 코드를 바탕으로 프로젝트를 구현해 보았습니다.
프로젝트에서는 DataSource를 생성하고, LookUp Key를 이용해 동적으로 라우팅하는 방식으로 샤딩을 구현되었습니다.Pinterest에서의 Sharding 구현
글로벌 기업인 Pinterest 역시 DB 분산 처리를 위해 샤딩을 도입한 사례가 있습니다.
폭발적인 성장 속에서 기존 데이터베이스 구조로는 급증하는 데이터를 처리하기 어려워지자, 샤딩 방식을 선택하게 되었습니다.
처음에는 클러스터링 방식과 샤딩 방식을 비교했으나, 당시 클러스터링 기술이 성숙하지 않아 버그가 많았고 안정성이 떨어졌기 때문에 샤딩을 선택했습니다.
흥미롭게도, Pinterest는 NoSQL 솔루션인 MongoDB나 Cassandra 대신 MySQL을 선택했습니다.
그 이유는 NoSQL 역시 당시에는 충분히 발전되지 않아 안정성에서 MySQL에 미치지 못했기 때문입니다.
MySQL은 오랜 기간 안정적인 기술로 평가받아왔으며, 성숙한 생태계를 갖추고 있어 샤딩을 구현하는 데 적합한 선택이었습니다.
Pinterest의 샤딩 구성에서 눈에 띄는 특징은 데이터를 JSON 형태로 단일 컬럼에 저장한다는 점입니다.
CREATE TABLE pins ( local_id INT PRIMARY KEY AUTO_INCREMENT, data TEXT, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; ex. {“details”: “New Star Wars character”, “link”: “http://webpage.com/asdf”, “user_id”: 241294629943640797, “board_id”: 241294561224164665, …}
이는 샤딩 환경에서 컬럼 추가와 같은 스키마 변경의 부담을 줄여주는 장점이 있습니다.
데이터 스키마 변경이 빈번한 서비스에서는 특히 유용한 방식으로 보입니다.
샤드 키
글에서 샤드 키 생성 방식이 구체적으로 설명되지는 않았지만, 다른 자료를 통해 이를 보완할 수 있었습니다.
Pinterest는 유저 생성 시 랜덤으로 샤드를 배정하며, 동일한 샤드에 해당 유저의 핀, 보드와 같은 관련 데이터를 모두 저장합니다. 이를 통해 유저 정보와 관련된 데이터 조회 시 어플리케이션 레벨에서 조인이 필요 없어지는 장점을 얻을 수 있습니다.
또한, Pinterest는 유저에게 글로벌 유니크 키를 노출합니다. 이 글로벌 유니크 키는 샤드 정보(16비트), 데이터 타입(10비트), 테이블의 로컬 ID(32비트), 그리고 미래 확장성을 고려한 2비트 공간으로 이루어진 64비트 ID입니다.예로 241294492511762325의 글로벌 유니크 키는 아래와 같이 변환할 수 있습니다.
Shard ID = (241294492511762325 >> 46) & 0xFFFF = 3429 Type ID = (241294492511762325 >> 36) & 0x3FF = 1 Local ID = (241294492511762325 >> 0) & 0xFFFFFFFFF = 7075733
이러한 설계는 데이터 라우팅을 간소화하고 성능을 최적화하는 데 기여합니다.
이런 방식은 instagram이나 twitter의 사례에서도 찾아볼 수 있습니다.
마무리
제가 아직 NoSQL에 대한 이해가 깊지 않아, RDB에서 구현한 샤딩과 Cassandra, MongoDB와 같은 NoSQL 기술을 사용하는 것의 장점을 명확히 비교하기는 어렵습니다.
그러나 앞으로 NoSQL에 대해 공부하고 경험을 쌓게 된다면, 이 글을 더 업데이트할 계획입니다.
Pinterest의 샤딩 경험을 다룬 글이나, 우아한 형제들이 공유한 깔끔한 샤딩 구현 예시는 많은 영감을 주었습니다.
성장하는 회사에서의 기술적 도전과 해결 과정은 개발자로서 많은 것을 배울 수 있는 기회라는 점을 다시 한번 느꼈습니다.비록 현재 상황과는 다르지만, 이러한 글을 통해 간접적으로 배움을 얻을 수 있어 좋은 경험이었습니다.
앞으로도 이러한 학습의 기회를 꾸준히 찾아가고자 합니다.
- https://nadermedhatthoughts.medium.com/understand-database-sharding-the-good-and-ugly-868aa1cbc94c
- https://techblog.woowahan.com/2687/
- https://medium.com/codex/how-pinterest-scaled-to-11-million-users-with-only-6-engineers-a0f62cea62b8
- https://medium.com/pinterest-engineering/sharding-pinterest-how-we-scaled-our-mysql-fleet-3f341e96ca6f
- https://levelup.gitconnected.com/4-advanced-sharding-techniques-every-software-engineer-must-know-b4493dc6ec0f
- https://www.digitalocean.com/community/tutorials/understanding-database-sharding
- https://www.publickey1.jp/blog/13/pinterestqcon_tokyo_2013.html
- https://www.quora.com/How-would-you-compare-MySQL-sharding-vs-Cassandra-vs-MongoDB
- https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c
'글또' 카테고리의 다른 글
실시간 리더보드 만들어보기 (0) 2024.11.09 글또10기 삶의 지도 (0) 2024.10.12 HikariCP와 Slow Query로 인한 Commit 성공과 Rollback 실패 (0) 2024.09.19 Lock에 대해 알아보기: Gap Lock (0) 2024.09.01 Lock에 대해 알아보기: Gap Lock 2 (0) 2024.08.30 - 수직적 확장 (Vertical Scaling)