취미겸생업

[Architecture] 대규모 시스템에서의 데이터 베이스 본문

IT/Architecture

[Architecture] 대규모 시스템에서의 데이터 베이스

nohumb 2026. 7. 22. 23:05
SMALL

대규모 시스템

처리량

대규모 시스팀 설계 시 가장 중요한 요소 중 하나는 사용자 수이다.

얼마나 많은 사용자가 시스템을 사용할 것인지 파악할 때, 시스템 모니터링을 통해 하루의 동시 접속량과 동시 접속자의 요청 수를 파악하는 것이 중요하다

TPS(Transactions Per Scond)

TPS는 초당 처리되는 트랜잭션의 수를 나타내는 지표이다. 대규모 시스템이 얼마나 많은 요청을 동시에 처리할 수 있는지를 나타낸다.

  • 시스템은 TPS를 견딜 수 있어야 한다
  • 일간 접속량이 아닌 특정 시간대의 가장 큰 TPS를 파악해야 한다
    • 즉, 시스템이 예상치 못한 최대 부하를 견딜 수 있도록 해야 한다
    • ex) 시스템이 오전 9시에 초당 200건의 요청을 처리한다면, 200건의 1.5배인 300건을 처리할 수 있도록 설계하는 것이 바람직하다
  • 예상치 못한 이벤트로 인해 설계 이상의 트래픽이 몰릴 경우 시스템의 중단을 막기 위해 대비해야 한다
    • 애플리케이션의 수를 늘리기
    • 오류 상황에서 사용자의 대기열을 설정하기
    • 자동 스케일링으로 시스템의 자원을 동적으로 할당하여 부하를 분산하기

조회 최적화

시스템이 읽기 전용인지, 쓰기 및 업데이트를 위한 것인지를 파악해야 한다. 데이터 제공 및 저장에서 가장 많은 시간을 소모하는 것은 대부분 DB에서 데이터를 조회하거나 쓰는 것이기 때문에, 요청 종류에 따라 이 부분의 허들을 최소화해야 한다.

캐시 전략

  • 읽기 요청 최적화 (캐싱)
    • 캐시를 통해 자주 사용되는 데이터를 미리 로드해서 DB 부하 최소화
    • 엣지 캐싱, 즉 사용자와 가장 가까운 곳에서 캐싱하여 네트워크 지연 최소화, UX 향상
    • 효율적인 캐시 갱신 정책을 통해 효율성 극대화 ex) 변경의 빈도에 따른 유효기간 설정이나 캐시 무효화 시점 설정
    • 데이터의 유효성을 지속적으로 검증
  • 캐싱 시 유의사항
    • 인덱스를 타기 힘든 복잡한 형태의 데이터는 Query보다 메모리(로직 처리 함수)에서 필터링하는게 빠를 수 있다
      • JSON과 같은 복잡한 구조를 가진 데이터에서 특정 부분을 추출해야 할 때, DB의 쿼리로 추출하는 것보다 우선 메모리에 데이터를 통으로 가져오고 애플리케이션 레이어에서 추출하는 것이 빠를 수 있다
      • 단, 데이터의 Payload 자체가 작고, Redis에 이미 캐싱되어 있는 경우, 복잡한 도메인 규칙으로 인해 필터링이 SQL 만으로는 표현 불가능한 경우 등, 제한적인 상황에 해당되며 남용하면 안된다
    • 무분별한 객체 캐싱은 자제해야 하며, 캐시 저장소 부하에 대한 모니터링은 필수
      • 객체 자체를 캐싱할 경우 불필요한 데이터가 쌓일 수 있다
      • 캐시 저장소에 과부하가 오면 서비스가 다운될 수 있다

데이터베이스 최적화

데이터 베이스 최적화 방식으로는 아래와 같은 것들이 있다. 각각의 내용을 정리하기엔 길기 때문에 다른 포스트에서 다룰 예정이다.

  • 인덱싱
  • 샤딩 (Sharding)
  • 테이블 파티셔닝
  • 읽기 전용 DB
    • 쓰기 전용 DB와 캐시 저장소(Redis) 간 Race Condition 문제에 긴밀한 대응 필요
  • 쿼리 최적화

쓰기 최적화

쓰기에서 가장 많은 시간을 소요하는 부분은 DB에 데이터를 생성하는 부분이다. 이를 해결하기 위한 다양한 방법이 있다.

  • 비동기 처리
  • 배치 처리
  • 분산 DB

데이터 일관성

대규모 시스템에서는 데이터 일관성을 유지하는 것이 중요하다. 이를 위해 분산 트랜잭션, 이벤트 소싱, CQRS(Command Query Responsibility Segregation) 등의 기법을 사용할 수 있다.

분산 트랜잭션

분산 트랜잭션은 여러 개의 독립된 시스템이나 데이터베이스에서 동시에 일어나는 트랜잭션을 일관되게 관리하는 방법이다. 하나의 트랜잭션이 여러 시스템에 걸쳐 발생할 때, 모든 시스템이 해당 트랜잭션을 성공하거나 실패하도록 보장해야 한다.

  • 트랜잭션 ACID 속성
    • 원자성 (Atomicity) : 트랜잭션은 전부 성공하거나 전부 실패하여, 부분적인 작업 수행이 없는 것을 보장
    • 일관성 (Consistency) : 트랜잭션이 완료된 후에도 데이터베이스는 모든 무결성 제약 조건을 유지
    • 격리성 (Isolation) : 동시에 실행되는 트랜잭션이 서로 간섭하지 않도록 보장
    • 지속성 (Durability) : 트랜잭션이 성공적으로 완료된 후의 결과는 시스템 장애가 발생해도 영구적으로 유지
  • 분산 트랜잭션
    • 여러 분산된 데이터 소스에 걸쳐 트랜잭션을 수행하는 작업으로, 여러 마이크로서비스나 데이터베이스에서 동시에 업데이트를 하는 경우
    • ACID 속성을 분산 환경에서도 유지
    • 단점
      • 시스템의 복잡성 증가
      • 2PC의 경우 모든 노드의 준비 상태를 위해 대기하여 성능 저하
      • 네트워크 오버헤드
      • 복구의 어려움
  • 기법
    • 2PC (Two-Phase Commit)
      • 준비(Prepare) 단계 : 각 참여 노드는 트랜잭션 준비 상태를 확인하고, 준비 완료를 마스터 노드에 알림
      • 커밋(Commit) 단계 : 마스터 노드는 모든 참여 노드가 준비되었음을 확인하고, 트랜잭션을 커밋하도록 지시. 만약 준비가 완료되지 않은 노드가 있다면 트랜잭션을 롤백
    • 사가 패턴 (Saga Pattern)
      • 트랜잭션을 여러 단계로 나누어 처리하고, 각 단계는 독립적으로 커밋됨. 실패 시 보상 트랜잭션을 통해 롤백
      • 예시
        1. 주문 생성 : 사용자가 주문을 생성
        2. 결제 처리 : 결제 서비스가 주문 결제를 처리
        3. 재고 감소 : 재고 서비스가 주문된 상품의 재고를 감소
        4. 특정 단계가 실패하면 이전 단계에서 수행된 작업을 취소
    • 이벤트 소싱 (Event Sourcing)
      • 데이터 상태 변화를 이벤트로 기록하고, 해당 이벤트를 재생하여 현재 상태를 유지
      • 데이터 변경 자체가 아닌 변경 이벤트를 저장하여 복잡한 비즈니스 로직에 대한 데이터 일관성과 추적 가능성을 높임
      • 복잡성이 증가할 수 있으므로, 시스템 요구사항에 맞게 신중히 적용해야 함

이벤트 소싱

  • 주요개념
    • 이벤트 (Event) : 데이터의 상태 변화에 대한 기록
    • 이벤트 스토어 (Event Store) : 이벤트를 저장하는 저장소. 불변성과 순차성을 보장해야 함
    • 애그리거트 (Aggregate) : 관련된 이벤트를 모아 현재 상태를 재현할 수 있는 엔티티. 도메인 모델의 일부
    • 커맨드 (Command) : 애그리게이트에 특정 동작을 지시하는 명령, 이벤트를 생성하는 트리거 역할
    • 프로젝션 (Projection) : 이벤트를 읽기 모델로 변환하여 조회 성능을 최적화하는 방식. 이벤트를 기반으로 읽기 전용 데이터베이스를 업데이트
  • 장점
    • 데이터 변경 이력 추적 가능, 감사와 디버깅에 유용함
    • 이벤트 재생을 통해 복구 가능
    • CQRS와의 자연스러운 통합 가능
  • 단점
    • 시스텀 설계와 구현의 복잡성 증가. 이벤트 모델링 및 이벤트 스토어 관리 필요
    • 이벤트를 재생하여 현재 상태를 계산하기 때문에 읽기 성능 저하 가능성

CQRS (Command Query Responsibility Segregation) 패턴

CQRS는 Command(명령)과 조회(Query)의 책임을 분리하는 디자인 패턴이다. 읽기 작업과 쓰기 작업을 서로 다른 모델로 분리해 각 작업에 최적화된 구조를 사용할 수 있도록 한다.

  • 주요 개념
    • 명령 (Command)
      • 데이터를 변경하는 작업으로, DB에 대한 쓰기 작업을 수행
      • 복잡한 비즈니스 로직을 포함할 수 있으며, 무결성 보장을 위해 트랜잭션을 사용
    • 조회 (Query)
      • 데이터를 조회하는 작업으로, DB에 대한 읽기 작업을 수행
      • 읽기 전용 데이터베이스 또는 캐시를 사용해 빠른 응답을 제공
  • 장점
    • 명령과 조회에 따른 구분된 최적화로 성능 향상
    • 읽기와 쓰기에 대한 독립적인 확장 가능
    • 읽기 모델에 대한 단순화를 통해 유지보수에 용이
    • 이벤트 소싱과의 통합 용이
  • 단점
    • 각 동작에 대한 시스템 설계와 구현의 복잡성 증가
    • 명령 모델과 조회 모델 간 데이터 동기화의 추가적인 구현과 관리
LIST