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

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 도구의 도움을 받아 생성되거나 다듬어졌습니다.
'5. IT기술노트 > 인프라&개발' 카테고리의 다른 글
| V모델로 이해하는 테스트 레벨과 테스트 방법 (0) | 2026.05.12 |
|---|---|
| 행위 주도 개발 BDD(Behavior-Driven Development) 이해하기 (0) | 2026.05.07 |
| 테스트 주도 개발 TDD(Test-Driven Development) 이해하기 (0) | 2026.05.05 |
| CQRS 개념과 Read-Your-Own-Writes 해결 전략 (0) | 2026.02.09 |
| PWA(Progressive Web App)의 개념과 실행 프로세스 이해 (0) | 2026.01.08 |