Langfuse 셀프 호스팅 가이드: VPS 구축 및 운영 방법
Langfuse를 자체 VPS에 직접 설치하고 운영하는 실무 가이드입니다. ClickHouse 디스크 용량 관리, 이미지 태그 고정, TLS 설정, 데이터 백업 전략 등 프로덕션 환경에서 반드시 고려해야 할 핵심 설정과 리소스 최적화 노하우를 상세히 설명합니다.
AI 에이전트를 추적해야 하는 이유
Langfuse를 직접 호스팅하면 에이전트가 실행 중에 실제로 어떤 작업을 수행했는지 확인할 수 있습니다. Langfuse는 오픈 소스 LLM(거대 언어 모델) 관측성 도구입니다. 모든 프롬프트, 모델 응답, 도구 호출, 토큰을 기록한 뒤 이를 하나의 추적(trace)으로 묶어 사용자가 열람할 수 있게 합니다. 자체 VPS에서 실행하면 프롬프트가 사용자가 제어하는 서버 외부로 유출되지 않습니다.
추적을 수행해야 하는 이유는 명확합니다. 볼 수 없는 비용 문제나 품질 문제는 해결할 수 없기 때문입니다. 공급자의 청구서에는 화요일 비용이 월요일보다 4배 높았다는 사실만 나타납니다. 반면 추적을 확인하면 어떤 에이전트 실행이 원인인지, 어떤 프롬프트가 40,000 토큰까지 증가했는지, 어떤 재시도 루프가 9번 반복된 후 종료되었는지 알 수 있습니다. 청구서는 결과 수치만 보여주지만, 추적은 그 수치를 만들어낸 코드를 보여줍니다.
이 가이드에서는 세 가지 용어를 사용합니다. 추적(trace)은 에이전트의 전체 실행 과정을 의미합니다. 관측(observation)은 실행 내부의 단일 단계를 의미하며, 일반 코드 실행을 위한 스팬(span)과 모델 호출을 위한 생성(generation)으로 나뉩니다. 점수(score)는 사람의 검토나 자동 평가 도구를 통해 추적에 부여된 수치입니다. Langfuse는 분산 추적을 위한 벤더 중립 표준인 OpenTelemetry(OTel)를 지원하므로, 이미 구축된 계측 도구를 그대로 연결할 수 있습니다.
Langfuse 셀프 호스팅의 실제 구성
Langfuse v4는 단일 컨테이너가 아닙니다. 두 개의 애플리케이션 컨테이너와 네 개의 저장소 서비스로 구성되며, 단일 VPS 환경에서는 이 여섯 가지가 모두 해당 서버에서 실행됩니다.
langfuse-web은 웹 인터페이스와 수집 API를 제공합니다.langfuse-worker은 백그라운드에서 큐를 처리합니다. 수집된 배치 데이터를 파싱하고 비용을 계산하며, 야간 보존 작업을 수행합니다.- Postgres는 사용자, 조직, 프로젝트, API 키, 프롬프트와 같은 트랜잭션 데이터를 저장합니다.
- ClickHouse는 추적 데이터 자체(관측값 및 점수)를 저장합니다. 분석 쿼리에 최적화된 컬럼형 저장소이므로 수억 개의 행이 있는 대시보드도 빠르게 응답합니다.
- Redis는 웹과 워커 사이에서 큐 및 캐시 역할을 합니다.
- MinIO는 서버 내에서 S3 호환 객체 스토리지를 제공합니다. 모든 원본 수신 이벤트와 첨부된 미디어를 저장합니다.
Langfuse는 작업을 수행하는 세 가지 구성 요소에 대한 최소 리소스 요구 사항을 게시하고 있습니다.
The data behind this chart
[
{
"label": "ClickHouse",
"cpu_cores": 2,
"memory_gib": 8
},
{
"label": "Langfuse web",
"cpu_cores": 2,
"memory_gib": 4
},
{
"label": "Langfuse worker",
"cpu_cores": 2,
"memory_gib": 4
}
]ClickHouse 단독으로만 8 GiB의 메모리를 요구합니다. 웹 컨테이너와 워커는 각각 4 GiB를 요구합니다. 이는 Langfuse가 크기를 산정하는 3개 구성 요소의 최소 사양이며, Postgres, Redis, MinIO는 별도의 메모리가 추가로 필요합니다. 프로젝트의 공식 Docker Compose 가이드에서는 4코어 CPU, 16 GiB 메모리, 약 100 GiB의 스토리지를 권장하며, 이는 단순 여유 공간을 포함한 수치가 아니라 실제 연산 결과에 부합하는 사양입니다.
2 GiB 플랜에서 시도하지 마십시오. ClickHouse가 시작되어 잠시 쓰기 작업을 수행하다가 백그라운드 병합 과정에서 종료될 것입니다. 병합 작업은 테이블의 상당 부분을 메모리에 로드하기 때문입니다. 이때 docker compose ps은 clickhouse 컨테이너를 restarting 상태로 보고하며, dmesg에는 Out of memory: Killed process 1234 (clickhouse-serv)과 같은 메시지가 기록되고, 모든 Langfuse 대시보드는 500 오류를 반환하게 됩니다. 부하가 적을 때는 ClickHouse가 쿼리를 거부하고 DB::Exception: Memory limit (total) exceeded를 로그에 남깁니다. 8 GiB는 하루에 수천 개의 추적을 보내는 개발자 한 명에게는 운용 가능한 수준입니다. 16 GiB를 기준으로 계획하십시오.
Docker Compose로 Langfuse 배포하기
저장소를 복제합니다. 스택, 연결 설정, 기본 환경 변수는 모두 docker-compose.yml에 있습니다.
git clone https://github.com/langfuse/langfuse.git
cd langfuse변경해야 할 모든 값은 해당 파일 내 # CHANGEME로 표시되어 있습니다. 먼저 세 가지 애플리케이션 보안 키를 생성합니다.
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYENCRYPTION_KEY는 64자리 16진수 문자로 작성된 256비트 값이어야 하며, 이는 openssl rand -hex 32 명령어로 정확히 생성할 수 있습니다. 이 값은 인스턴스에 저장된 LLM 제공업체 키를 포함하여 저장된 민감한 데이터를 암호화합니다. 데이터가 생성된 이후에 이 값을 변경하면 기존 데이터를 복호화할 수 없으므로, 첫 부팅 시점부터 영구적인 값으로 취급해야 합니다. SALT은 Langfuse API 키를 해싱하는 데 사용되므로, 이 값을 변경하면 에이전트가 이미 사용 중인 모든 키가 무효화됩니다.
그다음 POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH, MINIO_ROOT_PASSWORD을 설정합니다. MinIO 비밀번호는 MINIO_ROOT_PASSWORD, LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY와 같이 네 곳에 나타납니다. 하나라도 누락되면 MinIO는 SignatureDoesNotMatch 오류와 함께 클라이언트 연결을 거부하며, 웹 인터페이스는 정상으로 보여도 워커 로그에는 해당 오류가 기록됩니다. 이러한 값을 추적되는 compose 파일 대신 env 파일에 보관하는 방식은 Docker Compose env 파일 및 보안 키에서 다룹니다.
시작 전 이미지 태그 고정하기
제공되는 파일은 langfuse/langfuse:4 및 langfuse/langfuse-worker:4 태그를 사용합니다. 이 태그들은 계속 변경됩니다. Langfuse는 시작 시 Postgres 및 ClickHouse 마이그레이션을 자동으로 수행하므로, 몇 달 뒤 일상적인 docker compose pull를 실행하면 당일 백업을 수행하지 않은 데이터베이스에서 예기치 않은 스키마 마이그레이션이 발생할 수 있습니다. 두 태그를 docker-compose.override.yml 파일 내 특정 릴리스 버전으로 고정하십시오. Compose는 이 파일을 기존 파일 위에 병합하므로, 나중에 git pull을 실행해도 사용자가 수정한 내용이 덮어씌워지지 않습니다.
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.3.1
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.3.1버전 4.3.1은 2026년 8월 기준 최신 4.3 릴리스였습니다(이후 4.4.0이 릴리스되었습니다). 프로젝트의 GitHub 릴리스 페이지를 확인하여 배포 당일 최신 버전을 고정하고, 이후 의도적으로 버전을 업데이트하십시오. 제공된 파일의 스토리지 이미지들은 이미 메이저 버전인 postgres:17, clickhouse-server:25.12, redis:7로 고정되어 있으며, 이들 역시 동일하게 관리해야 합니다.
서비스를 시작합니다.
docker compose up -d
docker compose ps
docker compose logs -f langfuse-worker첫 부팅 시 마이그레이션이 실행되므로 응답이 올 때까지 1~2분 정도 기다려야 합니다. docker compose ps를 실행하면 6개의 서비스가 running 상태로 표시되어야 합니다. 워커가 반복적으로 재시작된다면 로그에서 원인을 확인하십시오. CLICKHOUSE_MIGRATION_URL은 포트 8123(HTTP 포트)이 아닌 9000번 포트의 ClickHouse 네이티브 프로토콜을 사용합니다. 8123번 포트로 설정하면 웹 컨테이너는 정상으로 보여도 워커에서 연결 오류가 발생합니다.
서버 내부에서 상태를 확인합니다.
curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/ready단순한 /api/public/health 호출은 API 프로세스가 살아있음만 증명합니다. 이는 데이터베이스 연결을 의도적으로 건너뛰어 Postgres에 일시적인 문제가 생겨도 서비스가 계속 유지되도록 하기 때문입니다. 모니터링 도구에는 failIfDatabaseUnavailable=true 형태를 사용하는 것이 좋으며, 데이터베이스에 연결할 수 없을 때 503을 반환합니다. /api/public/ready은 마이그레이션이 완료되고 컨테이너가 트래픽을 수용할 준비가 되면 200을 반환합니다. 두 방식 모두 일반적인 HTTP 체크이므로, Uptime Kuma 상태 페이지를 통해 에이전트보다 먼저 스택의 다운 여부를 감지할 수 있습니다.
TLS를 전면에 배치하고 추가 포트 닫기
배포된 compose 파일은 웹 컨테이너를 위해 3000:3000을, MinIO를 위해 9090:9000를 게시합니다. 두 포트 모두 모든 인터페이스에 바인딩됩니다. 공인 IP 환경에서 이는 포트 3000을 스캔하는 누구든 가입 페이지에 접근할 수 있고, 9090을 스캔하는 누구든 원본 프롬프트가 저장된 버킷과 통신할 수 있음을 의미합니다.
방화벽 규칙만으로는 이 포트들을 닫을 수 없습니다. Docker는 자체적으로 nat 테이블에 DNAT 규칙을 작성하며, 이 규칙은 ufw의 필터 규칙이 패킷을 확인하기 전에 먼저 평가되므로 ufw deny 3000은 게시된 포트를 그대로 열어둡니다. 이 문제는 매우 흔하여 별도의 가이드가 존재합니다: Docker 게시 포트가 ufw를 우회하는 이유. 대신 override 파일에서 루프백(loopback) 주소에 바인딩하십시오.
services:
langfuse-web:
ports:
- "127.0.0.1:3000:3000"
environment:
NEXTAUTH_URL: https://langfuse.example.com
minio:
ports:
- "127.0.0.1:9090:9000"
- "127.0.0.1:9091:9001"NEXTAUTH_URL는 스킴(scheme)을 포함한 정확한 공인 주소여야 합니다. 로그인 흐름이 해당 값을 기반으로 콜백 URL을 생성하기 때문입니다. HTTPS 프록시 뒤에서 이를 http://localhost:3000로 두면, 로그인 왕복 과정에서 브라우저가 도달할 수 없는 곳으로 리다이렉트됩니다.
이제 리버스 프록시를 127.0.0.1:3000으로 지정하고 인증서를 관리하게 하십시오. 동일한 Compose 프로젝트 내의 Traefik을 사용하는 것이 일반적이며, 라우팅 레이블은 하나의 Traefik 리버스 프록시 뒤에서 여러 앱 실행하기에서 다루는 내용을 따릅니다. 서버에 Langfuse만 운영한다면 Caddy를 사용하여 두 줄의 설정으로 동일한 작업을 수행할 수 있습니다. curl -sI https://langfuse.example.com/api/public/ready로 확인한 뒤, 다른 기기에서 curl http://YOUR_IP:3000이 타임아웃되는지 확인하십시오.
MinIO 사용 시 주의할 점이 하나 있습니다. Langfuse는 S3 엔드포인트를 가리키는 사전 서명된 URL(presigned URL)을 통해 첨부된 미디어를 브라우저로 제공합니다. 따라서 이미지나 오디오가 포함된 멀티모달 트레이스를 사용하는 경우, 루프백 전용으로 설정된 MinIO에서는 해당 첨부 파일이 로드되지 않습니다. 프록시를 설정하기 전에 블록 스토리지 구성 페이지를 읽어보십시오. 사전 서명된 URL에 기록되는 엔드포인트는 사용자가 게시하는 주소와 일치해야 하기 때문입니다. 일반 텍스트 트레이스는 영향을 받지 않습니다.
첫 방문 시 계정을 생성한 후, 해당 인스턴스를 본인 전용으로 유지하십시오. LANGFUSE_ALLOWED_ORGANIZATION_CREATORS를 본인의 이메일 주소로 설정하여, 페이지에 접속한 낯선 사람이 서버에 조직을 생성하지 못하도록 하십시오.
첫 번째 트레이스 전송하기
웹 인터페이스에서 프로젝트를 생성하고 프로젝트 설정에서 공개 키와 비밀 키를 복사합니다. Python SDK는 세 가지 환경 변수를 읽어 들입니다.
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://langfuse.example.com"LANGFUSE_BASE_URL은 2026년 3월에 릴리스된 SDK v4에서 사용하는 변수명입니다. 이전 코드나 가이드에서는 LANGFUSE_HOST을 사용합니다. 트레이스가 서버가 아닌 Langfuse Cloud로 전송된다면, 기본값이 호스팅된 인스턴스를 가리키기 때문에 베이스 URL이 설정되지 않은 것이 원인입니다.
pip install langfuse opentelemetry-instrumentation-anthropic anthropicimport os
from anthropic import Anthropic
from langfuse import get_client, observe
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
AnthropicInstrumentor().instrument()
langfuse = get_client()
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
@observe(as_type="tool")
def lookup_order(order_id: str) -> str:
return f"order {order_id}: shipped"
@observe()
def handle_request(question: str) -> str:
context = lookup_order("A-1042")
message = client.messages.create(
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": f"{context}\n\n{question}"}],
)
return message.content[0].text
if __name__ == "__main__":
assert langfuse.auth_check()
print(handle_request("Where is my order?"))
langfuse.flush()@observe 데코레이터는 함수를 감싸는 관찰(observation)을 시작하여 인자와 반환값을 캡처하고, 이미 활성화된 관찰 하위에 중첩합니다. AnthropicInstrumentor은 Anthropic 클라이언트를 위한 OpenTelemetry 계측 도구이며, 호출 지점의 변경 없이 각 messages.create 호출을 모델명, 토큰 사용량, 지연 시간을 포함하는 생성(generation)으로 변환합니다.
두 가지 호출을 통해 확인 작업을 수행할 수 있습니다. langfuse.auth_check()는 잘못된 키나 베이스 URL이 설정된 경우 False를 반환하며, 이는 대시보드가 비어 있는 이유를 고민하는 것보다 빠릅니다. langfuse.flush()은 큐에 담긴 스팬(span)이 모두 전송될 때까지 대기합니다. SDK는 백그라운드에서 배치를 처리하므로, 즉시 종료되는 스크립트는 전송되지 않은 배치를 함께 소멸시키기 때문에 단기 프로세스에서는 이 호출이 필요합니다.
ClickHouse의 디스크 사용량이 계속 증가하는 이유는 무엇입니까?
트레이스(trace) 데이터는 개인이 직접 호스팅하는 데이터 중 가장 빠르게 증가하는 데이터입니다. 에이전트가 실행될 때마다 단계별로 한 행씩 기록되며, 입력과 출력 전체가 저장됩니다. 따라서 긴 프롬프트를 사용하는 에이전트는 감시 대상 애플리케이션보다 훨씬 많은 바이트를 매일 생성합니다. 방치할 경우 ClickHouse는 디스크를 가득 채우게 되며, 디스크가 가득 차면 데이터 수집 속도가 느려지는 것이 아니라 아예 중단됩니다.
여기에는 두 가지 별개의 증가 요인이 있으며, 각각 다른 해결책이 필요합니다.
첫 번째는 사용자의 트레이스 데이터이며, 해결책은 보존(retention) 설정입니다. 웹 인터페이스에서 프로젝트 설정을 열고 데이터 보존 기간을 일 단위로 설정하십시오. Langfuse는 최소 3일 이상의 보존 기간을 지원합니다. 매일 밤 실행되는 작업이 해당 기간보다 오래된 트레이스, 관찰(observation), 점수(score) 및 미디어 자산을 선택하여 ClickHouse와 블롭(blob) 저장소에서 삭제합니다. 이 작업에는 버킷에 대한 DeleteObject 권한이 필요하며, 기본 compose 파일의 MinIO 루트 자격 증명은 이미 이 권한을 가지고 있습니다. 삭제는 영구적이므로 장기 기록이 필요하다면 먼저 블롭 저장소 내보내기를 구성하십시오. Langfuse의 테이블에 직접 TTL 구문을 작성하지 마십시오. 보존 작업이 ClickHouse와 버킷의 동기화를 유지하며, 수동으로 TTL을 설정하면 한쪽만 삭제될 수 있습니다.
실제 사용량에 맞춰 기간을 선택하십시오. 비용 및 품질 검토는 수개월 전 데이터가 아닌 며칠 전 데이터를 대상으로 수행됩니다. 소규모 팀의 경우 30일이 적절한 시작점이며, 문제가 발생했을 때만 트레이스를 확인한다면 14일로도 충분합니다.
두 번째는 ClickHouse 자체의 시스템 로그 테이블입니다. 보존 설정을 마쳤음에도 디스크가 계속 증가하여 많은 사용자가 당황하곤 합니다. ClickHouse는 진단을 위해 trace_log, text_log, opentelemetry_span_log, metric_log 및 asynchronous_metric_log를 기록하는데, 여기에는 기본적으로 TTL이 없으며 Langfuse는 이를 읽지 않습니다. 먼저 디스크 공간을 실제로 점유하고 있는 항목을 확인하십시오.
SELECT table, formatReadableSize(size) AS size, rows FROM (
SELECT table, database, sum(bytes) AS size, sum(rows) AS rows
FROM system.parts
WHERE active
GROUP BY table, database
ORDER BY size DESC
)docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD"를 사용하여 실행하십시오. 시스템 테이블이 상위권에 있다면 설정 오버레이를 사용하여 비활성화하십시오. ClickHouse는 시작 시 /etc/clickhouse-server/config.d/의 모든 파일을 기본 설정 위에 병합합니다.
<clickhouse>
<trace_log remove="1"/>
<text_log remove="1"/>
<opentelemetry_span_log remove="1"/>
<asynchronous_metric_log remove="1"/>
<metric_log remove="1"/>
</clickhouse>이를 마운트하고 ClickHouse를 재시작하십시오.
services:
clickhouse:
volumes:
- ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:ro이렇게 하면 새로운 쓰기가 중단됩니다. 이미 디스크에 있는 행은 그대로 유지되므로 DROP TABLE IF EXISTS system.trace_log를 사용하여 공간을 명시적으로 회수하십시오. 제거한 각 테이블에 대해서도 동일하게 수행합니다. 진단 데이터를 유지하고 싶다면 remove="1" 대신 각 테이블에 공격적인 TTL을 설정하는 대안이 있으며, 이는 Langfuse 확장성 문서에 자세히 설명되어 있습니다.
알아두어야 할 테이블이 하나 더 있습니다. blob_storage_file_log은 버킷에 업로드된 이벤트 파일을 추적합니다. 버킷에 수명 주기 정책을 설정했다면, 두 데이터가 어긋나지 않도록 해당 테이블에도 일치하는 TTL을 설정하십시오.
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;데이터 디스크에 일반적인 df -h 알림도 설정하십시오. 트레이스는 일정하게 증가하지 않습니다. 새로운 에이전트를 배포하는 날 급격히 증가하며, 그 첫 징후가 데이터 수집 실패가 되어서는 안 됩니다.
Postgres 및 ClickHouse 백업
Langfuse 백업은 세 부분으로 구성됩니다. Postgres는 사용자, 조직, 프로젝트 및 API 키를 보관합니다. ClickHouse는 추적(trace) 데이터를 보관합니다. MinIO는 원시 이벤트를 보관합니다. Postgres만 복원하면 로그인은 가능하지만 기록이 보이지 않습니다. ClickHouse만 복원하면 기록은 있지만 아무도 로그인하여 볼 수 없습니다.
Postgres는 일반적인 pg_dump를 사용하며, 이는 Langfuse 백업 문서에서 권장하는 방식입니다.
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzClickHouse는 더 주의가 필요합니다. 병합이 진행 중일 때 데이터 디렉터리를 그대로 복사하면 일관된 백업이 되지 않기 때문입니다. 단일 서버에서 사용하는 간단한 방법은 컨테이너를 중지하고 볼륨을 아카이브하는 것입니다.
docker compose stop clickhouse
docker volume ls | grep clickhouse
docker run --rm -v langfuse_langfuse_clickhouse_data:/data -v "$PWD":/backup alpine \
tar czf /backup/langfuse-ch-$(date +%F).tar.gz -C /data .
docker compose start clickhouseYAML에 적힌 이름이 아니라 docker volume ls 명령어가 출력하는 볼륨 이름을 사용하십시오. 파일에는 langfuse_clickhouse_data라고 선언되어 있지만, Compose는 프로젝트 이름을 접두사로 붙입니다. 따라서 langfuse라는 디렉터리에서 복제하면 langfuse_langfuse_clickhouse_data이 생성됩니다. 이를 잘못 입력하면 docker run는 경고 없이 새로운 빈 볼륨을 생성하며, 결과적으로 아카이브에는 아무것도 담기지 않게 됩니다.
웹 컨테이너는 워커가 처리하기 전에 모든 수신 이벤트를 버킷에 기록하므로, ClickHouse를 잠시 중지하더라도 워커가 나중에 재시도하게 됩니다. 트래픽이 적은 시간에 수행하고 중지 시간을 짧게 유지하십시오. 인스턴스 사용량이 많다면 ClickHouse의 BACKUP DATABASE default TO S3(...) 문을 사용하여 서버를 중지하지 않고도 일관된 백업을 생성할 수 있습니다. MinIO는 세 번째 구성 요소이며, mc mirror 또는 MinIO 복제를 사용하여 외부 버킷으로 백업할 수 있습니다. 어떤 방식을 사용하든 서버 외부로 데이터를 옮겨야 하며, 이를 위해 VPS의 암호화된 restic 백업을 활용하십시오.
Redis는 백업이 필요 없습니다. 큐와 캐시만 보관하므로, 데이터가 유실되어도 처리 중이던 이벤트만 손실될 뿐 과거 데이터는 안전합니다.
일관성 문제는 실재하며 명확히 인지해야 합니다. Postgres와 ClickHouse는 서로 다른 시점에 덤프되므로, 복원 후 프로젝트 행은 존재하지만 추적 데이터가 없거나, 존재하지 않는 프로젝트의 추적 데이터가 남을 수 있습니다. Langfuse는 이러한 상황을 허용하지만, 두 덤프를 최대한 가까운 시점에, 트래픽이 적은 시간대에 수행하십시오. 이벤트 버킷은 실제 안전망 역할을 합니다. Langfuse는 처리 전 모든 수신 이벤트를 해당 버킷에 영구 저장하기 때문입니다.
최소 한 번은 테스트 환경(scratch stack)에 복원해 보십시오. 그래야 장애 상황이 아닌 지금, 잘못된 볼륨 이름을 미리 발견할 수 있습니다.
가장 먼저 확인해야 할 사항
첫 주에 반드시 확인해야 할 네 가지 항목은 다음과 같습니다.
- 트레이스당 비용. Langfuse는 모델 이름과 토큰 사용량을 바탕으로 비용을 계산합니다. 따라서 트레이스를 비용순으로 정렬한 뒤 가장 비용이 많이 발생한 트레이스를 처음부터 끝까지 검토하십시오. 원인은 보통 비대해진 프롬프트입니다. 전체 문서를 컨텍스트에 붙여넣었거나, 아무도 다듬지 않은 대화 기록이 쌓여 있는 경우가 많습니다. 이를 확인하고 나면 AI 에이전트 비용 제어는 추측이 아닌 엔지니어링 작업이 됩니다.
- 입력 및 출력별 토큰 사용량 분할. 입력 토큰은 양이 많고 저렴하지만, 출력 토큰은 양이 적고 비쌉니다. 캐시된 입력은 훨씬 더 저렴합니다. 이와 동일한 계산 방식이 Claude Code 토큰 사용량 산정 방식에 설명되어 있으며, 이는 직접 작성하는 모든 에이전트에도 적용됩니다.
- 지연 시간 백분위수. 중앙값은 문제를 숨깁니다. p95와 p99에서 타임아웃이 발생하며, 에이전트 루프 내부에서는 p95 수준의 느린 도구 호출이 반복 횟수만큼 곱해져 지연 시간이 늘어납니다.
- 실패한 도구 호출. 관측 데이터를
ERROR레벨로 필터링하십시오. 5%의 확률로 실패하는 도구는 전체 성공률 통계에서는 보이지 않지만, 트레이스에서는 매우 뚜렷하게 나타납니다. 트레이스를 보면 모델이 재시도하고 이를 우회하기 위해 토큰을 낭비하는 과정을 확인할 수 있습니다.
데이터 보존 기간을 설정하고, 배포하는 요일에 맞춰 매주 확인할 대시보드를 선택하십시오. 아무도 열어보지 않는 관측 도구는 디스크만 채우는 데이터베이스일 뿐입니다.
FAQ
자체 호스팅 Langfuse에는 메모리가 얼마나 필요한가?
4개의 CPU 코어와 16 GiB의 메모리를 계획하십시오. 이는 단일 가상 머신을 위한 Langfuse Docker Compose 가이드에서 권장하는 사양이며, 약 100 GiB의 저장 공간이 추가로 필요합니다. 공개된 구성 요소별 최소 사양은 ClickHouse의 경우 8 GiB이며, 웹 및 워커 컨테이너, Postgres, Redis, MinIO는 이와 별도로 추가 메모리가 필요합니다. 8 GiB 환경에서는 개발자 1인용 인스턴스를 실행할 수 있습니다. 2 GiB 환경에서는 실행이 불가능합니다. ClickHouse가 백그라운드 병합 중에 커널에 의해 강제 종료되며, dmesg은 Out of memory: Killed process를 보여줍니다.
데이터 보존 기간을 설정했는데도 왜 ClickHouse 디스크가 계속 가득 차는가?
보존 설정은 Langfuse의 자체 데이터에만 적용됩니다. ClickHouse는 별도로 진단 테이블인 trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log를 기록하며, 이 테이블들에는 기본적으로 TTL이 설정되어 있지 않습니다. system.parts 쿼리를 테이블별로 그룹화하여 가장 큰 테이블을 확인한 다음, /etc/clickhouse-server/config.d/ 아래의 파일에 remove="1" 항목을 추가하여 사용하지 않는 테이블을 비활성화하십시오. 이후 ClickHouse를 재시작하고 기존 테이블을 삭제하여 이미 사용 중인 공간을 확보하십시오.
Langfuse의 최소 데이터 보존 기간은 얼마인가?
3일입니다. 보존 기간은 프로젝트 설정 또는 프로젝트 API를 통해 프로젝트별로 설정하며, 매일 밤 실행되는 작업이 설정된 기간보다 오래된 트레이스, 관찰, 점수 및 미디어 자산을 ClickHouse와 blob 저장소에서 삭제합니다. 삭제된 데이터는 복구할 수 없으므로, 해당 기간 이후의 기록이 필요하다면 먼저 blob 저장소 내보내기를 구성하십시오.
Postgres와 ClickHouse를 모두 백업해야 하는가?
네, 두 데이터베이스가 서로 다른 정보를 저장하기 때문입니다. Postgres는 사용자, 조직, 프로젝트 및 API 키를 저장하며, ClickHouse는 트레이스 데이터 자체를 저장합니다. Postgres만 복원하면 로그인은 가능하지만 데이터가 없는 인스턴스가 됩니다. MinIO 버킷도 함께 백업하십시오. Langfuse가 수신 시점에 원시 이벤트를 저장하는 곳이며, 이 스택에서 원천 데이터(source of truth)에 가장 가까운 저장소이기 때문입니다.
기존 OpenTelemetry 설정을 자체 호스팅 Langfuse에 연결할 수 있는가?
네, 가능합니다. Langfuse v4와 v4 SDK는 OpenTelemetry를 기반으로 구축되었으며, Anthropic 및 OpenAI OTel 계측은 이를 직접 내보냅니다. Python에서는 pip install langfuse opentelemetry-instrumentation-anthropic을 실행하고, 시작 시 AnthropicInstrumentor().instrument()를 한 번 호출한 뒤, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_BASE_URL를 본인의 호스트로 설정하십시오. 대시보드에 데이터가 보이지 않는다면 먼저 langfuse.auth_check()으로 연결을 확인하십시오.