콘텐츠로 이동

L8 데이터베이스 입구

분류: Layer 8 - 데이터베이스

1. 이 레이어는 무엇을 가능하게 하나

섹션 제목: “1. 이 레이어는 무엇을 가능하게 하나”

L8은 애플리케이션의 상태를 오래 보존하고, 여러 사용자가 동시에 바꾸고, 장애 이후에도 설명 가능한 상태로 복구하는 법을 다룬다. 화면 상태와 달리 데이터베이스의 주문, 결제, 재고, 권한은 여러 요청과 장애를 지나도 서비스가 책임져야 하는 사실이다.

그래서 이 레이어의 질문은 “SQL을 어떻게 쓰는가”에서 끝나지 않는다. 데이터가 맞는 상태로 남아 있는가, 조회가 왜 느려지는가, 동시에 들어온 요청은 어떤 순서로 처리되는가, 서버나 DB가 죽은 뒤 무엇을 믿고 복구할 수 있는가, 한 대의 DB로 버티지 못할 때 어디를 나누어야 하는가를 함께 본다.

첫 토픽인 Transaction Basics는 이 질문 중 정합성과 동시성을 깊게 다루기 때문에 처음부터 어렵게 느껴질 수 있다. 이 문서는 그 내용을 미리 요약하지 않고, L8 전체를 볼 때 어떤 렌즈를 들고 들어가면 되는지 잡아주는 입구다.

2. 영구 상태가 지켜야 하는 계약

섹션 제목: “2. 영구 상태가 지켜야 하는 계약”

영구 상태는 값을 저장하는 행위보다 “어떤 사실을 언제 확정하고, 누가 바꿀 수 있으며, 실패 뒤 무엇을 복구할 것인가”라는 계약이 먼저다. 데이터베이스는 이 계약을 테이블 하나로 자동 완성하지 않는다. 애플리케이션과 DB가 원본, 제약 조건, 트랜잭션 경계, 복구 기준을 함께 정해야 한다.

  • 원본과 불변식: 주문 금액, 재고 수량, 권한처럼 하나의 기준이 필요한 사실은 정본 위치와 허용 상태를 정해야 한다. 테이블 관계와 UNIQUE, CHECK, 외래키 같은 제약이 잘못된 상태의 저장을 막는다.
  • 커밋 경계: 여러 변경이 하나의 업무 사실이라면 함께 확정되거나 함께 버려져야 한다. 트랜잭션은 부분 성공을 “설명 가능한 실패”로 바꾸는 경계다.
  • 동시성과 재시도: 재고 1개를 두 요청이 동시에 읽거나 timeout 뒤 같은 주문 요청이 다시 오면, 단일 요청만 볼 때는 없던 충돌과 중복이 생긴다. 격리 수준, lock, idempotency key, 제약 조건이 이 경계를 나눠 맡는다.
  • 복구와 복사본: WAL과 backup은 장애 후 원본을 복구하는 경로이고, Replica·캐시·CDC는 원본을 복사해 읽기와 연동을 돕는 경로다. 복사본은 지연될 수 있으므로 허용 가능한 RPO(복구 시점 목표)와 freshness를 구분해야 한다.

작은 재고 예시로 보면 네 계약이 연결된다. stock = 1일 때 두 주문이 모두 성공하지 않도록 제약과 동시성 제어가 필요하고, 주문과 재고 차감은 같은 커밋 경계에 있어야 한다. 커밋 성공 뒤 서버가 죽어도 WAL에서 복구되어야 하며, 읽기 Replica가 잠시 stock = 1을 보여줄 수 있다면 주문 판정은 Replica가 아니라 원본에서 해야 한다.

데이터베이스를 볼 때는 여섯 가지 질문을 반복해서 던지면 좋다.

첫째, 무엇을 상태로 저장하는가. 임시 계산 결과인지, 비즈니스 사실인지, 캐시에 둘 값인지 구분해야 한다.

둘째, 무엇이 정합성을 깨뜨리는가. 두 작업 중 하나만 성공하거나, 중복된 데이터 중 일부만 바뀌거나, 동시에 들어온 요청이 같은 값을 덮어쓰면 상태가 어긋난다.

셋째, 조회 비용은 어디서 생기는가. DB는 필요한 행만 마법처럼 찾지 않는다. 인덱스가 없거나 쿼리 형태가 맞지 않으면 많은 행과 페이지를 읽는다.

넷째, 동시성은 어떤 실패 모드를 만든다. 여러 요청이 같은 데이터를 읽고 쓰면 순서, 잠금, 격리 수준, 재시도 정책이 모두 설계 요소가 된다.

다섯째, 장애 복구는 무엇을 기준으로 판단하는가. 커밋된 변경과 버려야 할 변경을 구분할 수 있어야 DB가 장애 이후에도 설명 가능한 상태로 돌아온다.

여섯째, 확장은 무엇을 포기하게 만드는가. 복제는 읽기와 가용성을 돕지만 지연을 만든다. 샤딩은 용량과 쓰기 확장을 돕지만 쿼리와 운영을 어렵게 만든다.

  • RDS가 무엇을 대신 운영해주는지 감이 없다면 content/topics/L3/rds-basics.mdx를 먼저 읽는다. 특히 Multi-AZ, Read Replica, Connection Pool은 L8의 복제와 운영 판단으로 이어진다.
  • SQL의 SELECT, INSERT, UPDATE, DELETE, JOIN이 낯설다면 간단한 CRUD 예제를 먼저 손으로 실행해본다. L8은 SQL 문법 강의가 아니라 그 SQL이 저장소에서 어떤 비용과 정합성 문제를 만드는지 보는 레이어다.
  • 일부 예제는 TypeScript/NestJS 형태로 나오지만, 핵심은 프레임워크 사용법이 아니라 DB 경계와 실패 모드다. 코드가 낯설면 SQL과 상태 변화만 따라가도 된다.
  • 요청 실패, 재시도, 캐시 무효화 경험은 출발점으로 삼을 수 있다. L8에서는 이를 정본 데이터, 커밋 경계, 복사본 지연, 장애 복구 문제로 확장한다.

L8 데이터베이스 입구 학습 순서

  1. Transaction Basics

    여러 DB 작업을 하나의 성공/실패 단위로 묶어 정합성을 지키는 관점을 연다.

  2. DB Modeling

    어떤 사실을 어떤 테이블과 관계로 저장할지 정하고, 중복과 불일치를 줄이는 구조를 배운다.

  3. DB Index & Query Optimization

    데이터가 많아질수록 조회가 왜 느려지고, 인덱스와 실행 계획으로 어떻게 비용을 줄이는지 본다. 첫 회독에서는 Seq Scan, Index Scan, 복합 인덱스, EXPLAIN의 rows/actual 감각까지만 잡아도 된다. planner knob, work_mem, bloat, HOT는 선택 심화로 이름과 실패 신호만 보고 넘어간다.

  4. DB Replication & Sharding

    한 대의 DB가 읽기, 쓰기, 가용성, 용량 한계에 부딪힐 때 복제와 분할로 어떻게 확장하는지 이해한다.

  5. Redis 내부 원리 & ElastiCache 운영

    캐시 사용법을 넘어 Redis의 메모리 인코딩과 이벤트 루프, self-managed RDB/AOF, Cluster hash slot, ElastiCache의 backup·Multi-AZ 경계와 운영 지표를 구분해 배운다.

  6. CDC & Outbox 패턴

    DB 변경을 이벤트로 내보낼 때 유실, 중복, 순서 문제를 어떻게 줄이는지 본다.

처음에는 모든 세부 구현을 외우려 하지 않아도 된다. 각 토픽이 “정합성”, “구조”, “조회 비용”, “확장”, “상태 복사” 중 어느 문제를 다루는지만 놓치지 않으면 된다.

6. 어렵게 느껴지는 지점과 돌아갈 곳

섹션 제목: “6. 어렵게 느껴지는 지점과 돌아갈 곳”

막힐 때는 먼저 어떤 종류의 어려움인지 이름 붙이고, 그에 맞는 문서로 돌아가면 된다.

6. 어렵게 느껴지는 지점과 돌아갈 곳 비교

RDS, Replica, Multi-AZ가 계속 섞인다

보통 부족한 전제: 관리형 DB 운영 개념

돌아갈 문서: `content/topics/L3/rds-basics.mdx`

트랜잭션이 단순한 try/catch처럼 느껴진다

보통 부족한 전제: 영구 저장 상태와 부분 처리 실패의 차이

돌아갈 문서: `content/topics/L8/transaction-basics.mdx`

하나의 사실을 어디에 둬야 할지 헷갈린다

보통 부족한 전제: 중복과 불일치를 줄이는 상태 모델링

돌아갈 문서: `content/topics/L8/db-modeling.mdx`

인덱스가 그냥 빠르게 해주는 옵션처럼 느껴진다

보통 부족한 전제: 조회 조건, 정렬, 쓰기 비용의 균형

돌아갈 문서: `content/topics/L8/db-index-query-optimization.mdx`

복제와 샤딩이 같은 확장으로 보인다

보통 부족한 전제: 읽기 분산, 쓰기 분산, 가용성의 구분

돌아갈 문서: `content/topics/L8/db-replication-sharding.mdx`

Redis 문서에서 event loop, AOF, hash slot이 갑자기 어렵다

보통 부족한 전제: 캐시 사용 패턴과 복제/샤딩의 기본 모델

돌아갈 문서: `content/topics/L6/redis-cache-basics.mdx`, `content/topics/L8/db-replication-sharding.mdx`

CDC와 Outbox에서 broker, consumer, slot이 섞인다

보통 부족한 전제: 이벤트 기본기, 트랜잭션 경계, 복제 로그 위치

돌아갈 문서: `content/topics/L6/eda-basics.mdx`, `content/topics/L8/transaction-basics.mdx`, `content/topics/L8/db-replication-sharding.mdx`

7. 들을 준비가 된 상태 체크

  • 요청 실패와 영구 저장 상태의 부분 커밋을 나눠 설명할 수 있다
  • "하나의 사실은 한 곳에 둔다"는 원칙을 테이블 설계 문제로 옮겨볼 수 있다
  • 느린 API를 볼 때 네트워크만이 아니라 DB 조회 비용과 인덱스 가능성을 함께 의심할 수 있다
  • 캐시나 Replica가 원본 DB와 잠깐 다를 수 있다는 사실을 받아들이고, 그 차이가 위험한 데이터인지 질문할 수 있다
  • 막히면 `content/topics/L3/rds-basics.mdx`로 돌아가 RDS 운영 개념을 다시 확인해야 한다는 것을 안다

L8 데이터베이스 레이어는 애플리케이션의 상태를 “저장했다”에서 끝내지 않고, 맞게 남기고, 빠르게 찾고, 동시에 바꾸고, 장애 후 복구하고, 커져도 운영할 수 있게 만드는 사고 모델을 배운다.