1. Reliable, Scalable, and Maintainable Applications
신뢰성, 확장성, 유지보수성
- Haram Lee
- 2026-03-24
- studies / Topics / DDIA
Martin Kleppmann, 『Designing Data-Intensive Applications』(O’Reilly, 2017)를 읽으며 정리한 노트. 한국어판 『데이터 중심 애플리케이션 설계』의 번역 용어를 주로 따랐고, 내용은 책을 요약한 것이며 그림은 개념만 다시 그렸음.
1.1 Thinking About Data Systems
- 목표: 특정 목적에 어떤 기술이 적합한지 결정하고, 좋은 애플리케이션 아키텍처의 기반을 만들기 위해 도구를 조합하는 방법을 이해하는 능력을 기른다
- 데이터 중심적 vs 계산 중심적
- 주된 문제: 데이터 양, 데이터 복잡성, 데이터가 변하는 속도 등 vs CPU 사이클
- 요즘 애플리케이션은 DB 하나가 아니라 여러 도구를 애플리케이션 코드로 엮어서 하나의 데이터 시스템을 만듦
flowchart TD client["Client Request"] --> app["Application Code"] app --> cache["In-memory Cache"] app --> db["Primary Database"] app --> search["Full-text Index"] app --> queue["Message Queue"]
- 기능적 요구사항: 애플리케이션이 처리하는 다양한 작업
- 비기능적 요구사항: 보안, 신뢰성, 법규 준수, 확장성, 호환성, 유지보수성
1.2 Reliability
- 사용자가 기대한 기능 수행(expected)
- 사용자가 실수하거나 소프트웨어를 예상치 못한 방식으로 써도 견딤(fault tolerance; resiliency)
- 예상된 부하와 데이터 양에서 필요한 사용 사례를 충분히 만족함
- 허가되지 않은 접근과 오남용을 막음(protection)
- 하드웨어 장애
- 대응: 하드웨어 구성 요소마다 중복(redundancy)을 추가
- 데이터와 부하가 작을 땐 이걸로 충분했지만, 장비 수가 늘면서 하드웨어 결함 자체도 늘어남
- 소프트웨어 장애
- 그래서 소프트웨어 내결함성 기술과 하드웨어 중복을 함께 써서 장비 하나가 통째로 죽어도 버티는 시스템으로 가는 중
- 이런 시스템은 한 번에 한 노드씩 패치할 수 있어서 전체 중단 없이 운영 가능
- 정교한 테스트, process isolation, 재시작 허용, 시스템 동작 측정과 모니터링이 예방에 도움
- 인적 오류
- 애초에 실수할 여지를 줄이는 설계: 잘 만든 추상화, API, 관리 인터페이스
- 실수가 나도 빨리 복구할 수 있게: 설정 롤백, 점진적 롤아웃, 데이터 재계산 도구
- 성능 지표와 오류율 같은 상세하고 명확한 모니터링
1.3 Scalability
- 확장성: 증가한 부하에 대처하는 시스템 능력
- 부하는 부하 매개변수로 표현함
- e.g. 웹 서버의 초당 요청 수, DB 읽기 대 쓰기 비율, 대화방의 동시 활성 사용자, 캐시 적중률
e.g. Twitter 홈 타임라인
- 읽을 때 합치기: 트윗은 전역 컬렉션에 넣기만 하고, 타임라인을 요청하면 팔로우하는 사람들의 트윗을 모아 시간순으로 합침
- 쓸 때 퍼뜨리기(fan-out): 사용자별 타임라인 캐시를 두고, 트윗을 쓰면 팔로워 각자의 캐시에 넣어 둠. 그래서 읽기가 싸짐
- 핵심 부하 매개변수는 사용자당 팔로워 분포 (fan-out 부하를 결정)
- 결론적으로 둘을 섞음: 팔로워가 매우 많은 사용자는 fan-out에서 빼고 읽을 때 1번 방식으로 합침
e.g. Hadoop 같은 배치 시스템과 온라인 시스템의 성능
- 배치 시스템은 처리량(throughput), 온라인 시스템은 응답 시간(response time)을 봄
- vs. latency: 응답 시간은 실제 처리 시간에 네트워크 지연과 큐 지연까지 포함. latency는 요청이 처리되기를 기다리며 쉬고 있는 시간이라, 응답 시간이 latency보다 항상 더 김
- 응답 시간은 단일 숫자가 아니라 분포로 봐야 함
- context switch, 패킷 손실과 TCP 재전송, GC pause, page fault 같은 것들로 가끔씩 튀기 때문
- 산술 평균, 백분위, 중앙값
- 백분위는 SLO(service level objective), SLA(service level agreement)에 주로 쓰임
- 선두 차단(head-of-line blocking): 느린 요청 몇 개 때문에 뒤의 요청 처리까지 밀림
확장 방식
- 용량 확장(scaling up) 또는 수직 확장(vertical scaling) vs 규모 확장(scaling out) 또는 수평 확장(horizontal scaling)
- 탄력성(elasticity): 부하 증가를 감지하면 컴퓨팅 자원을 자동으로 추가하는 특성
- stateless 서비스를 여러 장비에 배포하는 건 간단하지만, stateful 데이터 시스템을 여러 노드로 분산하는 건 복잡도가 훨씬 커짐
1.4 Maintainability
- 운용성(operability)
- 운영하기 편해야 함. 운영 중 일부는 자동화할 수 있고, 또 자동화해야 함
- 단순성(simplicity)
- 상태 공간 급증, 모듈 간 강한 커플링, 복잡한 의존성, 일관성 없는 명명, 성능용 해킹, 임시방편 같은 복잡성을 없애야 함
- 복잡할수록 변경할 때 버그가 생길 위험이 커지기 때문
- 우발적 복잡도를 없애는 최상의 도구는 추상화: 깔끔한 겉모습 뒤로 구현을 숨기고, 다른 곳에서도 재사용
- 발전성(evolvability): extensibility, modifiability, plasticity
- 요구사항은 끊임없이 변함. 조직 프로세스 측면에서는 agile한 작업 패턴이 변화에 적응하는 프레임워크가 됨