콘텐츠로 이동

L8 데이터베이스 입구

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

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

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

L8은 애플리케이션의 상태를 오래 보존하고, 여러 사용자가 동시에 바꾸고, 장애 이후에도 설명 가능한 상태로 복구하는 법을 다룬다. 프론트엔드에서 상태는 화면을 다시 그리기 위한 재료에 가깝지만, 데이터베이스의 상태는 주문, 결제, 재고, 권한처럼 서비스가 책임져야 하는 사실이다.

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

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

2. 이미 알고 있는 것에서 출발하기

섹션 제목: “2. 이미 알고 있는 것에서 출발하기”

React나 React Native에서 상태를 다뤄본 경험은 DB 학습에 꽤 많이 이어진다.

  • 상태 정규화: 중첩된 클라이언트 상태를 byIdids로 나누는 감각은 DB 모델링의 정규화와 닮아 있다. 하나의 사실을 어디에 둘지 정하는 문제다.
  • Optimistic UI: 화면에서는 먼저 성공한 것처럼 보여주고 실패하면 되돌릴 수 있다. DB에서는 그 되돌림을 감으로 처리하지 않고, 트랜잭션과 제약 조건으로 보장해야 한다.
  • API 실패 처리: 프론트엔드에서 500, timeout, retry를 다뤘다면 “서버가 중간에 실패했을 때 DB에는 무엇이 남는가”라는 질문으로 확장할 수 있다.
  • Cache invalidation: 클라이언트 캐시가 언제 낡는지 고민해봤다면, Replica 지연, Redis 캐시, CDC/Outbox 같은 주제도 “원본 상태와 복사본 상태의 시간차”로 이해할 수 있다.

즉, 완전히 낯선 세계로 들어가는 것이 아니다. 다만 L8에서는 상태가 화면 안에서 끝나지 않고, 여러 프로세스와 여러 서버, 장애와 복구를 지나도 유지되어야 한다.

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

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

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

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

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

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

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

  • RDS가 무엇을 대신 운영해주는지 감이 없다면 content/topics/L3/rds-basics.md를 먼저 읽는다. 특히 Multi-AZ, Read Replica, Connection Pool은 L8의 복제와 운영 판단으로 이어진다.
  • SQL의 SELECT, INSERT, UPDATE, DELETE, JOIN이 낯설다면 간단한 CRUD 예제를 먼저 손으로 실행해본다. L8은 SQL 문법 강의가 아니라 그 SQL이 저장소에서 어떤 비용과 정합성 문제를 만드는지 보는 레이어다.
  • 프론트엔드 상태 정규화, API 실패 처리, optimistic UI, 캐시 무효화 경험은 그대로 가져와도 된다. 다만 DB에서는 “사용자에게 어떻게 보이는가”뿐 아니라 “영구 저장된 사실이 맞는가”까지 판단해야 한다.
  1. Transaction Basics - 여러 DB 작업을 하나의 성공/실패 단위로 묶어 정합성을 지키는 관점을 연다.
  2. DB Modeling - 어떤 사실을 어떤 테이블과 관계로 저장할지 정하고, 중복과 불일치를 줄이는 구조를 배운다.
  3. DB Index & Query Optimization - 데이터가 많아질수록 조회가 왜 느려지고, 인덱스와 실행 계획으로 어떻게 비용을 줄이는지 본다.
  4. DB Replication & Sharding - 한 대의 DB가 읽기, 쓰기, 가용성, 용량 한계에 부딪힐 때 복제와 분할로 어떻게 확장하는지 이해한다.
  5. Redis 내부 원리 & ElastiCache 운영 - DB 앞에 캐시를 둘 때 성능은 좋아지지만, 원본 상태와 캐시 상태의 차이를 어떻게 다룰지 배운다.
  6. CDC & Outbox 패턴 - DB 변경을 이벤트로 내보낼 때 유실, 중복, 순서 문제를 어떻게 줄이는지 본다.

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

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

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

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

막히는 느낌보통 부족한 전제돌아갈 문서
RDS, Replica, Multi-AZ가 계속 섞인다관리형 DB 운영 개념content/topics/L3/rds-basics.md
트랜잭션이 단순한 try/catch처럼 느껴진다영구 저장 상태와 부분 처리 실패의 차이content/topics/L8/transaction-basics.md
정규화가 프론트엔드 상태 설계와 연결되지 않는다하나의 사실을 한 곳에 둔다는 상태 모델링content/topics/L8/db-modeling.md
인덱스가 그냥 빠르게 해주는 옵션처럼 느껴진다조회 조건, 정렬, 쓰기 비용의 균형content/topics/L8/db-index-query-optimization.md
복제와 샤딩이 같은 확장으로 보인다읽기 분산, 쓰기 분산, 가용성의 구분content/topics/L8/db-replication-sharding.md
  • 프론트엔드의 optimistic UI가 실패했을 때 화면을 되돌리는 일과, DB가 부분 처리 상태를 남기지 않는 일이 어떻게 다른지 설명할 수 있다.
  • “하나의 사실은 한 곳에 둔다”는 상태 정규화 감각을 테이블 설계 문제로 옮겨볼 수 있다.
  • 느린 API를 볼 때 네트워크만이 아니라 DB 조회 비용과 인덱스 가능성을 함께 의심할 수 있다.
  • 캐시나 Replica가 원본 DB와 잠깐 다를 수 있다는 사실을 받아들이고, 그 차이가 위험한 데이터인지 질문할 수 있다.
  • 막히면 content/topics/L3/rds-basics.md로 돌아가 RDS 운영 개념을 다시 확인해야 한다는 것을 안다.

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