[내일배움캠프 사전캠프] 23회차 TIL(7/27 월) - 대규모 시스템 설계

2026. 7. 27. 15:22·심화_AI를 활용한 백엔드 아키텍처 심화 과정

대규모 시스템 설계

대규모 시스템에서는 많은 사용자의 요청을 안정적으로 처리하면서도 장애에 대응할 수 있는 구조를 설계해야 한다.

단순히 서버의 성능을 높이는 것뿐만 아니라 TPS, 캐싱, 데이터베이스 최적화, CQRS와 Event Sourcing, 모니터링 및 로깅, 배포 전략 등을 종합적으로 고려해야 한다.


1. TPS와 시스템 처리량

TPS(Transaction Per Second)란?

TPS는 1초 동안 처리할 수 있는 트랜잭션의 수를 의미하며, 시스템의 처리량을 나타내는 주요 성능 지표 중 하나이다.

예를 들어 특정 시간대에 초당 200건의 트랜잭션이 발생한다면 TPS는 약 200이라고 볼 수 있다.

여기서 주의할 점은 TPS가 동시 접속자 수 자체를 의미하는 것은 아니라는 점이다.

  • 동시 접속자 수: 동시에 시스템을 이용하고 있는 사용자 수
  • TPS: 시스템이 초당 처리하는 트랜잭션 수

대규모 시스템을 설계할 때는 평소의 요청량뿐만 아니라 갑작스러운 트래픽 증가에도 대응할 수 있도록 여유 있게 시스템의 처리 용량을 설계해야 한다.

예를 들어 피크 시간대의 최대 TPS가 200이라고 예상한다면 정확히 200 TPS만 처리하도록 설계하기보다는, 장애 상황이나 트래픽 증가 등을 고려하여 150% 수준인 300 TPS 등을 목표 처리량으로 설정할 수 있다.

단, 150%가 반드시 정답인 것은 아니며 실제 서비스에서는 트래픽 패턴, 비용, SLA, 장애 대응 전략 등을 고려하여 목표 처리량을 결정해야 한다.


2. Cache와 Caching

Cache란?

Cache는 자주 사용하는 데이터를 원본 저장소보다 빠른 저장 공간에 임시로 보관하여, 동일한 데이터가 다시 필요할 때 빠르게 반환하기 위한 저장 공간이다.

DB에 반복적으로 접근하는 대신 Redis와 같은 In-Memory 저장소에 데이터를 저장하면 DB의 부하를 줄이고 응답 속도를 향상시킬 수 있다.

Caching이란?

Caching은 자주 사용하는 데이터를 Cache에 저장하고 필요할 때 Cache에서 데이터를 가져오는 일련의 방식을 의미한다.

대표적인 흐름은 다음과 같다.

Client
   ↓
Application
   ↓
Redis에 데이터가 있는지 확인
   ↓
┌──────────────────────────┐
│ Cache Hit                │
│ 데이터 존재 → 즉시 반환  │
└──────────────────────────┘

┌──────────────────────────┐
│ Cache Miss               │
│ 데이터 없음              │
└──────────────────────────┘
   ↓
Database 조회
   ↓
데이터 반환
   ↓
Redis Cache에 데이터 저장
   ↓
Client에게 반환

이러한 방식을 Cache-Aside 패턴이라고 한다.

애플리케이션이 먼저 Cache를 조회하고 데이터가 존재하면 바로 반환한다. 데이터가 존재하지 않으면 DB에서 데이터를 조회한 뒤 Redis에 저장하고 사용자에게 반환한다.

이후 동일한 데이터가 요청되면 DB까지 접근할 필요 없이 Redis에서 바로 반환할 수 있다.


Redis Cache 사용 시 주의사항

Redis를 사용한다고 항상 성능이 향상되는 것은 아니다. Redis 또한 하나의 외부 시스템이기 때문에 장애, 네트워크 지연, 메모리 부족 등을 고려해야 한다.

Connection Timeout

Redis 서버에 장애가 발생하거나 네트워크 문제가 생겼을 때 애플리케이션이 Redis의 응답을 무한정 기다려서는 안 된다.

예를 들어 Redis에 연결을 시도한 뒤 5초 동안 연결되지 않는다면 연결을 중단하도록 Connection Timeout을 설정할 수 있다.

Application
    ↓
Redis 연결 시도
    ↓
응답 없음
    ↓
설정한 Timeout 초과
    ↓
연결 실패 처리

이를 통해 Redis의 장애가 애플리케이션 전체의 응답 지연으로 이어지는 것을 방지할 수 있다.

또한 캐시가 필수 데이터 저장소가 아니라 성능 개선을 위한 보조 저장소라면 상황에 따라 다음과 같은 장애 대응도 고려할 수 있다.

Redis 조회
   ↓
Redis 장애
   ↓
Fallback
   ↓
DB 직접 조회

Redis 장애 하나가 전체 서비스 장애로 전파되지 않도록 설계하는 것이 중요하다.

TTL(Time To Live)

캐시 데이터에 만료 시간을 설정하지 않으면 Redis에 데이터가 계속 쌓이면서 메모리가 부족해질 수 있다.

따라서 캐시의 특성에 따라 TTL을 설정하여 일정 시간이 지난 데이터가 자동으로 제거되도록 할 수 있다.

Cache와 DB의 데이터 정합성

DB의 데이터가 변경되었는데 Redis에는 기존 데이터가 남아있을 수 있다.

Redis → 상품 가격 10,000원
DB    → 상품 가격 12,000원

이 상태에서 Redis 데이터를 반환하면 사용자는 오래된 데이터를 받게 된다.

따라서 DB의 데이터가 변경될 때 관련 캐시를 삭제하거나 갱신하는 Cache Invalidation 전략이 필요하다.


Redis 메모리 모니터링

Redis는 메모리를 기반으로 데이터를 저장하기 때문에 메모리 사용량 관리가 중요하다.

예를 들어 Redis의 최대 메모리를 50GB로 설정했다고 가정하자.

최대 Redis Memory → 50GB

30GB 이상 → Warning
40GB 이상 → Critical

실제 임계치는 서비스 환경에 맞게 설정해야 하지만, 일정 수준 이상의 메모리가 사용되었을 때 운영자에게 알림을 보내도록 구성할 수 있다.

대표적으로 다음과 같은 구조를 사용할 수 있다.

Redis
  ↓
Redis Exporter
  ↓
Prometheus
  ↓
Grafana / Alertmanager
  ↓
Slack / Email 등으로 운영자 알림

Redis에서는 used_memory, maxmemory 등의 지표를 통해 현재 메모리 사용량을 확인할 수 있다.

또한 단순히 알림만 설정하는 것이 아니라 Redis가 최대 메모리에 도달했을 때 어떻게 데이터를 처리할지도 결정해야 한다.

이를 위해 Redis의 maxmemory와 Eviction Policy를 설정할 수 있다.

Eviction Policy에 따라 메모리가 부족할 경우 TTL이나 사용 빈도 등을 기준으로 기존 데이터를 제거할 수 있다.

즉, Redis를 운영할 때는 장애 대응 + 메모리 모니터링 + TTL + Eviction Policy + 데이터 정합성을 함께 고려해야 한다.


3. 데이터베이스 쓰기 요청 최적화

대규모 시스템에서는 수많은 쓰기 요청이 동시에 DB에 전달될 수 있다.

모든 요청을 즉시 DB에서 처리하면 데이터베이스에 부하가 집중될 수 있기 때문에 비동기 처리, 배치 처리, DB 분산 등의 전략을 사용할 수 있다.

비동기 처리

요청을 받은 즉시 모든 작업을 완료하는 대신, 즉시 처리할 필요가 없는 작업을 별도로 처리하는 방식이다.

예를 들어 주문이 완료된 이후 이메일이나 알림을 보내야 한다고 생각해보자.

주문 요청
   ↓
주문 처리
   ↓
이벤트 / 메시지 발행
   ↓
사용자에게 주문 결과 반환

       동시에

메시지 소비
   ↓
이메일 / 알림 처리

사용자는 이메일 발송이 끝날 때까지 기다릴 필요가 없다.

Kafka, RabbitMQ와 같은 메시지 브로커를 이용하여 이러한 구조를 구현할 수 있다.

비동기 처리를 통해 요청의 응답 시간을 줄이고 특정 컴포넌트에 부하가 집중되는 것을 완화할 수 있다.

Batch 처리

데이터를 한 건씩 처리하는 대신 여러 데이터를 일정 단위로 묶어서 처리하는 방식이다.

1건 저장
1건 저장
1건 저장
1건 저장
...

보다 상황에 따라

데이터 수집
데이터 수집
데이터 수집
   ↓
일정 단위로 묶음
   ↓
Batch 처리

방식을 사용할 수 있다.

로그 집계, 통계 처리, 대량 데이터 처리 등 즉시 처리할 필요가 없는 작업에서 활용할 수 있다.

다만 모든 쓰기 작업을 Batch로 처리할 수 있는 것은 아니며 실시간성이 중요한 작업에서는 적합하지 않을 수 있다.

분산 DB

하나의 데이터베이스에 모든 읽기와 쓰기 요청이 집중되면 DB가 병목 지점이 될 수 있다.

따라서 데이터의 특성에 따라 여러 DB로 데이터를 분산하는 방법을 고려할 수 있다.

대표적인 방법으로 Sharding이 있다.

User ID 1 ~ 1,000,000
        ↓
      DB 1

User ID 1,000,001 ~ 2,000,000
        ↓
      DB 2

데이터와 요청을 여러 DB에 분산하여 하나의 DB에 부하가 집중되는 것을 줄일 수 있다.

하지만 데이터 분산 기준을 설계해야 하고, 여러 DB에 걸친 JOIN이나 트랜잭션이 복잡해질 수 있다는 단점이 있다.


4. Event Sourcing

Event Sourcing은 데이터의 현재 상태만 저장하는 대신 데이터의 상태 변화를 이벤트로 기록하고, 해당 이벤트들을 순차적으로 적용하여 현재 상태를 재구성할 수 있도록 하는 방식이다.

예를 들어 주문이 다음과 같이 진행되었다고 가정해보자.

1. 주문 생성됨
2. 결제 완료됨
3. 배송 시작됨
4. 배송 완료됨

일반적인 방식에서는 최종적으로 배송 완료라는 현재 상태를 저장하는 데 집중한다.

Event Sourcing에서는 주문 생성, 결제 완료, 배송 시작, 배송 완료라는 상태 변화 자체를 이벤트로 저장한다.

필요하다면 저장된 이벤트를 순서대로 재생(Replay)하여 특정 시점 또는 현재의 상태를 재구성할 수 있다.

단, Replay는 실제 결제나 배송 같은 외부 작업을 다시 실행한다는 의미가 아니라 저장된 이벤트를 적용하여 상태를 다시 만들어낸다는 의미이다.

Event Sourcing 주요 개념

이벤트(Event)
데이터의 상태 변화를 나타내는 기록이다.

예를 들어 OrderCreated, PaymentCompleted, OrderCancelled 등이 이벤트가 될 수 있다.

이벤트 스토어(Event Store)
발생한 이벤트들을 순서대로 저장하는 저장소이다.

애그리게이트(Aggregate)
도메인에서 일관성을 유지해야 하는 데이터와 행위를 하나의 단위로 묶은 개념이다. Event Sourcing에서는 자신의 이벤트 이력을 적용하여 현재 상태를 재구성할 수 있다.

커맨드(Command)
시스템 또는 Aggregate에게 특정 동작을 수행하도록 요청하는 명령이다.

CreateOrder Command
        ↓
Order Aggregate
        ↓
OrderCreated Event

Command는 "주문을 생성해라", Event는 "주문이 생성되었다"라는 차이가 있다.

프로젝션(Projection)
이벤트를 이용하여 조회에 적합한 Read Model을 생성하는 방식이다.

Event Store
    ↓
Projection
    ↓
Read Model
    ↓
조회용 DB

이벤트가 발생하면 이를 기반으로 읽기 전용 데이터를 업데이트하여 조회 성능을 최적화할 수 있다.


5. CQRS + Event Sourcing

CQRS(Command Query Responsibility Segregation)는 데이터를 변경하는 Command와 데이터를 조회하는 Query의 책임을 분리하는 패턴이다.

Event Sourcing과 함께 사용하면 다음과 같은 구조를 만들 수 있다.

             Command
                ↓
           Aggregate
                ↓
             Event
                ↓
          Event Store
                ↓
            Projection
                ↓
           Read Model
                ↓
              Query

쓰기 영역에서는 Command를 처리한 결과로 이벤트를 생성하고 Event Store에 저장한다.

조회 영역에서는 저장된 이벤트를 기반으로 Projection을 수행하여 조회에 최적화된 Read Model을 만든다.

CQRS와 Event Sourcing을 함께 사용할 때의 장점

첫 번째는 변경 이력을 추적하기 쉽다는 것이다.

Event Store에 모든 상태 변화가 기록되기 때문에 어떤 과정을 거쳐 현재 상태가 만들어졌는지 확인할 수 있다.

두 번째는 읽기와 쓰기를 각각 최적화할 수 있다는 것이다.

쓰기 모델은 데이터 변경과 일관성에 집중하고, 읽기 모델은 조회 성능에 맞게 별도로 구성할 수 있다.

세 번째는 다양한 Read Model을 만들 수 있다는 것이다.

하나의 이벤트를 이용하여 서로 다른 목적의 조회 데이터를 생성할 수 있다.

Order Event
   ├── 사용자 주문 내역
   ├── 관리자 주문 통계
   └── 일별 매출 데이터

네 번째는 이벤트를 이용하여 상태를 재구성할 수 있다는 것이다.

필요한 경우 저장된 이벤트를 Replay하여 상태나 Read Model을 다시 만들 수 있다.

단점

CQRS와 Event Sourcing은 강력하지만 모든 시스템에서 사용할 필요는 없다.

가장 큰 단점은 시스템의 복잡성이 크게 증가한다는 것이다.

Command, Event Store, Projection, Read Model 등을 별도로 설계해야 하며 일반적인 CRUD 방식보다 개발과 운영이 어려워질 수 있다.

또한 쓰기 모델에서 이벤트가 발생한 뒤 읽기 모델에 반영되기까지 약간의 시간 차이가 발생할 수 있다.

Command 처리 완료
      ↓
Event 발생
      ↓
Projection 처리 중...
      ↓
Read Model 반영

따라서 쓰기 모델과 읽기 모델 사이의 데이터 동기화와 최종적 일관성(Eventual Consistency)을 관리해야 한다.


6. 모니터링과 로깅

대규모 시스템에서 모니터링과 로깅은 시스템의 안정성과 성능을 유지하는 데 필수적인 역할을 한다.

Monitoring

모니터링은 애플리케이션, DB, Redis, 서버 등 각 컴포넌트의 상태와 성능 지표를 지속적으로 확인하는 것이다.

예를 들어 다음과 같은 지표를 확인할 수 있다.

  • CPU / Memory 사용량
  • TPS 및 요청 수
  • API 응답 시간
  • Error Rate
  • DB Connection 수
  • Redis Memory 사용량
  • Cache Hit / Miss 비율

이러한 주요 지표를 지속적으로 확인하고 이상 징후가 발견되면 운영자에게 알림을 보내도록 구성할 수 있다.

예를 들어 Redis 메모리가 일정 수준을 넘어가거나 API 오류율이 급격하게 증가하면 Slack이나 Email 등으로 알림을 보낼 수 있다.

이를 통해 시스템 상태를 실시간으로 파악하고 장애 발생 시 빠르게 대응할 수 있다.

Logging

로깅은 애플리케이션에서 발생한 주요 사건과 정보를 기록하는 것이다.

사용자 요청
↓
주문 생성
↓
결제 요청
↓
결제 실패
↓
Exception 발생

이러한 과정이 로그에 기록되어 있다면 장애 발생 시 어떤 요청에서 어떤 문제가 발생했는지 추적할 수 있다.

특히 MSA처럼 여러 서비스가 서로 통신하는 환경에서는 하나의 요청이 여러 서비스를 거칠 수 있기 때문에 Trace ID 등을 이용한 분산 추적(Distributed Tracing)도 중요하다.

Client
  ↓
Gateway
  ↓
Order Service
  ↓
Payment Service
  ↓
Delivery Service

동일한 Trace ID를 통해 하나의 요청 추적

7. 대규모 시스템의 배포 전략

서비스를 운영하면서 새로운 버전을 배포할 때 서버를 모두 종료하고 새로운 버전을 실행하면 서비스 중단 시간이 발생할 수 있다.

이를 최소화하기 위해 Canary, Blue-Green, Rolling 등의 배포 전략을 사용할 수 있다.

Canary 배포

새로운 버전을 전체 사용자에게 바로 제공하지 않고 일부 사용자 또는 일부 트래픽에 먼저 적용하는 방법이다.

전체 트래픽

95% → 기존 버전
 5% → 새로운 버전

새로운 버전에서 문제가 발생하지 않는지 확인한 뒤 점진적으로 새로운 버전의 트래픽 비율을 증가시킨다.

문제가 발생하면 새로운 버전으로 향하는 트래픽을 중단하여 영향을 최소화할 수 있다.

따라서 새로운 기능을 단계적으로 도입하고 실제 운영 환경에서 안정성을 검증할 수 있다는 장점이 있다.

Blue-Green 배포

동일한 서비스를 제공할 수 있는 두 개의 환경을 준비하는 방식이다.

Blue  → 현재 운영 버전
Green → 새로운 버전

새로운 버전을 Green 환경에 배포하고 테스트가 완료되면 트래픽을 Blue에서 Green으로 전환한다.

Before

Client
  ↓
Blue


After

Client
  ↓
Green

Green 환경에서 문제가 발생하면 트래픽을 다시 Blue 환경으로 전환하여 빠르게 롤백할 수 있다.

서비스를 중단하지 않고 새로운 버전으로 전환할 수 있다는 장점이 있지만, 두 개의 환경을 유지해야 하기 때문에 추가적인 인프라 비용이 발생할 수 있다.

Rolling 배포

여러 서버를 운영하고 있을 때 서버를 한 번에 모두 변경하지 않고 일부 서버부터 순차적으로 새로운 버전으로 업데이트하는 방법이다.

기존

Server A → v1
Server B → v1
Server C → v1


1단계

Server A → v2
Server B → v1
Server C → v1


2단계

Server A → v2
Server B → v2
Server C → v1


완료

Server A → v2
Server B → v2
Server C → v2

일부 서버가 계속 요청을 처리하기 때문에 서비스 중단을 최소화하면서 새로운 버전을 배포할 수 있다.

다만 배포가 진행되는 동안 구버전과 신버전이 동시에 실행되므로 두 버전 간 호환성을 고려해야 한다.


정리

대규모 시스템에서는 단순히 서버의 개수를 늘리는 것만으로 모든 문제를 해결할 수 없다.

TPS와 트래픽을 고려한 용량 설계를 시작으로 Redis와 같은 Cache를 통한 조회 성능 개선, 비동기 및 Batch 처리와 DB 분산을 통한 쓰기 성능 개선이 필요하다.

또한 복잡한 도메인에서는 CQRS와 Event Sourcing을 이용하여 읽기와 쓰기를 분리하고 변경 이력을 관리하는 방법을 고려할 수 있다.

운영 단계에서는 Monitoring과 Logging을 통해 장애를 빠르게 탐지하고 원인을 추적해야 하며, Canary, Blue-Green, Rolling과 같은 배포 전략을 통해 서비스 중단과 배포 위험을 최소화할 수 있다.

결국 대규모 시스템 설계의 핵심은 단순히 많은 요청을 처리하는 것을 넘어 성능, 확장성, 장애 대응, 데이터 일관성, 운영 안정성을 함께 고려하는 것이다.

예습

RabbitMQ 흐름
프로듀서가 메시지 생성 -> 익스체인지 -> 큐 -> 컨슈머가 메시지 처리

프로듀서가 메시지 생성 → 익스체인지가 메시지를 받음 → 라우팅 규칙에 따라 Queue로 전달 → Consumer가 Queue의 메시지를 처리

'심화_AI를 활용한 백엔드 아키텍처 심화 과정' 카테고리의 다른 글

[내일배움캠프 사전캠프] 24회차 TIL(7/29 수) - RabbitMQ 구조 설계 및 이해, Kafka 개념 정리  (0) 2026.07.29
[내일배움캠프 사전캠프] 22회차 TIL(7/24 금) - Spring Session, Redis Cache  (0) 2026.07.24
[내일배움캠프 사전캠프] 21회차 TIL(7/23 목) - Redis  (0) 2026.07.23
[내일배움캠프 사전캠프] 20회차 TIL(7/22 수) - Docker, Docker-Compose  (0) 2026.07.22
[내일배움캠프 사전캠프] 19회차 TIL(7/21 화) - Docker Image, Container  (0) 2026.07.21
'심화_AI를 활용한 백엔드 아키텍처 심화 과정' 카테고리의 다른 글
  • [내일배움캠프 사전캠프] 24회차 TIL(7/29 수) - RabbitMQ 구조 설계 및 이해, Kafka 개념 정리
  • [내일배움캠프 사전캠프] 22회차 TIL(7/24 금) - Spring Session, Redis Cache
  • [내일배움캠프 사전캠프] 21회차 TIL(7/23 목) - Redis
  • [내일배움캠프 사전캠프] 20회차 TIL(7/22 수) - Docker, Docker-Compose
taeyoon2
taeyoon2
taeyoon2 님의 블로그 입니다.
  • taeyoon2
    taeyoon2 님의 블로그
    taeyoon2
  • 전체
    오늘
    어제
    • 분류 전체보기 (36)
      • 심화_AI를 활용한 백엔드 아키텍처 심화 과정 (24)
      • MSA (11)
      • Study (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    분산추적
    심화_AI를 활용한 백엔드 아키텍처 심화 과정
    내일배움캠프 #사전캠프 #til
    내일배움캠프
    Resilience4j
    spring cloud
    spring cloud config
    사전캠프
    api gateway
    이벤트 드리븐
    Config
    로드 밸런싱
    RabbitMQ
    OAuth2
    til
    JWT
    보안구성
    Zipkin
    서킷 브레이커
    MSA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
taeyoon2
[내일배움캠프 사전캠프] 23회차 TIL(7/27 월) - 대규모 시스템 설계
상단으로

티스토리툴바