Kubernetes로 대용량 오픈소스 웹 상용화하기 시리즈 목차
- 대용량 트래픽을 고려한 오픈소스 선정 및 분석
- 컨테이너화와 Kubernetes 리소스 관리 (Pod, Deployment, StatefulSet)
- Helm chart로 Kubernetes에 오픈 소스 웹 배포하기
- Kubernetes 서비스(Service) 및 Ingress 관리 (HTTP 및 gRPC 프로토콜 이해)
- 보안 강화를 위한 인증서(Certificate) 관리
- 서비스 안정성을 위한 튜닝(성능테스트, HA 구성, 리소스 최적화)
Kubernetes로 대용량 오픈소스 웹 상용화하기 ⑤: 보안 강화를 위한 인증서(Certificate) 관리
Kubernetes로 대용량 오픈소스 웹 상용화하기 시리즈 목차대용량 트래픽을 고려한 오픈소스 선정 및 분석컨테이너화와 Kubernetes 리소스 관리 (Pod, Deployment, StatefulSet)Helm chart로 Kubernetes에 오픈 소스
develiro.tistory.com
드디어 대망의 시리즈 마지막 글입니다👏
지금까지 쿠버네티스에 애플리케이션을 배포하고, Ingress 및 인증서를 세팅해서 운영환경에 사용할 수 있도록 해보았는데요,
사실 이제부터 시작이죠. 다음 고민은 “얼마나 앱이 잘 버틸 수 있는가”입니다.
사용자가 늘어나거나 데이터가 몰릴 때, 서비스가 끊기지 않고 안정적으로 응답할 수 있어야 진짜 운영 가능한 상태라고 할 수 있겠습니다.
이번 글에서는 Langfuse self-hosted 버전을 기준으로 성능테스트를 어떻게 진행했고,
그 결과를 바탕으로 고가용성(HA) 구성과 리소스 최적화를 어떻게 적용했는지를 정리해보려 합니다.
1. 왜 성능테스트가 필요할까?
개발 단계에서는 요청량도 적고, 쌓인 데이터도 많지 않기 때문에 대체로 잘 돌아갑니다.
하지만 실제 운영 환경에선 트래픽이 순간적으로 몰릴 수도 있고, 조회 대상이 되는 데이터 양도 점점 많아집니다.
특히 Langfuse처럼 로그, 트레이스, 스코어링 데이터를 수집하고 분석하는 시스템은
쓰기(데이터 적재)와 읽기(대시보드 조회)가 동시에 이뤄지기 때문에,
전체적인 처리 흐름이 얼마나 안정적으로 동작하는지 미리 확인할 필요가 있었습니다.
그래서 본격적인 운영에 들어가기 전, 다음과 같은 질문들에 대한 답을 얻기 위해 성능 테스트를 진행했습니다.
- Web과 Worker 파드를 몇 개까지 늘리면 처리량이 얼마나 증가할까?
- CPU나 메모리를 늘리면 실제로 응답 속도가 빨라질까?
- ClickHouse는 어느 정도 메모리를 줄 때 가장 안정적으로 동작할까?
2. 성능테스트 진행
테스트 대상 구성
https://develiro.tistory.com/16 에서의 Langfuse 어플리케이션 아키텍처에서 확인할 수 있는 리소스들은 여러가지 입니다.
하지만 빠른 시간 내에 유의미한 결과를 내야했기 때문에, 크게 세 가지 컴포넌트를 테스트 대상으로 삼았습니다.
- Web: 사용자 요청을 처리하고 대시보드를 제공하는 API 서버
- Worker: SDK에서 수집한 데이터를 비동기로 처리해 DB에 적재
- ClickHouse: 모든 트레이스, 로그, 평가 결과가 저장되는 데이터베이스
이 중 어느 하나라도 병목이 생기면 전체 서비스 품질에 영향을 주기 때문에,
테스트는 각각의 요소를 독립적으로, 또 조합해서 진행했습니다.
(+당연히 세부적인 테스트를 진행하려면 추후 Redis, PostgreSQL, Blob Storage도 성능 테스트 대상에 포함시켜야 합니다.)
테스트 방식
성능 테스트는 아래 두 가지 방식으로 진행했습니다.
- Locust를 활용해 사용자 요청을 시뮬레이션하며 Web 파드의 처리량을 측정
- Langfuse API를 Python 코드로 직접 호출하며 Worker와 ClickHouse의 쓰기 처리 성능을 확인
Locust란?
Locust는 Python 기반의 오픈소스 부하 테스트 도구입니다.
HTTP 요청 흐름을 코드로 정의한 뒤, 수백 명의 가상 사용자가 동시에 접속했을 때의 성능을 측정할 수 있습니다.
아래는 대시보드에서 트레이스를 조회하고 상세 페이지를 보는 흐름을 시뮬레이션한 예시입니다.
# locustfile.py
from locust import HttpUser, task, between
class DashboardUser(HttpUser):
wait_time = between(0.5, 1.5)
@task(3)
def list_traces(self):
self.client.get("/api/traces?limit=50")
@task(1)
def view_trace_detail(self):
self.client.get("/api/traces/trc_1234567890abcdef")
# 실행 명령어
locust --headless -u 100 -r 10 -t 10m -H https://your-langfuse.example.com
- -u: 최대 가상 사용자 수
- -r: 초당 사용자 증가 속도
- -t: 테스트 시간
이렇게 해서 Web 파드 수를 1개, 2개, 4개로 바꿔가며 요청 처리량과 응답 시간을 측정했습니다.
Python으로 직접 API 호출
쓰기 부하는 Langfuse의 /ingest API를 직접 호출하며 테스트했습니다.
수집 트래픽은 Locust보다 단순하게, 반복 호출하는 스크립트로 구현하는 게 효율적이었습니다.
import requests, time, random
host = "https://your-langfuse.example.com"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
for _ in range(10000):
payload = {
"name": "inference",
"timestamp": time.time(),
"latency_ms": random.randint(100, 500),
"input": {"question": "Hello?"},
"output": {"answer": "Hi!"}
}
requests.post(f"{host}/api/public/ingest/trace", json=payload, headers=headers)
time.sleep(random.uniform(0.05, 0.2))
Worker 파드 수를 1개에서 6개까지 늘려가며, 큐 처리 지연이나 ClickHouse 적재 속도가 얼마나 달라지는지를 관찰했습니다.
3. 테스트 결과
Web/Worker 파드 수
- Web 파드를 1개에서 2개로 늘렸을 때, 요청 처리량(QPS)은 거의 2배 증가했습니다.
- 하지만 4개 이상으로 늘렸을 땐 개선 폭이 줄어들었고, 이 시점부터는 ClickHouse가 병목이 되기 시작했습니다.
- Worker 파드는 6개까지는 수집 지연이 뚜렷하게 줄었고, 6개부터도 데이터 처리 증가 효과를 보이긴 하였으나, 대량 수집 상황이 아닌 이상 큰 차이는 없었습니다.
CPU 제한
- Web과 Worker를 1 vCPU로 실행했을 때는 간헐적으로 요청이 지연되거나 타임아웃이 발생했습니다.
- 2 vCPU로 늘리자 처리량이 안정되었고,
- 4 vCPU에선 추가적인 성능 향상은 제한적이었습니다. (CPU보단 I/O가 병목이라는 신호)
ClickHouse 메모리
- 4GB 환경에선 대시보드 쿼리 응답이 불안정했고,
- 8GB로 올리니 대부분의 지연이 해결됐습니다.
- 16GB까지 올렸을 땐 성능이 약간 개선되긴 했지만, 운영 비용을 고려하면 8GB가 가장 효율적이었습니다.
4. 고가용성(HA) 구성
성능이 잘 나오는 것도 중요하지만, 파드 하나가 죽었다고 전체 서비스가 멈춘다면 의미가 없습니다.
그래서 다음과 같은 방식으로 고가용성을 구성했습니다.
- HPA (Horizontal Pod Autoscaler)
CPU 사용량이 65%를 넘으면 자동으로 파드를 증설, 30% 미만이면 축소 - PodDisruptionBudget
노드 교체나 롤링 업데이트 시에도 최소한의 파드 수를 유지해 중단 방지 - 분산 배치 설정
Web/Worker 파드가 같은 노드에 몰리지 않도록 anti-affinity 적용
또한 테스트 환경에서 일부러 파드를 삭제하거나 노드를 드레인해보며, 서비스가 끊기지 않는지도 확인했습니다.
그 결과, 순간적인 에러 스파이크는 있었지만 빠르게 복구됐고 데이터 유실도 없었습니다.
5. 리소스 최적화 – 안정성과 비용의 균형
마지막 단계는 리소스를 얼마나 효율적으로 쓸 수 있느냐였습니다.
단순히 파드 수를 늘리고 CPU를 크게 할당하는 건 쉽지만, 클라우드에서는 비용이 곧 실적입니다.
최종적으로는 아래와 같은 리소스 구성을 적용했습니다.
구성 요소 | 기본 리소스 | 최대 리소스 | 비고 |
Web | 1 vCPU / 1Gi | 최대 3개까지 확장 | 대시보드 요청 대응 |
Worker | 2 vCPU / 2Gi | 최대 6개까지 확장 | 수집 처리용 |
ClickHouse | 8Gi 메모리 + SSD 스토리지 | - | 읽기/쓰기 병목 해결 |
HPA 설정 | CPU 65% 기준 | 필요 시 자동 확장 | Web/Worker 공통 |
운영 환경에서는 최소한의 자원으로 평균 트래픽을 감당하고,
트래픽이 몰릴 때만 자동으로 확장할 수 있도록 구성하는 것이 핵심입니다.
마무리 – 이제 운영할 준비가 되었습니다🎉
이번 글에서는 Langfuse self-hosted를 기준으로, 실제 성능 테스트를 어떻게 했고
그 결과를 바탕으로 어떻게 고가용성과 리소스 최적화를 적용했는지를 소개했습니다.
지금까지의 시리즈를 통해 우리는
- 오픈소스 선정과 아키텍처 분석
- Kubernetes 리소스 관리
- Helm Chart 배포
- Ingress와 HTTPS 구성
- 그리고 서비스 안정화를 위한 튜닝까지
실제로 운영 가능한 수준의 인프라를 직접 구성해보았습니다.
이제 남은 건 이 기반 위에 비즈니스 로직을 추가하는 일이겠네요.
아키텍처 검증, 배포부터 테스트 및 운영까지 다른 서비스에도 적용할 수 있도록 저만의 방식으로 정리해보았습니다.
도움이 되셨으면 좋겠네요.
감사합니다!
'Technical architecture > Kubernetes' 카테고리의 다른 글
Kubernetes로 대용량 오픈소스 웹 상용화하기 ⑤: 보안 강화를 위한 인증서(Certificate) 관리 (3) | 2025.08.10 |
---|---|
Kubernetes로 대용량 오픈소스 웹 상용화하기 ④: Ingress로 외부통신 설정하기 (3) | 2025.07.27 |
Kubernetes로 대용량 오픈소스 웹 상용화하기 ③: Helm chart로 Kubernetes에 오픈 소스 웹 배포하기 (3) | 2025.07.13 |
Kubernetes로 오픈소스 상용화하기 ②: 컨테이너화와 Kubernetes 리소스 관리 (5) | 2025.06.22 |
Kubernetes로 대용량 오픈소스 웹 상용화하기 ①: 아키텍처와 선정 전략 (7) | 2025.06.15 |