포스트

데이터 중심 애플리케이션 설계 리뷰


데이터중심 애플리케이션 설계 - 3년차 백엔드 개발자의 시각

이 책을 선택한 이유

소프트웨어 엔지니어 필독서 목록을 검색할 때마다 빠지지 않고 등장하는 책이 있었다. 바로 마틴 클레프만의 『데이터중심 애플리케이션 설계』였다. 소프트웨어 엔지니어 필수 서적, 월드 클래스 엔지니어가 되기 위해 읽어야할 12 가지 책 등등 국내, 해외를 가리지 않고 항상 필독서로 추천되기에 꼭 읽어봐야겠다고 생각했다.

3년차 백엔드 개발자로서 PostgreSQL 을 비롯한 여러 DB 엔진을 사용해왔고, OLTP, OLAP, 대량 데이터 처리 시스템 등을 주로 개발해왔다. 그럼에도 실무에서 마주하는 상황들 - 트랜잭션 격리 수준을 선택할 때의 고민, 대용량 데이터 처리 시 발생하는 성능 이슈, 배치 작업의 실패 복구 전략 등 - 에 대한 이론적 배경을 체계적으로 학습하고 싶었다. 무엇보다 “내가 경험해보지 못한 케이스들을 배우고 싶다”는 생각이 컸다. 지금까지는 주어진 환경에서 문제를 해결하는 데 급급했다면, 이제는 왜 이런 설계를 했는지, 다른 대안은 없었는지에 대해 더 깊이 생각해보고 싶었다.

3개월간의 험난한 여정

결론부터 말하면, 정말 어려웠다. Real MySQL 도 읽었고, 여러 쿼리 튜닝 경험이 있다보니 책을 나름대로 쉽게 읽을 수 있지 않을까 하는 자신이 있었는데, 그 자신은 점점 없어졌다. 국소적인 DBMS 에 대해서 다루는 책이 아니고, 정말 설계 레벨의 관점을 이야기하는 책이다. 혼자서는 꾸준하게 읽지 못할 것 같아서 스터디 멤버들과 1주일에 1장씩 읽기로 했고, 어느덧 주말 하루에 1장씩 읽는 것이 습관이 됐다(평일은 어쩌다보니 거의 읽을 틈이 안나더라;;)


특히 분산 시스템 파트에 들어가면서부터는 정말 고생했다. 한 문단을 읽고도 “이게 무슨 말이지?”하며 다시 읽기를 반복했다. 실무에서 PostgreSQL의 MVCC나 WAL(Write-Ahead Logging)을 다뤄본 경험이 있어서 3장 ‘저장소와 검색’ 부분은 비교적 수월했지만, 8장 ‘분산 시스템의 골칫거리’부터는 정말 난감했다(하지만 제일 추천). 책을 다 읽고 나서도 솔직히 절반 정도의 내용만 이해한 것 같다. 챕터 내에서도 “아, 이건 이해했다!” 하는 부분이 있는가 하면, 여러 번 읽어도 완전히 소화되지 않는 부분들이 있었다.

가장 큰 수확: 트레이드오프를 고려하는 사고방식

이 책에서 얻은 가장 큰 깨달음은 “There’s no free lunch” 라는 사고방식이었다. 모든 설계 결정에는 트레이드오프가 있다는 것을 체계적으로 학습할 수 있었다. 예전에는 “이 기능을 어떻게 구현하지?”에만 집중했다면, 이제는 “이 선택에는 어떤 트레이드오프가 있을까?”를 먼저 생각하게 되었다. 예를 들면, 읽기 부하를 줄이기 위해서 replica DB 를 하나 더 구성하는 경우에, replica 비용과 그 과정에서 쓰기, 읽기 불일치로 인해서 미래 시점을 본다거나 과거 시점을 본다거나 하는 문제들을 생각해볼 수 있게 됐다.

실무와 연결되는 순간들

1. 스토리지 엔진의 깊은 이해

가장 충격적이었던 부분은 B-tree vs LSM-tree 설명이었다. “B-tree는 빠른 읽기를 가능하게 하고, LSM-tree는 빠른 쓰기를 가능하게 한다” 라는 단순한 룰로 설명되는데, 이게 왜 PostgreSQL과 Cassandra가 다른 성능 특성을 갖는지 완벽하게 설명해줬다. PostgreSQL이 B-tree를 사용해서 읽기에 최적화되어 있고, 랜덤 쓰기가 많을 때 성능이 떨어지는 이유를 이제야 이해했다. 반면 Cassandra 같은 LSM-tree 기반 DB가 높은 쓰기 처리량을 자랑하는 이유도 명확해졌다. 실무에서 대용량 배치 작업 중 PostgreSQL 성능이 급격히 떨어졌던 경험이 있는데, 그때는 그냥 “DB가 느려졌네”로만 생각했었다. 이제는 랜덤 쓰기로 인한 디스크 I/O 문제였다는 걸 이해할 수 있다.

2. 데이터베이스 선택의 새로운 기준

“유행에 따라 데이터베이스를 선택하지 말고, 애플리케이션이 데이터를 어떻게 사용하는지에 따라 선택하라” - 이 문장이 정말 와닿았다. 언제나 기술을 선택해야 하는 이유의 본질에 대해서 집중해야 한다.

  • 복잡한 조인이 많고 ACID 트랜잭션이 중요하면 관계형 DB
  • 유연한 스키마가 필요하고 문서 단위로 읽는 패턴이 많으면 문서형 DB
  • 복잡한 관계 데이터를 다뤄야 하면 그래프 DB

이런 이유를 잘 찾아서 기술을 선택해야 하는 것이 AI 가 아니라 사람이 필요한 이유인 것 같다.

3. 트랜잭션과 격리 수준의 실질적 이해

7장 ‘트랜잭션’ 부분을 읽을 때가 가장 흥미로웠다. 평소 PostgreSQL 에서 BEGIN, COMMIT을 당연하게 사용했는데, Lost Updates, Write Skew, Phantom Reads 같은 경합 조건들에 대한 설명을 읽으니 진짜 이해가 되었다.


Serializable Snapshot Isolation (SSI)에 대한 설명도 인상 깊었다. 단순히 락을 거는 방식이 아니라 충돌을 감지해서 나중에 처리하는 낙관적 방식이라는 게 신선했다.

4. 복제 전략에 대한 체계적 이해

실무에서 Master-Slave 구성을 써봤지만, Single-leader, Multi-leader, Leaderless 복제 방식들의 트레이드오프를 체계적으로 비교한 건 처음이었다.

  • 동기 vs 비동기 복제의 차이점도 명확해졌다. 동기 복제는 강한 일관성을 보장하지만 가용성이 떨어지고, 비동기는 그 반대라는 걸 이론적으로 이해했다.
  • Quorum 읽기/쓰기도 흥미로운 개념이었다. N개 복제본 중 W개가 쓰기를 확인하고 R개가 읽기에 응답하면서 W + R > N을 만족시켜 일관성을 보장한다는 아이디어가 정말 영리하다고 생각했다.

5. 분산 시스템의 현실적 문제들

8장 ‘분산 시스템의 골칫거리’에서 가장 인상깊었던 건 “네트워크는 신뢰할 수 없다”는 전제였다.

클록 동기화 문제도 새로운 발견이었다. Time-of-day 클록과 Monotonic 클록의 차이, NTP 동기화로 인한 시간 역행 문제 등은 전혀 생각해보지 못한 부분이었다. 배치 시스템에서 타임스탬프 기반으로 순서를 보장하려고 했는데, 이런 문제들이 있다는 걸 알고 나니 더 신중해져야겠다는 생각이 들었다.

Split-brain 문제와 Fencing tokens도 흥미로웠다. 여러 노드가 동시에 리더라고 생각하는 상황을 방지하기 위해 토큰을 사용한다는 아이디어가 실용적이면서도 효과적이라고 느꼈다.
현실에서도 일을 하다보면 조직의 split brain 이 발생하는 것을 볼 수 있는데, 기계나 사람이나 모이면 똑같다고 생각했다.

6. 배치 vs 스트림 처리의 통합적 관점

10-11장에서 다룬 배치 처리와 스트림 처리는 현재 개발하고 있는 시스템과 직접적으로 연결되었다.

특히 Change Data Capture (CDC)Event Sourcing 패턴이 인상깊었다. CDC 는 서비스 운영간 데이터 분석을 위해 특정 데이터베이스에서 사용해본 적이 있다. OLTP 의 데이터를 BigQuery 로 CDC 를 이용해서 전달했다.


현재 외부 서비스로 데이터를 전송하는 배치 작업에서 실패 시 복구 로직을 고민하고 있는데, 멱등성(idempotency)정확히 한 번 처리(exactly-once processing)에 대한 설명이 실질적으로 도움이 되었다.

이해되지 않았던 부분들

솔직히 말하면 완전히 이해하지 못한 부분들이 꽤 많다.

  • 벡터 클록(Vector Clock)과 합의 알고리즘 부분은 여러 번 읽어도 머리에 들어오지 않았다. 특히 Raft나 Paxos 알고리즘에 대한 설명은 나중에 다시 공부해야할 것 같다.

  • Byzantine Fault ToleranceConsistent Hashing 같은 고급 개념들도 개념적으로만 이해했을 뿐, 실제 적용 시나리오를 그려보기는 어려웠다.

  • 그외 기타 등등.. 아마 절반정도..

실제로 해당 시스템을 다뤄보지 않아서 그런 것 같다. 이론만으로는 한계가 있다는 걸 느꼈다.

예상과 달랐던 점들

사실 이 책을 읽기 전에는 “실제 기업들이 어떤 기술을 사용하는지 알 수 있을 것”이라고 기대했다. Netflix, Twitter 등의 사례가 나오긴 하지만, “우리 회사에서 바로 적용할 수 있는 기술”을 기대했다면 실망할 수 있다.
이 책은 근본적인 원리와 개념에 중점을 둔다. 당장 써먹을 수 있는 How-to가 아니라 Why에 대한 책이다. 경우에 따라서는 실무와는 거리가 먼 이야기라고 느끼는 사람도 있는 것 같다.

누구에게 추천할까?

3년차 이상의 경험을 가진 백엔드 엔지니어, 아키텍트에게 강력 추천한다. 특히 이런 분들에게 유용할 것 같다:

  • 단순한 CRUD를 넘어서 시스템 아키텍처에 관심이 있는 개발자
  • 데이터베이스 내부 동작 원리를 깊이 이해하고 싶은 개발자
  • 분산 시스템이나 대용량 처리에 대한 기초 지식을 체계적으로 쌓고 싶은 개발자

하지만 정말 어렵다는 점은 미리 알고 시작하자. 특히 다양한 문제를 만나보고, 고민해보지 못한 신입 개발자에게는 절대 추천할 책이 아니라고 생각한다.
사실 1년 전에 읽으려고 시도했다가 바로 실패한 본인 이야기임

핵심 원칙들

책에서 얻은 핵심 원칙들을 정리하면:

  • 실패를 전제로 설계하라: 복제, 재시도, 우아한 성능 저하를 고려하자
  • 중요한 지표를 측정하라: 평균이 아닌 백분위수 지연시간(p95, p99)을 모니터링하자
  • 적절한 데이터 모델을 선택하라: 데이터 접근 패턴에 맞는 DB를 선택하자
  • 스토리지 엔진을 이해하라: B-tree(읽기 최적화) vs LSM-tree(쓰기 최적화)
  • 트랜잭션을 현명하게 사용하라: 분산 트랜잭션은 최대한 피하고 대안을 고려하자
  • 항상 트레이드오프를 고려하라: 완벽한 해결책은 없다. 상황에 맞는 최선의 선택을 하자

마치며

3개월간의 긴 여정을 마치며 드는 생각은 “어려웠지만 읽기를 정말 잘했다”는 것이다. 당장 업무에 써먹을 수 있는 실용적인 내용은 많지 않지만, 개발자로서의 사고 깊이가 한층 깊어진 것 같다. 가장 큰 수확은 트레이드오프를 고려하는 사고방식을 갖게 된 것이다. 이제는 “분산 트랜잭션이 정말 필요한가, 최종적 일관성으로도 충분하지 않을까?” 같은 질문들을 더 체계적으로 할 수 있게 되었다. 완전히 이해하지 못한 부분들이 많아서 아쉽긴 하지만, 그것도 나름의 가치가 있다고 생각한다. “내가 모르는 영역이 이렇게 많구나”를 알게 되는 것도 성장의 과정이니까.


마지막으로, 이 책은 “완독”이 목표가 아니라 “이해”가 목표인 책이라고 생각한다. 다 읽었다고 해서 끝이 아니라, 앞으로 실무에서 마주하는 상황들과 연결지어가며 계속 참고해야 할 평생 레퍼런스 북이다.
다 읽으면 중고로 팔려고 했는데 못 팔 것 같다
내 책상 옆에도 여전히 꽂혀 있고, 시스템 설계나 기술 선택에 고민이 생길 때마다 관련 챕터를 다시 찾아보려고 한다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.