[Project : Gold-Rush-Lab] 0. 모놀리식에서 분산 시스템까지
개요
최근 주식 시장이 빈번하게 급등, 급락을 반복하며 사이드카로 인해 멈추는 일이 빈번하다.
이러한 주식 시작의 안정성을 도모하는 정책은 내게 어떠한 영감을 줬다.
- 급등/급락 → 매도/매수 요청의 증가 → 트래픽 증가 = 대규모 트래픽
이러한 상황을 모방할 수 있다면, 여러가지 관측과 그 간의 궁금증에 대한 해결이 가능하겠다는 생각을 했다.
나는 지금까지 스타트업, 사이드 프로젝트, 개인 프로젝트를 통해 다양한 경험을 했지만 그 규모가 크지 않았기에
MSA, 분산시스템, 대용량 트래픽 을 ‘가정한’ 개발은 진행했지만 실제로 이를 겪어본 경험은 적다.
이러한 ‘가정 개발’을 진행하면서 항상 풀리지 않는 의구심이 있었다.
실제로 어떤 규모의 트래픽과 문제에 어떤 아키텍처가 적용 되어야 오버엔지니어링이 아니면서도 책임을 완수하는 시스템 인가?
나는 이 프로젝트를 통해서 위 의구심을 풀고자 한다.
처음에는 실제 주식 데이터를 수집해 시장 상황을 반영할지, 모의 시세를 생성할지 고민했다.
하지만 프로젝트를 설계할수록 한 가지 사실이 분명해졌다. 내가 알고 싶은 것은 주식 시장을 구현하는 방법이 아니라, 급격한 트래픽 증가 상황에서 시스템이 어떤 방식으로 정합성을 유지하는지였다.
따라서 주식이라는 도메인은 과감히 걷어내고, 관찰하고 싶은 현상만 남기기로 했다.
먼저 주식 시장에서는 다양한 종목이 매수되고 매도되지만, 주목한 것은 특정 종목에 대한 매매의 빈도가 급증한 다는 것 이었다.
주식 시장에서 하나의 종목으로 매매 요청이 몰리는 상황을 한정된 양의 금을 여러 사용자가 동시에 채굴하는 광산이라는, 훨씬 단순환 모델로 치환했다.
또한 유저는 지속적으로 상태를 관리할 필요가 없으며, 채굴 결과에 대한 감사로그 정도만 있으면 될 것을 가정으로 본격적인 프로젝트 설계에 들어갔다.
이를 토대로 프로젝트의 이름은 하나의 광맥을 향해 달려드는 요청과 프로젝트가 하나의 실험실이 될 것 이므로
Gold-Rush-Lab으로 정했다.
이 Gold-Rush-Lab을 통해서 실험을 만들어가는 과정을 블로그에 녹여내보고자 한다.
Gold Rush Lab
이 프로젝트는 가장 단순한 형태인 모놀리식 아키텍처를 시작으로, 아주 작은 규모의 분산 시스템 까지 성장 시키며 그 안에서 발생하는 자원, 경합, 에러들을 재현하는 것이 그 의의다. 한 문장으로 정리하자면 아래와 같이 되겠다.
한정된 자원을 여러 사용자가 동시에 요청할 때, 시스템의 구조가 달라짐에 따라 데이터의 정합성과 처리 성능은 어떻게 변화하는가?
아래에 로드맵을 통해서 어떻게 시스템을 발전시킬지와 성능을 검증할 지표들을 정리해두었다.
공통 구성
- Hyper - V: 시스템 환경 구성 (부자는 아니지만 데스크탑 메모리는 조금 여유가 있다)
- Grafana, Prometheus: 지표 측정과 시각화
로드맵
v0.1 - 모놀리식
목표
Lost Update 발생 확인
구성
Spring Boot PostgreSQL
관측 지표
- TPS
- Avg/P95/P99
- CPU
- Heap
- Remaining Gold
- Mining Log
v0.2 - DB Lock
목표
동시성 제어 방식 비교
구성
- Optimistic Lock
- Pessimistic Lock
비교 지표
- Retry
- Lock Wait
- Deadlock
- TPS
- Latency
v0.3 - Scale-out
목표
애플리케이션을 늘리면 정말 성능이 좋아지는가?
구성
- Nginx
- App ×2
- PostgreSQL
비교 지표
- TPS
- Latency
- DB Connection
- CPU
v0.4 - Distributed Lock
목표
DB Lock과 Redis Lock 비교
구성
- Redis
- Nginx
- App ×2
비교 지표
- Lock Wait
- Redis Command
- TPS
- Latency
v0.5 - Kafka
목표
동기 처리와 비동기 처리 비교
구성
- Kafka
- Redis
- App ×2
비교 지표
- Queue Length
- Consumer Lag
- Throughput
- Latency
지표 선정 기준
| 버전 | 지표 | 선정 이유 | 확인하려는 내용 |
|---|---|---|---|
| v0.1모놀리식 | TPS | 기본 처리량 측정 | 시스템이 초당 얼마나 많은 요청을 처리하는가 |
| Avg / P95 / P99 Latency | 평균뿐 아니라 Tail Latency 확인 | 동시 요청이 증가할수록 응답시간이 얼마나 악화되는가 | |
| CPU | 시스템 자원 사용량 확인 | 성능 저하가 CPU 부족 때문인지 확인 | |
| Heap | 메모리 사용량 및 GC 영향 확인 | 메모리 병목 여부 및 이후 버전과의 기준(Baseline) | |
| Remaining Gold | 데이터 정합성 검증 | Lost Update로 인해 남은 금의 수량이 올바른가 | |
| Mining Log | 요청 흐름 추적 | 어떤 요청에서 데이터 정합성이 깨졌는지 분석 | |
| v0.2DB Lock | Retry | Optimistic Lock 충돌 횟수 측정 | 충돌이 얼마나 자주 발생하는가 |
| Lock Wait | Lock 대기 시간 측정 | Lock으로 인해 얼마나 지연되는가 | |
| Deadlock | 교착 상태 발생 여부 | Lock 전략이 안정적으로 동작하는가 | |
| TPS | Lock 적용 후 처리량 비교 | 동시성 제어가 처리량에 미치는 영향 | |
| Latency | 응답시간 비교 | Lock 비용으로 인해 응답시간이 얼마나 증가하는가 | |
| v0.3Scale-out | TPS | Scale-out 효과 측정 | 애플리케이션을 늘리면 처리량이 증가하는가 |
| Latency | 응답시간 변화 확인 | Scale-out이 사용자 응답시간을 개선하는가 | |
| DB Connection | DB 병목 확인 | 애플리케이션 증가가 DB Connection 병목을 만드는가 | |
| CPU | 병목 위치 분석 | 병목이 App인지 DB인지 확인 | |
| v0.4Distributed Lock | Lock Wait | Lock 대기시간 비교 | Redis Lock이 DB Lock보다 대기시간을 줄이는가 |
| Redis Commands | Redis 부하 측정 | Lock 획득/반납 과정에서 Redis가 병목이 되는가 | |
| TPS | 처리량 비교 | Lock 구현 방식이 처리량에 미치는 영향 | |
| Latency | 네트워크 비용 측정 | Redis 사용으로 응답시간이 증가하는가 | |
| v0.5Kafka | Queue Length | 큐 적체 확인 | Producer가 Consumer보다 빠른가 |
| Consumer Lag | Kafka 처리 지연 측정 | Consumer가 메시지를 제때 처리하는가 | |
| Throughput | 실제 처리량 측정 | 비동기 방식이 얼마나 많은 작업을 처리하는가 | |
| Latency | End-to-End 처리시간 측정 | 비동기 처리가 전체 완료 시간을 어떻게 변화시키는가 |
공통적으로 함께 보면 좋은 지표
| 지표 | 선정 이유 |
|---|---|
| Error Rate | 실패 요청 비율을 통해 시스템 안정성 평가 |
| Success Rate | 실제 성공적으로 처리된 요청 비율 확인 |
| Gold Consistency | 초기 금 - 채굴된 금 = 0이 항상 성립하는지 검증하여 데이터 정합성 확인 |
| Thread Pool Utilization | 애플리케이션 스레드가 병목인지 확인 |
| DB Active Connections | Connection Pool 포화 여부 확인 |
| GC Pause Time | GC가 성능 저하의 원인인지 분석 |
댓글남기기