5. IT기술노트/인프라&개발

Latency Numbers로 설계하는 백엔드 아키텍처

쿼드큐브 2026. 5. 5. 21:49
반응형
반응형

 

Latency Numbers로 설계하는 백엔드 아키텍처

Latency Number 예시

 

1. 백엔드 개발자가 알아야 할 주요 Latency Numbers

Latency Numbers를 볼 때 가장 중요한 것은 절대값이 아니라 상대적 차이입니다.

예를 들어 “메모리 접근”, “Redis 조회”, “DB query”, “외부 API 호출”은 모두 데이터를 가져오는 작업처럼 보일 수 있습니다.
하지만 latency 관점에서는 완전히 다른 비용을 가집니다.


아래 표는 백엔드 개발자가 설계할 때 참고하면 좋은 대표적인 latency입니다.


실제 값은 CPU, 네트워크, cloud provider, region, payload 크기, connection 상태, DB 부하에 따라 달라질 수 있습니다.
따라서 아래 숫자는 정확한 기준값이라기보다 대략적인 규모를 이해하기 위한 숫자로 보는 것이 좋습니다.

 

🔷 주요 Latency Numbers

작업 Latency 비고
L1 cache 접근 약 0.5~1ns CPU 내부에서 처리되는 매우 저렴한 작업입니다.
L2 cache 접근 약 5ns 여전히 매우 빠른 영역입니다.
Main memory 접근 약 100ns 네트워크나 디스크에 비해 매우 저렴합니다.
Mutex lock/unlock 약 수십~100ns lock 경합이 심하면 throughput 병목이 될 수 있습니다.
1KB 압축 약 10μs 작은 데이터 압축은 비교적 저렴하지만 대량 처리에서는 누적됩니다.
SSD random read 약 수십~수백 μs 메모리보다 훨씬 비싸지만 HDD보다 빠릅니다.
Same datacenter round trip 약 0.5ms 내부 서비스 호출도 비용이 있습니다.
Same-region Redis 조회 약 1ms 전후 DB보다 빠르지만 local memory는 아닙니다.
Same-region DB query 약 수 ms~수십 ms 요청 횟수가 늘면 API latency에 직접 영향을 줍니다.
Disk seek 약 10ms random disk I/O는 매우 비싼 작업입니다.
Cross-region RTT 약 수십~150ms 이상 사용자 요청 경로에 포함되면 latency가 크게 증가합니다.
External API call 약 100ms~수 초 예측하기 어렵고 timeout, retry 설계가 필요합니다.

 

🔷 Latency Numbers를 읽는 핵심

Latency Numbers를 읽을 때는 다음 차이를 이해해야 합니다.

L1 cache 접근        ≈ 1ns
Main memory 접근     ≈ 100ns
Same datacenter RTT  ≈ 0.5ms = 500,000ns
DB query             ≈ 5~20ms
Cross-region RTT     ≈ 50~150ms 이상
External API call    ≈ 100ms~수 초

여기서 중요한 사실은 다음과 같습니다.
▸ 메모리 접근과 네트워크 호출은 완전히 다른 비용입니다.
▸ Redis는 빠르지만 local memory가 아니라 remote call입니다.
▸ DB query 1번은 괜찮을 수 있지만, 50번 반복되면 문제가 됩니다.
▸ 같은 region 호출과 cross-region 호출은 응답 시간에 큰 차이를 만듭니다.
▸ 외부 API는 평균 latency보다 p95, p99 latency가 더 문제가 될 수 있습니다.

즉, 백엔드 설계에서 중요한 것은 단순히 “빠르다/느리다”가 아닙니다.
얼마나 멀리 있는 것을, 몇 번 호출하는가가 중요합니다.

 

2. Latency Numbers로 API 요청을 분해하는 방법

Latency Numbers를 실제 설계에 활용하려면 API 요청 하나를 여러 구간으로 나눠봐야 합니다.

예를 들어 상품 상세 API가 있다고 가정해보겠습니다.

GET /products/{id}

 

🔷 Latency Budget 예시

 

목표 응답 시간을 200ms로 잡아보겠습니다.

작업 Latency
Client ↔ API Server network 30ms
인증/인가 처리 5ms
상품 DB 조회 20ms
리뷰 서비스 호출 50ms
재고 서비스 호출 30ms
추천 서비스 호출 80ms
응답 직렬화 5ms

모든 작업을 순차적으로 실행하면 다음과 같습니다.

30 + 5 + 20 + 50 + 30 + 80 + 5 = 220ms

목표 응답 시간인 200ms를 초과합니다.
이제 설계 질문이 명확해집니다.
▸ 리뷰, 재고, 추천 서비스 호출은 서로 의존하는가?
▸ 의존하지 않는다면 병렬화할 수 있는가?
▸ 추천 결과는 반드시 응답에 포함되어야 하는가?
▸ 리뷰 요약은 캐시할 수 있는가?
▸ 상품 상세용 read model을 만들면 DB query를 줄일 수 있는가?
이처럼 latency budget을 계산하면 성능 개선 방향이 추상적인 감이 아니라 구조적인 판단으로 바뀝니다.

 

🔷 Critical Path와 Non-Critical Path 구분하기

백엔드 설계에서 중요한 개념 중 하나는 Critical Path입니다.
사용자가 응답을 받기 전에 반드시 완료되어야 하는 작업이 있고, 응답 이후 처리해도 되는 작업이 있습니다.
이때 응답 전에 반드시 완료되어야 하는 경로를 Critical Path라고 볼 수 있습니다.

 

예를 들어 주문 생성 API를 생각해보겠습니다.

POST /orders
  ↓
쿠폰 검증
  ↓
재고 차감
  ↓
결제 승인
  ↓
주문 저장
  ↓
이메일 발송
  ↓
푸시 알림
  ↓
응답 반환

이 구조에서는 이메일 발송과 푸시 알림까지 모두 끝나야 응답을 반환합니다.

 

하지만 주문 생성의 핵심은 보통 다음 작업입니다.
▸ 쿠폰 검증
▸ 재고 차감
▸ 결제 승인
▸ 주문 저장
반면 이메일 발송과 푸시 알림은 주문 성공 이후 처리해도 되는 작업일 수 있습니다.
그러면 구조를 다음처럼 바꿀 수 있습니다.

POST /orders
  ↓
쿠폰 검증
  ↓
재고 차감
  ↓
결제 승인
  ↓
주문 저장
  ↓
OrderCreated 이벤트 발행
  ↓
응답 반환

비동기 Worker
  ├── 이메일 발송
  └── 푸시 알림

핵심은 간단합니다.
▸ 응답 전에 반드시 끝나야 하는 작업은 동기 경로에 둡니다.
▸ 나중에 처리해도 되는 작업은 비동기로 분리합니다.
▸ 외부 API처럼 latency 변동이 큰 작업은 가능하면 critical path에서 제거합니다.
▸ 실패해도 재시도 가능한 작업은 queue 뒤로 보냅니다.

Latency Numbers는 이 판단을 가능하게 합니다.

반응형

 

3. 계산으로 판단하는 아키텍처 의사결정

Latency Numbers의 가장 큰 장점은 설계 선택을 계산해볼 수 있다는 점입니다.

정확한 예측이 목적이 아니라, 어떤 설계가 더 위험한지 빠르게 판단하는 것이 목적입니다.

 

🔷 사례 1. 순차 처리 vs 병렬 처리

상품 상세 API가 다음 작업을 수행한다고 가정해보겠습니다.

작업 Latency
상품 DB 조회 20ms
리뷰 서비스 호출 50ms
재고 서비스 호출 30ms
추천 서비스 호출 80ms
응답 직렬화 5ms

가장 단순한 구현은 순차 처리입니다.

상품 DB 조회
  ↓
리뷰 서비스 호출
  ↓
재고 서비스 호출
  ↓
추천 서비스 호출
  ↓
응답 직렬화
총 latency = 20ms + 50ms + 30ms + 80ms + 5ms
           = 185ms

하지만 리뷰, 재고, 추천 서비스가 서로 의존하지 않는다면 병렬 처리할 수 있습니다.

상품 DB 조회
  ↓
 ├── 리뷰 서비스 호출
 ├── 재고 서비스 호출
 └── 추천 서비스 호출
  ↓
응답 직렬화

이 경우 latency는 다음처럼 계산됩니다.

총 latency = 상품 DB 조회 + max(리뷰, 재고, 추천) + 응답 직렬화
           = 20ms + max(50ms, 30ms, 80ms) + 5ms
           = 105ms

순차 처리에서는 185ms였지만 병렬 처리하면 약 105ms가 됩니다.

 

✔️ 여기서 중요한 점

병렬 처리가 항상 정답이라는 뜻은 아닙니다.
하지만 계산을 통해 병렬화로 약 80ms를 줄일 수 있다는 것을 알 수 있습니다.

 

이제 다음 판단을 할 수 있습니다.
▸ 80ms 개선을 위해 비동기 처리 복잡도를 감수할 가치가 있는가?
▸ downstream service가 병렬 요청을 감당할 수 있는가?
▸ timeout과 fallback은 어떻게 둘 것인가?
▸ 하나의 서비스가 느려질 때 전체 응답을 막아도 되는가?
숫자를 알면 설계 논의가 훨씬 구체적이 됩니다.

 

🔷 사례 2. Redis 캐시 도입 판단

캐시는 자주 사용되는 성능 개선 방법입니다. 하지만 모든 조회에 캐시를 넣어야 하는 것은 아닙니다.

캐시 도입은 다음 조건을 보고 판단해야 합니다.
▸ 같은 데이터가 반복해서 조회되는가?
▸ 원본 DB 조회 비용이 큰가?
▸ 약간 오래된 데이터를 허용할 수 있는가?
▸ cache invalidation을 감당할 수 있는가?
▸ cache hit ratio가 충분히 높을 것으로 예상되는가?

 

예를 들어 다음과 같이 가정해보겠습니다.

DB 조회 latency    = 20ms
Redis 조회 latency = 1ms
Cache hit ratio    = 90%

캐시를 사용했을 때 평균 latency는 다음과 같습니다.

평균 latency = cache hit 비율 × Redis latency
            + cache miss 비율 × DB latency

평균 latency = 0.9 × 1ms + 0.1 × 20ms
            = 0.9ms + 2ms
            = 2.9ms

DB만 사용하면 매번 20ms가 걸립니다.
하지만 캐시 hit ratio가 90%라면 평균 조회 latency는 약 2.9ms가 됩니다.

 

구조는 다음과 같습니다.

Client
  ↓
API Server
  ↓
Redis 조회
  ├── Hit  → 응답
  └── Miss → DB 조회 → Redis 저장 → 응답

이 구조는 다음 데이터에 적합합니다.
▸ 상품 상세 정보
▸ 카테고리 목록
▸ 설정 정보
▸ 인기 게시글
▸ 사용자 권한 정보
▸ 리뷰 요약
▸ 자주 조회되지만 자주 바뀌지 않는 데이터

 

다만 캐시는 다음 비용을 함께 가져옵니다.

고려사항 설명
Cache miss miss 시 Redis 조회와 DB 조회가 모두 발생합니다.
Invalidation 원본 데이터 변경 시 캐시를 언제 제거하거나 갱신할지 정해야 합니다.
Stale data 오래된 데이터를 사용자에게 보여줘도 되는지 판단해야 합니다.
Memory cost Redis 메모리 비용이 증가합니다.
장애 대응 Redis 장애 시 DB fallback이 가능한지 설계해야 합니다.
Hot key 특정 key에 요청이 몰리면 Redis 자체가 병목이 될 수 있습니다.

따라서 캐시는 “DB보다 빠르니까 넣는다”가 아니라,
반복 조회와 높은 hit ratio를 통해 평균 latency를 낮추는 도구로 봐야 합니다.

 

🔷 사례 3. N+1 Query 제거

DB query 1회가 10ms라고 가정해보겠습니다.
주문 목록 API가 다음처럼 동작한다고 해보겠습니다.

주문 목록 조회
  ↓
각 주문마다 사용자 정보 조회
  ↓
각 주문마다 결제 정보 조회
  ↓
각 주문마다 배송 정보 조회

주문이 30개라면 query 수는 다음과 같습니다.

주문 목록 조회: 1회
사용자 정보 조회: 30회
결제 정보 조회: 30회
배송 정보 조회: 30회

총 query 수 = 91회

query 1회가 10ms라면 단순 계산으로 다음과 같습니다.

총 latency = 91 × 10ms
           = 910ms

이 구조가 위험한 이유는 query 하나가 느려서가 아닙니다.
작은 비용이 반복되기 때문입니다.

개선 방법은 다음과 같습니다.
▸ join query 사용
▸ batch query 사용
▸ IN query 사용
▸ ORM fetch join 사용
▸ read model 구성
▸ denormalized table 구성

 

예를 들어 batch query로 줄이면 다음처럼 바뀔 수 있습니다.

주문 목록 조회: 1회
사용자 정보 batch 조회: 1회
결제 정보 batch 조회: 1회
배송 정보 batch 조회: 1회

총 query 수 = 4회

계산하면 다음과 같습니다.

총 latency = 4 × 10ms
           = 40ms

910ms였던 구조가 40ms 수준으로 줄어듭니다.
이 사례의 핵심은 DB 자체를 더 빠르게 만드는 것이 아닙니다.
DB round-trip 횟수를 줄이는 구조로 바꾸는 것입니다.

 

🔷 사례 4. 대시보드 API와 Pre-computation

대시보드 API는 요청 시점마다 모든 데이터를 계산하면 느려지기 쉽습니다.
예를 들어 관리자 대시보드가 다음 데이터를 보여준다고 가정해보겠습니다.
▸ 오늘 주문 수
▸ 오늘 매출
▸ 카테고리별 매출
▸ 시간대별 주문 수
▸ 신규 가입자 수
▸ 환불 건수
▸ 인기 상품 top 10

단순 구현은 요청이 들어올 때마다 여러 테이블을 집계하는 방식입니다.

GET /dashboard
  ↓
orders table aggregate
  ↓
payments table aggregate
  ↓
users table aggregate
  ↓
refunds table aggregate
  ↓
products table aggregate
  ↓
response

각 집계 query가 200ms씩 걸리고 5개를 순차 실행하면 다음과 같습니다.

총 latency = 5 × 200ms
           = 1000ms

1초짜리 API가 됩니다.

이 경우 매번 실시간 계산을 하는 대신 미리 계산된 summary table을 사용할 수 있습니다.

주문 발생
  ↓
이벤트 발행
  ↓
집계 Worker
  ↓
dashboard_summary 갱신

조회는 다음처럼 단순해집니다.

GET /dashboard
  ↓
dashboard_summary 조회
  ↓
response

summary table 조회가 20ms라면 다음과 같이 줄어듭니다.

기존 latency = 1000ms
개선 latency = 20ms

이 구조는 다음 상황에 적합합니다.
▸ 실시간 정확도보다 빠른 조회가 중요한 경우
▸ 동일한 집계 결과가 반복 조회되는 경우
▸ 복잡한 join과 aggregate가 많은 경우
▸ dashboard, report, ranking, feed 같은 조회 중심 기능

 

다만 다음 trade-off가 있습니다.
▸ 데이터가 약간 지연될 수 있습니다.
▸ 집계 worker 장애에 대비해야 합니다.
▸ 재집계 기능이 필요합니다.
▸ 원본 데이터와 summary table 정합성을 모니터링해야 합니다.

 

🔷 사례 5. Cross-region 호출 제거

글로벌 서비스를 운영하다 보면 region 간 호출이 생길 수 있습니다.
예를 들어 한국 사용자의 요청이 서울 region의 API 서버로 들어왔는데, DB가 미국 region에 있다고 가정해보겠습니다.

User(KR)
  ↓
API Server(ap-northeast)
  ↓
DB(us-west)

same-region DB query가 10ms라면 큰 문제가 아닐 수 있습니다.
하지만 cross-region round trip은 수십~150ms 이상 걸릴 수 있습니다.

 

API 요청 하나에서 cross-region 호출이 3번 발생한다고 가정해보겠습니다.

cross-region 호출 1회 = 100ms
3회 호출 = 300ms

여기에 client network, application processing, serialization까지 더하면 API 응답 시간이 쉽게 500ms 이상으로 증가할 수 있습니다.
해결 전략은 다음과 같습니다.

 

✔️ 서비스와 DB를 같은 region에 배치

API Server(ap-northeast)
  ↓
DB(ap-northeast)

가장 기본적인 전략입니다.
사용자 요청의 critical path에 있는 DB와 service는 가능한 한 같은 region에 두는 것이 좋습니다.

 

✔️ Read replica 사용

쓰기 DB는 하나의 region에 두더라도, 읽기 요청은 가까운 replica에서 처리할 수 있습니다.

Write DB(us-west)
  ↓ replication
Read Replica(ap-northeast)

읽기 latency를 줄일 수 있지만 replica lag를 고려해야 합니다.

 

✔️ Regional cache 사용

자주 조회되는 데이터는 사용자와 가까운 region의 Redis나 CDN에 둘 수 있습니다

User
  ↓
Regional Cache
  ↓
Origin DB

상품 정보, 설정 정보, 공개 프로필, 카탈로그 데이터처럼 변경 빈도가 낮은 데이터에 효과적입니다.

 


※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.

반응형

 

반응형