Key-Value & Document Store Physics
Key-Value 및 Document Store 메커니즘의 정의, 범위, 선행 지식, 학습 주제, 참고 근거를 정리한 CS&E 학습 노드입니다.
목차 보기22
1. Overview
키-값 및 문서 저장소(Key-Value & Document Store Physics)는 RDBMS의 엄격한 테이블 스키마와 무거운 조인(Join) 연산을 버리고, 극강의 읽기/쓰기 속도와 스키마 없는(Schemaless) 유연성을 획득하기 위해 탄생한 NoSQL의 두 가지 핵심 저장 엔진을 해부합니다.
학습자는 메모리 기반 캐시나 단순 식별자 매핑에 최적화된 **Key-Value Store (Redis, Memcached)**의 해시 테이블 물리 엔진과 단일 스레드 이벤트 루프 아키텍처를 뜯어봅니다. 나아가 JSON 등 복잡한 계층형 데이터를 하나의 단위로 묶어 저장하는 **Document Store (MongoDB, Couchbase)**의 BSON 물리 저장 구조와 집계 파이프라인(Aggregation Pipeline)을 해부합니다. 마지막으로 RDBMS의 B-Tree와 극명하게 대비되는, 쓰기 성능을 극한으로 끌어올린 **LSM Tree (Log-Structured Merge-Tree)**의 MemTable 및 SSTable 병합 메커니즘을 장악하여 대용량 트래픽 인프라 설계 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Key-Value Store: 시간 복잡도, 해시 충돌, Redis 아키텍처(단일 스레드, 인메모리, AOF/RDB 영속성), Memcached.
- Document Store: JSON/BSON 직렬화, 컬렉션(Collection)과 문서(Document), 임베딩(Embedding) vs 참조(Reference) 데이터 모델링, MongoDB 인덱스.
- 물리적 저장 엔진 (Storage Engines): B-Tree (RDBMS 읽기 최적화) vs LSM Tree (NoSQL 쓰기 최적화), MemTable, WAL, SSTable, Compaction.
- Use Cases: 세션 관리, 캐싱, 실시간 장바구니, 유연한 카탈로그 시스템.
Out-of-Scope
- Redis 클러스터링 및 센티넬 상세 구성: 고가용성 및 샤딩 클러스터 네트워크 설정 → 07-03 Scalability & High Availability 영역.
- 그래프 및 와이드 컬럼 스토어: Cassandra, Neo4j 등의 구조 → 06-02-02, 06-02-05 영역으로 위임.
Boundaries
- 임베딩(Embedding) vs 정규화(Normalization): RDBMS는 사용자 1명에 이메일 3개를 매핑할 때 테이블을 쪼갭니다(정규화). 반면 Document Store는 사용자 1명의 JSON 문서 안에
["email1", "email2", "email3"]배열을 통째로 쑤셔 넣습니다(임베딩). 임베딩은 조인(Join) 없이 한 번의 I/O로 전체 데이터를 가져오는 엄청난 읽기 속도를 제공하지만, 이메일이 수정될 때 해당 문서를 통째로 갱신해야 하는 페이로드(Payload) 오버헤드가 발생합니다. '함께 자주 조회되는 데이터는 함께 저장한다'는 Document 모델링의 제1원칙을 숙지해야 합니다.
3. Counterexample
- Redis Keys 명령어 남용으로 인한 전체 시스템 멈춤: 수백만 개의 캐시 키가 저장된 Redis 프로덕션 서버에서 특정 패턴의 키를 찾겠다며
KEYS *user*명령어를 실행. Redis는 단일 스레드(Single Thread)로 동작하므로, 이 1개의 명령어가 수백만 개 키를 풀스캔하는 몇 초 동안 다른 모든 Get/Set 요청이 차단(Blocking)되어 전체 웹 서버 타임아웃과 장애를 유발합니다.KEYS대신 비동기적 순회 명령어인SCAN을 사용해야 하는, 내부 아키텍처에 대한 무지가 부른 치명적 실수입니다. - MongoDB BSON 16MB 한계 폭발: 게시판 시스템을 Document DB로 설계하며, '게시글' 문서 안에 '댓글'들을 무한정 배열로 임베딩(
comments: [{...}, {...}])한 경우. 초기에는 조인 없이 빠르게 조회되어 좋았으나, 댓글이 만 개 이상 달리면서 단일 BSON 문서의 물리적 크기 제한(16MB)을 초과하여 더 이상 댓글이 달리지 않는(Insert 실패) 아키텍처 붕괴가 발생. 무한히 커질 수 있는 배열(Unbounded Array)은 임베딩이 아닌 쪼개기(참조)로 설계해야 합니다.
4. Prerequisites
- RDBMS 스토리지 엔진 (Basic): B-Tree 기반의 디스크 저장과 조인(Join) 개념. (06-01-04 RDBMS Implementation)
- JSON 데이터 구조 (Basic): 키-값 쌍 및 중첩 객체(Nested Object) 형태에 대한 이해.
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 궁극의 단순함과 속도, Key-Value Store (Redis Architecture)
- Why to Learn: RDBMS가 튜닝을 거쳐도 초당 수천~수만 건 처리에 그칠 때, 초당 수십만 건의 I/O를 가볍게 씹어먹으며 웹 서버의 캐시와 세션을 책임지는 Redis의 물리 엔진을 장악하기 위함입니다.
- What to Learn:
- Concepts: 해시 테이블(Hash Table), In-Memory 연산, 단일 스레드 이벤트 루프(Single-threaded Event Loop), 영속성 방어(AOF/RDB).
- Skills: Redis 자료구조(String, Hash, List, Set, Sorted Set) 선택, 원자적 연산(
INCR)을 통한 카운터 구현.
- How to Learn:
- 1단계: 인메모리 해시: 디스크 헤드의 물리적 이동(Seek Time) 없이, RAM에 거대한 해시맵을 펼쳐놓고 데이터를 즉시 꽂고 빼는 물리적 제약 해방을 해부합니다.
- 2단계: 단일 스레드의 마법: 다중 스레드 DB처럼 복잡한 락(Lock)이나 트랜잭션 충돌 관리 큐가 없습니다. 오직 1개의 스레드가 큐에 들어온 요청을 순서대로 매우 빠르게(메모리니까) 처리합니다. 이 때문에 트랜잭션 ACID 락 없이도 완벽한 원자성(Atomicity)을 달성하는 역학을 뜯어봅니다.
- Implement: 파이썬
select모듈을 이용한 단일 스레드 Key-Value 캐시 서버 스크래치 구현. 글로벌dict()객체 생성. 비동기 I/O 이벤트 루프로 클라이언트 접속 및SET key val,GET key명령어 파싱. 멀티스레드 락 없이도INCR연산 시 Race Condition이 발생하지 않는 구조적 특징 증명.
Recommended
Core Topic 02: 쓰기를 위해 B-Tree를 버리다, LSM Tree 아키텍처 (LSM Tree Physics)
- Why to Learn: RDBMS의 B-Tree는 데이터 삽입 시 디스크 곳곳을 무작위로 업데이트(Random I/O)하므로 대규모 쓰기에 쥐약입니다. 반면 카산드라, RocksDB 등 NoSQL이 채택한 LSM Tree가 쓰기 성능을 수백 배 폭발시키는 물리적 비결을 꿰기 위함입니다.
- What to Learn:
- Concepts: Random I/O vs Sequential I/O, MemTable(메모리 밸런스 트리), WAL(트랜잭션 로그), SSTable(Sorted String Table, 디스크 불변 블록), Compaction(병합).
- Skills: B-Tree(읽기 최적)와 LSM Tree(쓰기 최적)의 선택 트레이드오프 분석.
- How to Learn:
- 1단계: 디스크의 본질(순차 쓰기): SSD나 HDD 모두 '이곳저곳 조금씩 고치기'보다 '끝에 쭉 이어 쓰기'가 압도적으로 빠릅니다. LSM Tree는 업데이트가 들어오면 무조건 메모리 트리(MemTable)에 쓰고, 꽉 차면 디스크에 통째로 쏟아버리는(Flush, 순차 쓰기) 혁신적 I/O 역학을 해부합니다.
- 2단계: 컴팩션(Compaction): 계속 쓰기만 하면 같은 키에 대한 과거 데이터가 디스크에 파편처럼 쌓입니다(SSTable). 백그라운드 스레드가 이 여러 덩어리들을 모아 최신 값만 남겨 하나의 큰 덩어리로 뭉쳐주는 컴팩션(병합 정렬) 작업의 오버헤드를 뜯어봅니다.
- Implement: 파이썬 메모리 한정 LSM Tree 모사 스크립트.
MemTable(최대 5개 항목 수용하는 리스트 정렬 유지).put()으로 5개가 차면sstable_1.txt파일로 디스크 덤프 후 메모리 초기화. 디스크 덤프 파일이 3개가 되면, 백그라운드 병합 스크립트가 세 파일을 읽어 키 최신 버전만 남긴sstable_merged.txt를 생성하는 컴팩션 동작 원리 시연.
Practical
Core Topic 03: 객체를 찢지 말고 통째로 담아라, Document Store (MongoDB BSON)
- Why to Learn: 애플리케이션의 JSON 객체(Order 클래스 안에 Item 리스트 객체)를 RDBMS의 2차원 표로 매핑하기 위해 억지로 찢어야 하는 임피던스 불일치(Impedance Mismatch) 고통을 없애고 직관적인 개발 속도를 장악하기 위함입니다.
- What to Learn:
- Concepts: 컬렉션(Collection), 문서(Document), BSON(Binary JSON), 스키마리스(Schemaless/Dynamic Schema), ObejctId(
_id), 인덱스 구조(MongoDB는 B-Tree 사용). - Skills: MongoDB Aggregation Pipeline(
$match,$group,$project) 쿼리 매핑.
- Concepts: 컬렉션(Collection), 문서(Document), BSON(Binary JSON), 스키마리스(Schemaless/Dynamic Schema), ObejctId(
- How to Learn:
- 1단계: 데이터 단위의 확장: RDBMS에서는
사용자,주소,결제수단테이블 3개를 조인해서 화면을 그립니다. Document DB에서는주소와결제수단을사용자문서 안에 배열(Array)로 임베딩하여, 단 1번의 쿼리로 화면 렌더링 데이터를 퍼올리는 데이터 지역성(Locality)을 해부합니다. - 2단계: BSON 스토리지: 순수 JSON 텍스트 파싱은 너무 느립니다. MongoDB는 바이너리 형태(BSON)로 디스크에 저장하여, 데이터 타입(Date, Byte 등)을 보존하고 인덱스 스캔을 가속화하는 물리 엔진을 뜯어봅니다.
- 1단계: 데이터 단위의 확장: RDBMS에서는
- Implement: RDBMS 3개 테이블(사용자, 블로그포스트, 태그) 조인 결과를 통짜 JSON Document 1개로 변환해주는 파이썬 데이터 컨버터 스크립트. 반환된 JSON 덩어리의 구조를 출력하며 "이제 조인이 필요 없다"는 구조적 차이점 분석 주석 로깅.
Advanced
Core Topic 04: 자유방임이 초래한 쿼리 지옥, 스키마리스 데이터 모델링 (Schemaless Modeling)
- Why to Learn: "NoSQL은 스키마 설계가 필요 없다"는 착각에 빠져 대충 넣었다가, 추후 데이터 추출 시 기괴하게 느린 애플리케이션 코드를 양산하는 실패를 막고, 완벽히 **쿼리 주도(Query-Driven)**적인 모델링 역량을 장악하기 위해서입니다.
- What to Learn:
- Concepts: 쿼리 주도 설계(Query-driven Design), 임베딩(Embedding, 읽기 성능 중심), 참조(Referencing, 중복/수정 중심), 배열 팽창(Array Growth/Unbounded Array), 다형성 스키마(Polymorphic Pattern).
- Skills: 비즈니스 워크로드(조회 중심 vs 수정 중심)에 따른 NoSQL 스키마 결정.
- How to Learn:
- 1단계: 임베딩의 한계 (배열 팽창): 블로그 글 객체에 '좋아요 한 사람 목록'을 배열로 임베딩. 좋아요가 100만 개가 되면 16MB 한계를 뚫고 에러 발생. 데이터 크기가 무한히 늘어날 수 있는 1
관계는 반드시 참조(별도 Collection)로 끊어야 하는 물리적 한계를 해부합니다. - 2단계: 스키마 온 리드 (Schema on Read): 데이터를 넣을 때(Write)는 검사하지 않고 자유롭게 넣지만, 읽어서(Read) 애플리케이션 객체에 매핑할 때 스키마 에러가 터집니다. 결국 NoSQL 서버는 자유롭지만, Java/Python 애플리케이션 단의 데이터 유효성 검사 클래스가 그 짐을 무겁게 짊어져야 하는 트레이드오프를 뜯어봅니다.
- 1단계: 임베딩의 한계 (배열 팽창): 블로그 글 객체에 '좋아요 한 사람 목록'을 배열로 임베딩. 좋아요가 100만 개가 되면 16MB 한계를 뚫고 에러 발생. 데이터 크기가 무한히 늘어날 수 있는 1
- Implement: 데이터 모델링 비교 시뮬레이터. '쇼핑몰 주문 데이터' 요건 분석. 1) 모든 상품 정보가 복사되어 들어가는 '완전 임베딩' JSON 모델 (상품명 변경 시 과거 주문 내역의 이름은 안 바뀌는 장점/단점 존재). 2) 상품 ID만 저장하는 '참조' JSON 모델. 각각의 JSON 모델에서
update_product_name()요구사항 발생 시, 1번과 2번 중 어느 것이 시스템에 유리/불리한지 판정하여 텍스트 리포트 생성.
7. Terminology
8. References
Primary
- [P1] CS2023 - Information Management (IM) - Non-relational databases
- [P5] SFIA - Data Modeling and Design (DTAN) - NoSQL
Secondary
- [Designing Data-Intensive Applications] Martin Kleppmann - Storage and Retrieval (LSM Trees)
- [NoSQL Distilled] Pramod J. Sadalage, Martin Fowler - Aggregate Data Models
Industry
- [Redis Documentation] - Redis Persistence (AOF/RDB) & Single-thread Architecture
- [MongoDB Manual] - Data Modeling Introduction & Aggregation Pipeline
9. Final Checklist
Primary
- Redis가 멀티 스레드의 락(Lock) 없이도 완벽한 동시성 처리와 초고속 성능을 달성하는 이벤트 루프 구조를 설명할 수 있는가?
- Document Store에서 '임베딩(Embedding)'과 '참조(Reference)' 중 어느 것을 선택해야 하는지 쿼리 패턴을 기반으로 논증할 수 있는가?
Secondary
- RDBMS의 B-Tree 인덱스가 무작위 쓰기(Random I/O)로 인해 겪는 병목 현상과, LSM Tree의 순차 쓰기(Sequential I/O) 우위를 비교할 수 있는가?
- MongoDB의 BSON 포맷이 단순 JSON 텍스트와 비교해 쿼리 성능과 데이터 타입 표현에서 가지는 물리적 차이를 해부할 수 있는가?
Industry
- Redis의
KEYS명령어가 프로덕션 환경에서 장애를 유발하는 이유를 단일 스레드 관점에서 분석하고 대체 방안(SCAN)을 제시할 수 있는가? - Document 모델에서 배열이 끝없이 늘어나는(Unbounded Array) 설계가 16MB 한계를 초과하여 일으키는 시스템 붕괴 시나리오를 방어할 수 있는가?
태그
nosql-polyglotkey-value-document-store-physicskey-valuedocument-store-physicsdata-dbdatainformation-managementnosqlpolyglotkeyvalueno-sqldatabases