NoSQL 데이터베이스는 비관계형 데이터베이스로, 데이터를 저장하고 검색하는 데 있어 전통적인 관계형 데이터베이스의 테이블 구조를 사용하지 않습니다.
NoSQL 데이터베이스는 다양한 데이터 모델을 지원하며, 주로 대규모 데이터 처리와 높은 확장성을 필요로 하는 애플리케이션에서 사용됩니다.
다양한 데이터 모델: 문서(Document), 키-값(Key-Value), 열(Column-Family), 그래프(Graph) 등의 다양한 데이터 모델을 지원합니다.
수평적 확장성: 데이터를 쉽게 샤딩하여 여러 서버에 분산 저장할 수 있어 수평적 확장이 용이합니다.
유연한 스키마: 스키마가 고정되지 않아, 동적으로 데이터 구조를 변경할 수 있습니다.
고성능: 높은 쓰기 및 읽기 성능을 제공하며, 대규모 데이터 처리에 적합합니다.
NoSQL에서 샤딩이 쉬운 이유
NoSQL 데이터베이스는 일반적으로 수평적 확장성과 분산 시스템을 염두에 두고 설계되었습니다.
NoSQL이 샤딩을 쉽게 지원하는 이유는 다음과 같습니다:
유연한 데이터 모델:
NoSQL 데이터베이스는 스키마리스(Schema-less) 구조를 가지므로,
데이터를 동적으로 추가하고 수정할 수 있습니다.
이는 데이터 모델을 변경하지 않고도 샤딩을 쉽게 구현할 수 있게 합니다.
다양한 데이터 모델(문서, 키-값, 열 가족, 그래프)을 지원하여 특정 데이터 모델에 맞게 샤딩 전략을 쉽게 적용할 수 있습니다.
내장된 샤딩 지원:
많은 NoSQL 데이터베이스(예: MongoDB, Cassandra, Redis)는 기본적으로 샤딩을 지원합니다.
이러한 데이터베이스는 자동으로 데이터를 분할하고, 샤드 간의 데이터 일관성을 유지하며,
쿼리를 적절한 샤드로 라우팅하는 기능을 제공합니다.
수평적 확장성:
NoSQL 데이터베이스는 수평적 확장을 염두에 두고 설계되었으므로,
새로운 노드를 추가하여 쉽게 확장할 수 있습니다.
데이터를 여러 샤드로 분할하여 저장함으로써 읽기 및 쓰기 작업을 분산시켜 부하를 줄일 수 있습니다.
CAP 이론:
NoSQL 데이터베이스는 CAP 이론(Consistency, Availability, Partition Tolerance)에 따라 설계되었습니다.
-> AP를 취하고 C를 희생 (RDBMS는 CA를 취하고 P를 희생)
대부분의 NoSQL 시스템은 일관성을 일부 포기하고 가용성과 파티션 내성을 중시하여,
샤딩과 같은 분산 시스템에서의 확장성을 극대화합니다.
Consistency (일관성):
모든 노드가 동일한 시점에 동일한 데이터를 보장합니다.
즉, 하나의 노드에서 데이터 변경이 발생하면, 모든 노드에서 즉시 해당 변경 사항이 반영되어야 합니다.
예를 들어, 데이터가 업데이트되면 즉시 모든 읽기 연산은 최신 데이터를 반환해야 합니다.
Availability (가용성):
시스템이 항상 응답할 수 있어야 합니다.
특정 노드가 장애가 발생하더라도, 전체 시스템은 계속해서 정상적으로 작동하고 응답을 반환해야 합니다.
모든 요청이 실패하지 않고 항상 응답을 받아야 함을 의미합니다.
Partition Tolerance (분할 내성):
네트워크 분할이 발생하더라도 시스템이 정상적으로 작동할 수 있어야 합니다.
분산 시스템에서 네트워크 연결이 일시적으로 끊어지는 상황에서도 시스템은 계속 동작해야 합니다.
노드 간의 통신이 불가능해져도 시스템은 운영을 지속할 수 있어야 합니다.
확장성: 수평적 확장이 용이하여 대규모 데이터와 높은 트래픽을 처리할 수 있습니다.
유연성: 스키마리스 구조로 데이터 모델링이 유연합니다.
다양한 데이터 모델: 다양한 데이터 모델을 지원하여 특정 요구사항에 맞는 선택이 가능합니다.
고성능: 빠른 데이터 읽기/쓰기 성능을 제공합니다.
데이터 일관성 문제: 분산 환경에서 데이터 일관성을 유지하는 것이 어려울 수 있습니다.
제한된 쿼리 기능: 복잡한 쿼리와 조인 연산이 제한적입니다.
트랜잭션 지원 제한: ACID 트랜잭션 지원이 제한적일 수 있습니다.
빅 데이터 처리: 대규모 데이터 분석 및 처리 시스템.
실시간 웹 애플리케이션: 높은 트래픽을 처리하는 웹 애플리케이션.
유연한 데이터 모델이 필요한 경우: 스키마가 자주 변경되는 애플리케이션.
분산 환경: 여러 노드에 걸쳐 데이터를 저장하고 관리하는 시스템.
인메모리 스토어: Redis와 같은 NoSQL 데이터베이스는 주로 데이터를 메모리에 저장하여 초고속 읽기 및 쓰기 성능을 제공합니다.
키-값 스토어: 데이터는 키-값 쌍으로 저장되어 간단한 조회 및 업데이트가 가능합니다. 예를 들어, DynamoDB, Redis 등이 있습니다.
TTL (Time To Live): 일부 NoSQL 데이터베이스는 데이터에 TTL을 설정하여 일정 시간이 지나면 자동으로 데이터를 삭제할 수 있습니다. 이는 캐시 데이터 관리에 유용합니다.
고가용성 및 스케일링: NoSQL 데이터베이스는 고가용성을 위해 데이터 복제 및 클러스터링을 지원하며, 자동으로 데이터 파티셔닝을 통해 확장성을 제공합니다.
다양한 데이터 타입 저장 가능: NoSQL 데이터베이스는 문자열, 숫자, 리스트, 해시, 셋 등의 다양한 데이터 타입을 저장할 수 있습니다.
관계형 데이터베이스는 데이터를 테이블 형태로 저장하며, 각 테이블은 열(Column)과 행(Row)으로 구성됩니다. 테이블 간의 관계를 정의하고, 이를 SQL(Structured Query Language)로 관리합니다. RDBMS는 ACID 트랜잭션을 지원하여 데이터 무결성과 일관성을 보장합니다.
정형화된 데이터 구조: 테이블과 스키마를 정의하여 데이터를 정형화된 구조로 저장합니다.
SQL 사용: SQL을 사용하여 데이터 쿼리, 삽입, 업데이트, 삭제를 수행합니다.
ACID 트랜잭션 지원: 원자성, 일관성, 격리성, 지속성을 보장하는 트랜잭션을 지원합니다.
정교한 쿼리 기능: 복잡한 조인, 서브쿼리 등을 포함한 정교한 쿼리 기능을 제공합니다.
데이터 무결성: ACID 트랜잭션을 통해 데이터 무결성과 일관성을 보장합니다.
강력한 쿼리 기능: SQL을 통해 복잡한 데이터 조작 및 분석이 가능합니다.
보안 및 권한 관리: 사용자 권한 관리와 보안 기능이 강력합니다.
표준화: SQL은 데이터베이스 관리의 표준 언어로 널리 사용됩니다.
확장성 문제: 수평적 확장이 어렵고, 대규모 데이터 처리에 성능이 저하될 수 있습니다.
유연성 부족: 스키마가 고정되어 있어 데이터 구조 변경이 어렵습니다.
성능 문제: 높은 읽기/쓰기 성능을 요구하는 경우 성능이 저하될 수 있습니다.
트랜잭션 처리: 금융 거래, 주문 처리 등 트랜잭션이 중요한 애플리케이션.
정형 데이터 저장: 데이터 구조가 고정되고 정형화된 데이터를 저장하는 경우.
데이터 분석: 복잡한 쿼리를 통한 데이터 분석 및 보고서 생성.
비즈니스 애플리케이션: ERP, CRM 등 비즈니스 애플리케이션.
RDBMS는 데이터를 디스크에 영구적으로 저장하며, 데이터 무결성과 일관성을 보장하기 위해 다양한 기술을 사용합니다:
테이블 구조: 데이터는 테이블 형태로 저장되며, 각 테이블은 고유한 열(Column)과 행(Row)으로 구성됩니다. 테이블 간의 관계를 외래 키(Foreign Key)를 통해 정의합니다.
인덱스: 데이터 검색 속도를 높이기 위해 인덱스를 사용합니다. 인덱스는 특정 열의 값을 기반으로 데이터의 위치를 빠르게 찾을 수 있도록 도와줍니다.
트랜잭션 로그: 트랜잭션의 일관성을 유지하기 위해 모든 데이터 변경 사항을 트랜잭션 로그에 기록합니다. 시스템 장애 시 로그를 이용해 데이터를 복구할 수 있습니다.
백업 및 복구: 정기적인 백업을 통해 데이터를 안전하게 보관하며, 필요 시 백업된 데이터를 복구할 수 있습니다.
스토리지 엔진: MySQL의 InnoDB, PostgreSQL의 MVCC 등 다양한 스토리지 엔진을 사용하여 데이터 저장 및 관리를 최적화합니다.
클러스터링 및 복제: 고가용성을 위해 데이터베이스 클러스터링 및 데이터 복제 기능을 지원합니다. 이를 통해 데이터베이스 서버 간의 부하 분산과 장애 복구를 할 수 있습니다.
클러스터링과 샤딩은 모두 데이터베이스의 성능을 향상시키고 고가용성을 보장하기 위해 사용되는 기술이지만, 그 구현 방식과 목적에는 차이가 있습니다.
개념: 클러스터링은 여러 데이터베이스 서버를 하나의 시스템처럼 동작하도록 구성하는 것입니다. 클러스터 내의 각 노드는 데이터를 복제하여 동일한 데이터를 가지고 있으며, 노드 간에 부하 분산 및 고가용성을 제공합니다.
목적: 고가용성 및 부하 분산
특징:
데이터 복제: 모든 노드가 동일한 데이터를 가지고 있으므로, 하나의 노드가 장애가 발생하더라도 다른 노드가 서비스를 지속할 수 있습니다.
부하 분산: 클러스터 내의 여러 노드로 읽기 요청을 분산시켜 성능을 향상시킬 수 있습니다.
장애 복구: 특정 노드에 장애가 발생해도 다른 노드가 동일한 데이터를 가지고 있으므로 서비스가 중단되지 않습니다.
개념: 샤딩은 데이터베이스를 여러 서버에 분산 저장하는 방식입니다. 각 서버(샤드)는 전체 데이터의 일부만을 저장하며, 특정 데이터는 특정 샤드에만 존재합니다.
목적: 수평적 확장성 및 대규모 데이터 처리
특징:
데이터 분할: 데이터를 여러 샤드로 분할하여 저장하므로, 데이터가 특정 샤드에만 존재합니다. 예를 들어, 사용자 ID에 따라 데이터를 분할할 수 있습니다.
수평적 확장성: 새로운 샤드를 추가하여 쉽게 확장할 수 있습니다. 데이터의 양이 증가할수록 샤드를 추가하여 처리할 수 있습니다.
성능 향상: 데이터의 양이 분산되므로, 각 샤드는 처리해야 할 데이터 양이 줄어들어 성능이 향상됩니다.
복잡성 증가: 데이터 분할 및 쿼리 라우팅 등 복잡한 로직을 관리해야 하므로 구현이 어렵습니다.
클러스터링과 샤딩의 차이점
데이터 저장 방식:
클러스터링: 모든 노드가 동일한 데이터를 가지고 있습니다.
샤딩: 각 샤드는 데이터의 일부만 저장하며, 전체 데이터가 각 샤드에 분산되어 저장됩니다.
목적:
클러스터링: 고가용성 및 부하 분산을 위해 사용됩니다.
샤딩: 수평적 확장성과 대규모 데이터 처리를 위해 사용됩니다.
구현 난이도:
클러스터링: 구현이 상대적으로 쉽고, 많은 RDBMS가 기본적으로 지원합니다.
샤딩: 구현이 복잡하고, 데이터 분할 및 쿼리 라우팅 등 추가적인 로직이 필요합니다.
관계형 데이터베이스에서의 클러스터링과 샤딩
클러스터링: 관계형 데이터베이스는 클러스터링을 통해 고가용성과 부하 분산을 제공합니다. 예를 들어, MySQL의 InnoDB Cluster, PostgreSQL의 Patroni 등이 있습니다. 이러한 시스템은 데이터 복제와 자동 장애 복구를 통해 고가용성을 보장합니다.
샤딩: 관계형 데이터베이스에서 샤딩은 매우 복잡한 작업입니다. 이는 데이터의 일관성과 무결성을 유지하면서 데이터를 분할하고 관리해야 하기 때문입니다. 관계형 데이터베이스는 일반적으로 정교한 트랜잭션 관리와 강력한 데이터 일관성을 제공하므로, 데이터를 여러 샤드로 분할하는 것이 쉽지 않습니다. MySQL의 경우 MySQL Fabric, PostgreSQL의 경우 Citus 등 샤딩을 지원하는 확장 도구가 있지만, 여전히 구현과 관리가 복잡합니다.
결론적으로, 클러스터링은 관계형 데이터베이스에서 고가용성과 부하 분산을 쉽게 구현할 수 있는 반면, 샤딩은 복잡하고 관리가 어려운 작업입니다. 따라서 관계형 데이터베이스에서의 샤딩은 필요성이 크지 않은 경우가 많으며, 필요할 경우에는 매우 신중한 계획과 관리가 필요합니다.
In-Memory Store: 모든 데이터를 메모리에 저장하여 매우 빠른 읽기/쓰기 속도를 제공합니다.
Key-Value Store: 단순한 키-값 저장소로, 데이터를 키-값 쌍으로 저장합니다.
다양한 데이터 구조 지원: 문자열, 리스트, 셋, 해시, 정렬된 셋 등을 지원합니다.
고가용성 및 스케일링: 클러스터링과 복제를 통해 높은 가용성과 수평적 확장이 가능합니다.
TTL(Time to Live): 각 키에 만료 시간을 설정할 수 있어 자동으로 데이터가 삭제됩니다.
고성능: 메모리 기반이므로 매우 빠른 응답 속도를 제공합니다.
유연성: 다양한 데이터 구조를 지원하여 여러 용도로 활용할 수 있습니다.
단순성: 단순한 키-값 저장소로 사용이 쉽습니다.
분산 환경에서의 신뢰성: 분산락과 같은 고급 기능을 쉽게 구현할 수 있습니다.
데이터 영속성 문제: 기본적으로 메모리에 저장되므로 시스템 장애 시 데이터가 손실될 수 있습니다. 이를 보완하기 위해 스냅샷과 AOF(Append Only File) 기능을 사용해야 합니다.
제한된 쿼리 기능: 복잡한 쿼리와 조인을 지원하지 않습니다.
메모리 의존성: 메모리에 데이터를 저장하므로 메모리 사용량이 큰 경우 비용이 증가할 수 있습니다.
캐싱: 빈번하게 조회되는 데이터를 캐시에 저장하여 데이터베이스 부하를 줄이고 응답 시간을 개선합니다.
세션 관리: 사용자 세션 데이터를 빠르게 저장하고 조회하는 데 적합합니다.
실시간 데이터 처리: 실시간 데이터 분석, 통계, 모니터링 등.
분산락: 다중 인스턴스 환경에서 자원의 동시 접근 제어를 위해 Redis 분산락을 사용할 수 있습니다.
Redis의 단일 스레드 아키텍처
Redis는 단일 스레드로 작동하여 모든 명령어를 순차적으로 처리합니다. 이는 하나의 인스턴스 내에서의 동시성 문제를 해결하고, 원자적 연산을 보장합니다. 단일 인스턴스 환경에서는 원자적 연산이 안전하게 수행됩니다.
Redis 클러스터와 샤딩
Redis 클러스터 모드에서는 데이터를 해시 슬롯으로 분산시켜 여러 인스턴스에 저장합니다. 각 인스턴스는 여전히 단일 스레드로 작동하므로, 각 슬롯에 대해 원자적 연산이 보장됩니다.
Redis 분산 락
Redis 분산 락은 Redis의 빠른 성능과 원자적 명령을 활용하여 다중 인스턴스 환경에서도 안전하게 락을 구현할 수 있습니다. 대표적인 분산 락 구현 방법은 Redlock 알고리즘입니다.
Redlock 알고리즘
Redlock 알고리즘은 다중 Redis 노드를 사용하여 분산 락을 구현합니다. 이 알고리즘은 다음과 같이 동작합니다:
노드 설정: 다섯 개의 Redis 인스턴스를 사용하여 클러스터를 구성합니다.
락 획득 시도:
클라이언트는 모든 Redis 노드에 동일한 락 키를 설정합니다. 이때 각 노드에 대해 짧은 TTL(Time-To-Live)을 설정합니다.
클라이언트는 과반수 이상의 노드에서 락을 획득해야 합니다.
락 유지 및 해제:
락을 획득하면, 클라이언트는 TTL 내에 작업을 완료하고 락을 해제합니다.
TTL이 만료되면 락이 자동으로 해제되어 다른 클라이언트가 락을 획득할 수 있습니다.
Redis 분산 락의 장점
빠른 성능: 인메모리 데이터베이스로 매우 빠른 속도의 락 획득 및 해제가 가능합니다.
높은 가용성: 여러 노드를 사용하여 락을 분산 관리하므로, 일부 노드가 장애가 발생하더라도 락이 여전히 유효합니다.
간편한 구현: Redis의 원자적 명령을 활용하여 분산 락을 쉽게 구현할 수 있습니다.
Relational Database: 데이터를 테이블 구조로 저장하며, 각 테이블은 열과 행으로 구성됩니다.
ACID Compliance: 트랜잭션의 원자성, 일관성, 격리성, 지속성을 보장하여 데이터 무결성을 유지합니다.
SQL 지원: 강력한 SQL 쿼리를 통해 데이터 조작 및 조회가 가능합니다.
스키마 기반: 데이터의 스키마(구조)를 미리 정의해야 합니다.
데이터 무결성: ACID 특성을 통해 데이터의 무결성과 일관성을 유지합니다.
복잡한 쿼리 지원: 조인, 서브쿼리 등을 포함한 복잡한 쿼리를 지원합니다.
데이터 영속성: 디스크에 데이터를 저장하여 시스템 장애 시에도 데이터가 안전하게 보관됩니다.
보안 및 권한 관리: 강력한 사용자 권한 관리 및 보안 기능을 제공합니다.
성능: 대용량 데이터 처리나 높은 읽기/쓰기 요청이 있을 경우 성능이 저하될 수 있습니다.
스케일링의 어려움: 수평적 확장이 어려워 대규모 시스템에서는 관리가 복잡해질 수 있습니다.
유연성 부족: 스키마를 미리 정의해야 하며, 스키마 변경이 어려울 수 있습니다.
트랜잭션 처리: 금융 거래, 주문 처리 등 트랜잭션이 중요한 애플리케이션.
정형 데이터 저장: 데이터 구조가 고정되고 정형화된 데이터를 저장하는 경우.
데이터 분석: 복잡한 쿼리를 통한 데이터 분석 및 보고서 생성.
애플리케이션 백엔드: 웹 애플리케이션, 모바일 애플리케이션의 백엔드 데이터베이스로 널리 사용.
RDBMS는 데이터를 디스크에 영구적으로 저장하며, 데이터 무결성과 일관성을 보장하기 위해 다양한 기술을 사용합니다
테이블 구조: 데이터는 테이블 형태로 저장되며, 각 테이블은 고유한 열(Column)과 행(Row)으로 구성됩니다. 테이블 간의 관계를 외래 키(Foreign Key)를 통해 정의합니다.
인덱스: 데이터 검색 속도를 높이기 위해 인덱스를 사용합니다. 인덱스는 특정 열의 값을 기반으로 데이터의 위치를 빠르게 찾을 수 있도록 도와줍니다.
트랜잭션 로그: 트랜잭션의 일관성을 유지하기 위해 모든 데이터 변경 사항을 트랜잭션 로그에 기록합니다. 시스템 장애 시 로그를 이용해 데이터를 복구할 수 있습니다.
백업 및 복구: 정기적인 백업을 통해 데이터를 안전하게 보관하며, 필요 시 백업된 데이터를 복구할 수 있습니다.
스토리지 엔진: MySQL의 InnoDB, PostgreSQL의 MVCC 등 다양한 스토리지 엔진을 사용하여 데이터 저장 및 관리를 최적화합니다.
클러스터링 및 복제: 고가용성을 위해 데이터베이스 클러스터링 및 데이터 복제 기능을 지원합니다. 이를 통해 데이터베이스 서버 간의 부하 분산과 장애 복구를 할 수 있습니다.
MySQL의 멀티스레드 아키텍처
개념
멀티스레드 아키텍처: MySQL 서버는 여러 클라이언트 연결을 동시에 처리하기 위해 멀티스레드 아키텍처를 사용합니다. 각각의 클라이언트 연결은 별도의 스레드에서 처리되며, 여러 스레드가 병렬로 실행됩니다.
작동 방식
스레드 풀: MySQL은 스레드 풀을 사용하여 스레드를 효율적으로 관리합니다. 클라이언트가 데이터베이스에 접속하면, MySQL 서버는 스레드 풀에서 사용 가능한 스레드를 할당하여 클라이언트의 요청을 처리합니다.
컨텍스트 스위칭: 여러 스레드가 동시에 실행되므로, MySQL 서버는 각 스레드 간의 컨텍스트 스위칭을 통해 CPU 자원을 효율적으로 분배합니다. 이를 통해 높은 동시성 처리가 가능해집니다.
락 메커니즘: 여러 스레드가 동시에 동일한 데이터를 수정하려 할 때 데이터 일관성을 유지하기 위해 MySQL은 락 메커니즘을 사용합니다. 테이블 락, 행 락 등을 통해 데이터 무결성을 보장합니다.
장점
동시성: 멀티스레드 아키텍처는 다수의 클라이언트 요청을 동시에 처리할 수 있어, 동시 접속 처리 능력이 뛰어납니다.
확장성: 서버의 CPU 코어 수가 증가할수록 MySQL 서버는 더 많은 스레드를 병렬로 실행할 수 있어 성능이 향상됩니다.
단점
복잡성: 멀티스레드 환경에서 데이터 일관성을 유지하기 위해 락 메커니즘을 사용하는데, 이는 성능 저하를 초래할 수 있습니다. 특히, 높은 동시성 환경에서 락 경합이 발생할 수 있습니다.
컨텍스트 스위칭 오버헤드: 스레드 간의 컨텍스트 스위칭은 오버헤드를 발생시킬 수 있습니다. 많은 수의 스레드가 동시에 실행될 경우, 이 오버헤드가 성능에 영향을 줄 수 있습니다.
MySQL의 원자적 연산
멀티스레드 환경에서도 MySQL은 원자적 연산을 보장합니다. 트랜잭션과 락 메커니즘을 사용하여 여러 스레드가 동시에 데이터베이스에 접근할 때도 데이터 무결성을 유지합니다.
트랜잭션: MySQL의 InnoDB 스토리지 엔진은 ACID 특성을 지원하여, 원자성, 일관성, 격리성, 지속성을 보장합니다. 트랜잭션 내의 모든 연산은 원자적으로 처리됩니다.
락 메커니즘: MySQL은 테이블 락, 행 락, 페이지 락 등의 다양한 락 메커니즘을 사용하여 여러 스레드가 동시에 동일한 데이터를 수정하려 할 때 데이터 일관성을 유지합니다.
따라서, MySQL은 멀티스레드 아키텍처를 통해 높은 동시성 처리를 가능하게 하며, 락과 트랜잭션을 통해 데이터의 일관성과 무결성을 유지합니다.
클러스터링과 샤딩의 차이점
클러스터링과 샤딩은 모두 데이터베이스의 성능을 향상시키고 고가용성을 보장하기 위해 사용되는 기술이지만, 그 구현 방식과 목적에는 차이가 있습니다.
클러스터링
개념: 클러스터링은 여러 데이터베이스 서버를 하나의 시스템처럼 동작하도록 구성하는 것입니다. 클러스터 내의 각 노드는 데이터를 복제하여 동일한 데이터를 가지고 있으며, 노드 간에 부하 분산 및 고가용성을 제공합니다.
목적: 고가용성 및 부하 분산
특징:
데이터 복제: 모든 노드가 동일한 데이터를 가지고 있으므로, 하나의 노드가 장애가 발생하더라도 다른 노드가 서비스를 지속할 수 있습니다.
부하 분산: 클러스터 내의 여러 노드로 읽기 요청을 분산시켜 성능을 향상시킬 수 있습니다.
장애 복구: 특정 노드에 장애가 발생해도 다른 노드가 동일한 데이터를 가지고 있으므로 서비스가 중단되지 않습니다.
샤딩
개념: 샤딩은 데이터베이스를 여러 서버에 분산 저장하는 방식입니다. 각 서버(샤드)는 전체 데이터의 일부만을 저장하며, 특정 데이터는 특정 샤드에만 존재합니다.
목적: 수평적 확장성 및 대규모 데이터 처리
특징:
데이터 분할: 데이터를 여러 샤드로 분할하여 저장하므로, 데이터가 특정 샤드에만 존재합니다. 예를 들어, 사용자 ID에 따라 데이터를 분할할 수 있습니다.
수평적 확장성: 새로운 샤드를 추가하여 쉽게 확장할 수 있습니다. 데이터의 양이 증가할수록 샤드를 추가하여 처리할 수 있습니다.
성능 향상: 데이터의 양이 분산되므로, 각 샤드는 처리해야 할 데이터 양이 줄어들어 성능이 향상됩니다.
복잡성 증가: 데이터 분할 및 쿼리 라우팅 등 복잡한 로직을 관리해야 하므로 구현이 어렵습니다.
클러스터링과 샤딩의 차이점
데이터 저장 방식:
클러스터링: 모든 노드가 동일한 데이터를 가지고 있습니다.
샤딩: 각 샤드는 데이터의 일부만 저장하며, 전체 데이터가 각 샤드에 분산되어 저장됩니다.
목적:
클러스터링: 고가용성 및 부하 분산을 위해 사용됩니다.
샤딩: 수평적 확장성과 대규모 데이터 처리를 위해 사용됩니다.
구현 난이도:
클러스터링: 구현이 상대적으로 쉽고, 많은 RDBMS가 기본적으로 지원합니다.
샤딩: 구현이 복잡하고, 데이터 분할 및 쿼리 라우팅 등 추가적인 로직이 필요합니다.
관계형 데이터베이스에서의 클러스터링과 샤딩
클러스터링: 관계형 데이터베이스는 클러스터링을 통해 고가용성과 부하 분산을 제공합니다. 예를 들어, MySQL의 InnoDB Cluster, PostgreSQL의 Patroni 등이 있습니다. 이러한 시스템은 데이터 복제와 자동 장애 복구를 통해 고가용성을 보장합니다.
샤딩: 관계형 데이터베이스에서 샤딩은 매우 복잡한 작업입니다. 이는 데이터의 일관성과 무결성을 유지하면서 데이터를 분할하고 관리해야 하기 때문입니다. 관계형 데이터베이스는 일반적으로 정교한 트랜잭션 관리와 강력한 데이터 일관성을 제공하므로, 데이터를 여러 샤드로 분할하는 것이 쉽지 않습니다. MySQL의 경우 MySQL Fabric, PostgreSQL의 경우 Citus 등 샤딩을 지원하는 확장 도구가 있지만, 여전히 구현과 관리가 복잡합니다.
결론적으로, 클러스터링은 관계형 데이터베이스에서 고가용성과 부하 분산을 쉽게 구현할 수 있는 반면, 샤딩은 복잡하고 관리가 어려운 작업입니다. 따라서 관계형 데이터베이스에서의 샤딩은 필요성이 크지 않은 경우가 많으며, 필요할 경우에는 매우 신중한 계획과 관리가 필요합니다.
빠른 성능: 메모리 기반의 빠른 읽기/쓰기 성능.
간편한 구현: SETNX와 EXPIRE 명령어로 간단하게 락 구현.
TTL 지원: 자동 만료 기능으로 데드락 방지.
Redlock 알고리즘: 분산 환경에서 신뢰할 수 있는 락 구현.
데이터 무결성 보장: 트랜잭션과 잠금 메커니즘을 통해 데이터의 무결성과 일관성 보장.
행 수준 잠금: SELECT ... FOR UPDATE를 통해 특정 행을 잠글 수 있음.
복잡한 락 구현: 여러 데이터베이스 인스턴스 간의 락을 구현하기 어려움.
성능 저하 가능성: 높은 동시성 요청 시 성능 저하 가능.
Redis의 수평적 확장은 클러스터링과 리플리케이션을 통해 이루어집니다:
Redis 클러스터는 데이터를 여러 노드에 분산 저장하여 고가용성과 수평적 확장을 지원합니다.
각 노드는 데이터의 일부를 담당하며, 데이터 분산을 자동으로 관리합니다.
노드 간에 데이터 일관성을 유지하며, 분산 환경에서의 장애 복구도 자동으로 처리합니다.
Redis는 Master-Slave 구조를 사용하여 데이터를 복제합니다.
Master 노드는 쓰기 작업을 처리하고, Slave 노드는 읽기 작업을 처리하여 읽기 성능을 확장할 수 있습니다.
복제본 간의 데이터 일관성을 유지하며, Master 노드 장애 시 자동으로 Failover를 수행할 수 있습니다.
MySQL의 수평적 확장은 주로 다음 두 가지 방식으로 이루어집니다:
데이터를 여러 샤드(Shard)로 나누어 분산 저장하는 방식입니다.
각 샤드는 서로 다른 데이터베이스 인스턴스에 저장되며, 특정 기준(예: 사용자 ID, 지역 등)에 따라 데이터가 분할됩니다.
샤딩은 애플리케이션 레벨에서 관리가 필요하며, 샤드 간의 데이터 일관성 유지가 어려울 수 있습니다.
데이터 재분배와 샤드 간 조인은 복잡하고 성능에 영향을 줄 수 있습니다.
데이터베이스의 데이터를 여러 복제본(Replica)으로 복제하여 읽기 부하를 분산시키는 방식입니다.
주로 Master-Slave 구조를 사용하여 Master에서 쓰기 작업을 처리하고, Slave에서 읽기 작업을 처리합니다.
복제본 간의 데이터 일관성 문제를 해결해야 하며, 쓰기 작업의 확장은 어렵습니다.
분산락의 정의와 구현
분산락은 여러 프로세스나 노드가 동일한 자원에 동시 접근을 못하도록 제어하는 메커니즘입니다.
단일 노드에서의 락
개념: 단일 Redis 인스턴스를 사용하여 락을 설정하고, 여러 메인 서버 인스턴스가 동일한 Redis 인스턴스에 접근하여 락을 설정하고 확인합니다.
특징: 단일 장애점이 될 수 있지만, 기본적인 분산락의 역할을 수행합니다.
예시: 메인 서버 A에서 락을 설정하면 메인 서버 B는 락이 설정되었음을 인지하고 자원에 접근하지 않습니다.
다중 노드에서의 락 (Redlock 알고리즘)
개념: 여러 Redis 노드에 락을 설정하여 신뢰성과 가용성을 높이는 방식입니다.
특징: 네트워크 분할이나 노드 장애 시에도 높은 신뢰성을 제공하는 분산락 구현 방식입니다.
예시: 여러 Redis 노드에 락을 설정하고, 과반수 이상의 노드에서 락 설정이 성공해야만 자원에 접근할 수 있습니다.
비교
단일 노드에서의 락:
장점: 구현이 간단하고 빠르게 설정 가능.
단점: 단일 장애점이 되어 노드 장애 시 시스템 전체가 영향을 받을 수 있음.
다중 노드에서의 락 (Redlock 알고리즘):
장점: 높은 신뢰성과 가용성 제공. 네트워크 분할이나 노드 장애 시에도 안정적으로 동작.
단점: 구현이 복잡하며, 여러 노드에 락을 설정하는 과정에서 오버헤드가 발생할 수 있음.