마인크래프트 RPG 서버 데이터 동기화 디스코드 봇 및 FastAPI 직업 위키 웹 포털
*본 프로젝트는 **2026년 7월까지 가동된 실운영 서버 시스템(커뮤니티 유저 약 40명, 최대 동접 20명, 최대 90종 직업군 관리)*으로, 단일 노드(GCP Free Tier, 1GB RAM)와 대륙 간 네트워크 지연(GCP 미국 ↔ Supabase 한국, RTT 200ms) 환경에서 반복 조회 인메모리 전환 및 프로세스 격리로 시스템 병목을 완화한 프로젝트입니다.
| 핵심 검증 영역 | 개선 전 | 적용 후 | 핵심 성과 및 실측 수치 |
|---|---|---|---|
| 물리적 RTT 200ms 극복 | 405.66 ms | 16.18 ms (Redis Fast Path) | 평균 지연시간 약 96% 단축 (Redis 인메모리 캐시 전환 및 TCP 세션 유지) |
| 이벤트 루프 동결 방지 | 206.04 ms (지터) | 14.64 ms (지터) | 하트비트 지터 92.9% 억제 (게이트웨이 1006 연결 끊김 방어) |
| 경합 동시성 무결성 | 경쟁 상태 발생 | 오류율 0.0% (20건 중 1건 승인) | 15초 Safe TTL 단발 분산 락으로 운영진 중복 승인 방어 |
| 원격 소켓 단절 복구 | 서버 비정상 다운 | 자동 복구 100.0% (6회 전원 성공) | @db_retry 기반 끊긴 소켓 폐기 및 1회 재연결 자가 치유 검증 |
- 아키텍처 데이터 흐름 및 분산 제어 규약:
- ① Tailscale 사설 터널: 공인 IP가 없는 로컬 PaperMC 호스트와 GCP 단일 VM 간 외부 포트 개방 없이 WireGuard 암호화 터널 통신.
- ② 웹소켓 게이트웨이: Discord 커뮤니티 유저 및 운영진의 모달 인터랙션을 봇 비동기 이벤트 루프로 수신.
- ③ HTTP 조회: 웹 브라우저 포털 사용자가 ASGI 미들웨어를 거쳐 FastAPI 백엔드로 직업/스킬 데이터 요청.
- ④ Safe TTL 분산 락 & Pub/Sub: 1GB RAM 환경에서 운영진 중복 승인 경합을 억제하는 15초 안전 만료 마진 Redis 분산 락 및 크로스 플랫폼 이벤트 전파.
- ⑤ 인메모리 Fast Path: 200ms 대륙 간 물리 지연을 극복하기 위해 FastAPI 포털의 반복 직업 조회를 Redis 캐시(16.18ms)로 전환.
- ⑥ 원격 DB 질의 및 자가 치유: 200ms 대륙 간 RTT 환경에서 사전
SELECT 1검증을 배제하고@db_retry소켓 자가 치유 데코레이터로 원격 Supabase DB 무중단 연동.
- 정보 파편화 해소와 하드코딩 프로토타입의 유지보수 한계 극복:
- 80여 종에 달하는 방대한 직업군 정보가 디스코드 채널에 파편화되어 신규 유저의 탐색 피로가 컸습니다.
- 이를 해결하기 위해 커뮤니티 내부에서 정적 웹 위키 프로토타입(JavaScript 객체 내 직업 데이터 하드코딩 구조)이 1차로 시도되었으나, 잦은 밸런스 패치 시마다 소스 코드 직접 수정과 Git 재배포가 강제되어 지속적인 업데이트가 정체되는 한계를 노출했습니다.
- 본 프로젝트는 해당 아이디어를 발전시켜 데이터베이스 중심 아키텍처로 전면 재설계함으로써, 운영진이 디스코드에 텍스트를 작성하는 즉시 웹 위키와 인게임에 무중단 반영되는 실시간 동기화 파이프라인을 구축했습니다.
- 조직 변화 관리와 Discord 중심 단일 진실 공급원 설계:
- 개발자 편의 중심의 별도 웹 관리자 콘솔을 도입할 경우, 운영진이 Discord에서 논의한 내용을 웹 폼에 다시 복사하고 입력해야 하는 도구 전환 피로와 휴먼 에러가 발생합니다.
- 운영진의 기존 업무 흐름을 바꾸지 않고 정합성을 유지하기 위해, Discord 채널을 단일 진실 공급원으로 두고 봇 파서가 데이터베이스와 웹 위키로 데이터를 단방향 전파하도록 설계했습니다.
- 운영 중 추가 기능 확장 (화이트리스트 연동 및 심사 자동화):
- 위키 시스템을 운영하던 중, 운영진으로부터 "디스코드 음성 채널에 접속 중인 유저만 인게임에 접속할 수 있도록 제한해달라"는 요청을 받았습니다.
- 이에 디스코드 모달 입력과 PaperMC 플러그인, Redis 연동을 추가 구축하여 유저 심사와 실시간 화이트리스트 반영을 자동화했습니다.
- 개발 방식과 직접 부하 검증:
- 1인 개발 과정에서 생산성을 높이기 위해 AI 코딩 도구를 적극 활용했습니다.
- 다만 자동 생성 코드에서 발생하기 쉬운 네트워크 지연, 동시 클릭 경쟁 상태, 보안 취약점 등은 코드에 의존하지 않고 로컬 테스트 환경에 직접 부하를 주입하고 검증 스크립트를 작성하여 하나씩 확인했습니다.
- 운영 타임라인: 2026년 4월 개발 착수 (내부 프로토타입 온보딩 위키 운용) → 프론트엔드 개편 및 커뮤니티 공개 홍보 → 2026년 7월 서비스 종료
- 운영 인력 및 커뮤니티 규모:
- 엔지니어링: 1인 개발 (AI 도구 활용, 테스트 및 벤치마크 직접 검증)
- 운영진: 5~6명 (신규 유저 심사 및 접속 사유 우회 승인·거절 권한 동시 행사)
- 디스코드 커뮤니티 유저: 약 40명
- 최대 동시 접속자: 20명
- 관리 직업 데이터셋: 최대 약 90종 (스토리 내 등장인물 기반 직업군)
- 네트워크 경계 보안 및 사설 터널링:
- 인게임 마인크래프트 서버가 고정 및 공인 IP가 없는 비개발자 운영자의 개인 PC 환경에서 구동되었습니다.
- 로컬 공유기 포트포워딩 시 발생하는 외부 무차별 대입 공격 위험을 원천 차단하기 위해, WireGuard 기반 가상 사설 메쉬 VPN인 Tailscale을 구축하여 외부 공인 포트 노출 없이(공인 포트 0개) 클라우드 가상머신과 암호화 터널 통신을 수행했습니다.
- 인프라 제약과 무비용 운영:
- 호스트 인프라: GCP Compute Engine Free Tier
e2-micro(vCPU 2개, 1.0GB RAM, 미국 오리건 리전) - 원격 데이터베이스: Supabase PostgreSQL 15 (서울 리전, 미국 ↔ 한국 물리적 왕복 지연 200ms)
- 월 인프라 청구 비용: 0원 (월 10원 미만) — GCP 무료 티어와 Supabase 프리 티어를 조합하여 도메인 구입비 외 순수 클라우드 유지 비용 0원을 달성했습니다.
- 호스트 인프라: GCP Compute Engine Free Tier
- 웹 포털 구축 및 트래픽 수용:
- 인게임에 접속하지 않은 외부 유저에게 직업 위키 웹 포털을 제공해 신규 유입과 온보딩 접근성을 확보했습니다.
- 검색 엔진 최적화(SEO)와 Cloudflare CDN 캐싱을 결합해 불특정 다수의 유입 트래픽 수용.
실제 도커 인프라(postgres:15-alpine, redis:7-alpine, FastAPI)에 부하와 결함을 직접 주입하며 메트릭을 계측했습니다.
| 벤치마크 항목 | 핵심 검증 주제 | 실측 조건 및 부하 구성 | 상세 실증 보고서 |
|---|---|---|---|
| Part 1. 네트워크 & DB | RTT 200ms 극복과 커넥션 풀 자가 치유 | data.js 71종 직업 데이터셋 무작위 질의, RTT 200ms 모의 주입, pg_terminate_backend 강제 소켓 종료 |
PART1_CONNECTION_POOL.md |
| Part 2. 동시성 & 락 | 비동기 이벤트 루프 격리와 Safe TTL 분산 락 | 50ms 주기 Discord WebSocket 하트비트 지터 계측, 동일 키 20개 코루틴 동시 경합 | PART2_EVENT_LOOP_AND_LOCK.md |
| Part 3. 웹 보안 | Pure ASGI 미들웨어와 도메인 경계 보호 | 보안 헤더 6종 주입, HSTS 로컬 배제, CSRF Origin 경계 검증, Redis 연동 Client IP 레이트 리미팅 | PART3_WEB_SECURITY.md |
| Part 4. 데이터 무결성 | 비정형 텍스트 정형화와 일괄 적재 파이프라인 | 디스코드 비정규 포스트 계층형 버퍼 파싱, jobs 100회 일괄 UPSERT, JSONB 닉네임 템플릿 영속화 |
PART4_DATA_INTEGRITY_AND_PARSER.md |
| Part 5. 분산 이벤트 | 크로스 플랫폼 이벤트 브로커와 봇 순단 사후 대사 | Redis Pub/Sub 종단간 전달 지연시간 계측, 봇 오프라인 순단 시 누락 이벤트 PostgreSQL 사후 대사 | PART5_DISTRIBUTED_PUBSUB.md |
- 문제 상황: 미국 리전(GCP VM)과 한국 리전(Supabase PG) 간의 물리적 거리(RTT 200ms) 때문에, 쿼리 직전 연결을 확인하는
SELECT 1방식은 매 호출마다 400ms 이상의 지연을 누적시켰습니다. 또한 Supabase가 유휴 연결을 끊을 때 클라이언트 메모리 플래그(conn.closed)가 이를 감지하지 못해(conn.closed == 0) 런타임 쿼리 오류가 발생했습니다. - 해결 방식:
SELECT 1사전 검증을 제거하고 커널 레벨 TCP Keepalive를 적용해 세션을 안정적으로 유지했습니다.@db_retry데코레이터를 구현해psycopg2.OperationalError나DatabaseError발생 시 끊어진 소켓을 풀에서 영구 폐기(putconn(close=True))하고 즉시 재연결해 1회 재시도(Fail-fast Auto-Reconnect)하도록 구성했습니다.- 봇 기동 시 단 한 번의 벌크 쿼리로 유저와 직업(최대 90종) 데이터를 Redis에 사전 예열(Pre-warming)하여 반복 조회를 인메모리 Fast Path로 전환했습니다.
- 성과:
- 불필요한
SELECT 1검증을 제거하여 일반 쿼리 지연시간을 405.66ms에서 243.41ms로 약 40% 단축했습니다. - Redis Fast Path 적용 시 지연시간을 16.18ms로 단축하고 처리량을 2.47 RPS에서 61.78 RPS 수준으로 개선했습니다.
- 서버 소켓 강제 종료 상황에서 **자가 치유 재연결 100.0% (6회 테스트 전원 정상 복구)**를 확인했습니다.
- 불필요한
- 문제 상황:
discord.py는 단일 비동기 이벤트 루프 기반으로 동작합니다. 동기식 DB 쿼리(psycopg2)가 루프를 200ms 이상 점유하면 게이트웨이 하트비트 전송이 지연되어1006 Connection Closed에러와 함께 재연결 루프에 빠집니다. - 해결 방식:
- 비동기 메인 루프에 전용
ThreadPoolExecutor(max_workers=20)를 결합하고, 모든 동기 DB I/O 작업을await asyncio.to_thread로 위임해 완전히 격리했습니다.
- 비동기 메인 루프에 전용
- 성과:
- 10회 동시 DB 쿼리 부하 환경에서 하트비트 지터를 206.04ms에서 14.64ms로 92.9% 억제했습니다.
- 전체 처리 소요 시간을 2.495초에서 0.358초로 85.7% 단축하며 27.94 RPS를 확보했습니다.
- 문제 상황: 여러 운영진이 디스코드 채널에서 유저의 접속 사유 우회(
ReasonBypassView) 버튼(승인/거절)을 동시에 클릭하면 중복 처리(경쟁 상태)가 발생할 수 있습니다. 하지만 1GB 단일 VM 환경에서 Redlock이나 백그라운드 Watchdog 프로세스를 운용하면 메모리 고갈 위험이 컸습니다. - 해결 방식:
- Redis 단일 노드의 원자적 명령어인
SET key val EX 15 NX를 채택했습니다. 임계 구역 처리 시간(약 50ms) 대비 300배의 안전 마진을 둔 15초 Safe TTL을 설정하고, 처리가 끝나면 명시적으로DEL하는 경량 동시성 제어를 설계했습니다.
- Redis 단일 노드의 원자적 명령어인
- 성과:
- 20개 세션 동시 요청 경합 환경에서 **정확히 1건 승인, 19건 차단(오류율 0.0%)**으로 무결성을 검증했습니다.
- 문제 상황: 불특정 다수가 접속하는 직업 위키 웹 포털 특성상 무차별 크롤링이나 비정상 트래픽이 유입될 수 있습니다. 또한 리버스 프록시(Cloudflare) 뒤에서 실제 클라이언트 IP를 식별하지 못하면 레이트 리미팅이 무력화됩니다.
- 해결 방식:
- Starlette/FastAPI 기반의 순수 ASGI 미들웨어를 구축해 필수 보안 헤더 6종(
X-Frame-Options: DENY,Content-Security-Policy: frame-ancestors 'none',X-Content-Type-Options: nosniff,Referrer-Policy,Permissions-Policy,X-Process-Time)을 자동 주입했습니다. - Cloudflare의
cf-connecting-ip헤더를 검증해 신뢰할 수 있는 클라이언트 IP를 기준으로 Redis 연동 SlowAPI 레이트 리미팅을 적용했습니다.
- Starlette/FastAPI 기반의 순수 ASGI 미들웨어를 구축해 필수 보안 헤더 6종(
- 성과:
- 모든 위키 엔드포인트에 보안 헤더 100% 주입을 확인했고, 임계치를 넘긴 요청을
HTTP 429 Too Many Requests로 차단했습니다.
- 모든 위키 엔드포인트에 보안 헤더 100% 주입을 확인했고, 임계치를 넘긴 요청을
- 문제 상황: 외부 마인크래프트 서버와 디스코드 간 실시간 이벤트 동기화에 Redis Pub/Sub을 사용할 때, 봇 프로세스 순단이나 네트워크 단절이 발생하면 인메모리 메시지가 유실될 위험이 있었습니다.
- 해결 방식:
- Redis Pub/Sub은 빠른 실시간 통지용 통로로 활용하고, 최종 진실의 원천은 PostgreSQL에 두었습니다.
- 봇 기동 및 재연결 시
users테이블의is_guide_completed및 권한 상태를 조회해 미처리 이벤트를 한 번에 맞추는 사후 상태 대사 파이프라인을 구현했습니다.
- 성과:
- 봇 다운 상태에서 인입된 20건의 완료 이벤트에 대해 재기동 시 단 1회의 대사 쿼리로 누락 없이 100% 복구 및 동기화를 완료했습니다.
- 문제 상황: 신규 유저 온보딩 시 Mojang 외부 계정 검증 API와 대륙 간 원격 DB(Supabase) 쓰기 트랜잭션이 직렬로 강결합되어 Discord 게이트웨이의 엄격한 3초 인터랙션 제한 시간을 정면으로 초과하고 세션이 끊기는 현상이 발생했습니다.
- 해결 방식:
- 모달 제출 즉시
interaction.response.defer(ephemeral=True)를 발행하는 선제 지연 응답으로 3초 타임아웃을 선제 방어했습니다. - 전역
aiohttp.ClientSession풀링을 통해 Mojang API 재연결 핸드셰이크 오버헤드를 제거하고, Redis 기반 3회 오입력 브루트포스 락과 7일 유효기간 매직링크 서약을 결합해 외부 API 장애가 봇 전체로 전파되지 않도록 격리했습니다.
- 모달 제출 즉시
- 성과:
- 외부 네트워크 지연과 무관하게 Discord UI 무응답 에러 0건을 달성하고 무중단 온보딩 자동화를 완성했습니다.
- 배경: 1GB 단일 VM 환경에서 무거운 로깅 스택을 띄우는 것은 메모리 낭비였고, 매번 SSH 터미널에 접속해
docker logs를 확인하는 방식은 신속한 장애 대응에 불리했습니다. - 구현:
- Docker 컨테이너의 표준 출력/에러 스트림을 디스코드 최대 메시지 길이(2,000자) 단위로 분할하여 관리자 전용 디스코드 관제 채널로 실시간 전송했습니다.
- 별도 모니터링 인프라 없이도 모바일과 데스크톱 디스코드에서 봇 크래시나
@db_retry경고 로그를 즉각 확인했습니다.
2. 서비스 정상 종료 및 콜드 아카이빙 파이프라인 (db_backup.py)
- 배경: 2026년 7월 서비스 종료 시 운영 데이터를 유실 없이 영구 보존하기 위해 정적 콜드 아카이빙 파이프라인을 구축했습니다.
- 구현:
- Cloudflare R2 도메인 매칭 정규식 필터링으로 검증된 정적 이미지만 선별 다운로드했습니다.
DateTimeEncoder커스텀 직렬화를 거쳐 PostgreSQL의 관계형 테이블과 JSONB 필드를 전수 덤프해 정적 아카이브 디렉토리(public/archive/)로 백업 전환했습니다.
rpg_sync_project/
├── plugins/ # 마인크래프트 인게임 동기화 플러그인 서브모듈 (rpg_sync_plugin)
├── src/
│ ├── bot/ # Discord.py 봇 메인 (이벤트 루프, Cogs, 스레드 풀 격리)
│ │ ├── cogs/ # 도메인별 Cog (auth, board, jobs, system, users)
│ │ └── utils/ # 계층형 버퍼 텍스트 파서, S3 클라이언트, 권한 체크
│ ├── database/ # PostgreSQL 커넥션 풀 (@db_retry 자가 치유) 및 Redis 캐시 계층
│ └── web/ # FastAPI 웹 포털 (직업 위키, Pure ASGI 보안 미들웨어, SlowAPI, SSR)
│ ├── routers/ # 인증, 대시보드, 직업 위키, 가이드 라우터
│ └── templates/ # Jinja2 서버사이드 렌더링 템플릿
├── public/ # 정적 자산 및 아키텍처 다이어그램 SVG (Light/Dark)
│ └── images/
│ ├── architecture-light.svg
│ └── architecture-dark.svg
├── portfolio/ # 포렌식 개발 로그, 아키텍처 백서, 트러블슈팅 가이드
│ ├── benchmarks/ # 5대 도메인별 벤치마크 실증 보고서 (Part 1 ~ Part 5)
│ └── TROUBLESHOOTING.md # 실제 발생 장애 및 4대 핵심 트러블슈팅 케이스
├── tests/ # 재현 가능한 벤치마크 계측 스크립트 5종
├── db_backup.py # 서비스 종료 시 R2 이미지 백업 및 DB JSON 덤프 스크립트
├── docker-compose.yml # 프로덕션 컨테이너 정의
├── docker-compose.dev.yml # 로컬 실증용 DB & Redis 인프라 정의
├── init.sql # PostgreSQL 15 초기 스키마 및 인덱스 정의
└── requirements.txt
- 로컬 빌드 환경과 사후 아카이빙:
- 운영 당시에는 PaperMC 서버 디렉터리에서 로컬 빌드로 jar 아티팩트를 직접 배치하며 개발했기 때문에 별도 원격 저장소 이력을 남기지 않았습니다.
- 서비스 종료 후 포트폴리오 정리 과정에서 독립 저장소(mmmphyun/rpg_sync_plugin)로 분리하여 서브모듈로 등록했습니다.
- 커밋 이력은 단일 커밋으로 올라가 있으나, 2026년 4~6월에 작성된 본 저장소의 Redis 발행/구독 채널 규약,
init.sql의 유저 테이블 구조, 접속 사유 우회 분산 락 로직과 맞물려 실서버에서 함께 구동되었던 코드입니다.
상세 트러블슈팅 로그와 코드 해결책은 portfolio/TROUBLESHOOTING.md에서 확인할 수 있습니다.
- Supabase 유휴 연결 강제 종료와
conn.closed감지 불가- 원인: 원격 방화벽/프록시가 소켓을 비정상 종료했을 때 클라이언트 메모리 플래그(
conn.closed)가0으로 남아 장애 감지를 우회했습니다. - 해결:
@db_retry데코레이터를 적용해psycopg2.OperationalError발생 시 끊긴 소켓을 폐기하고 1회 재연결하는 자가 치유 체계를 구축했습니다.
- 원인: 원격 방화벽/프록시가 소켓을 비정상 종료했을 때 클라이언트 메모리 플래그(
- 동기 I/O 쿼리로 인한 Discord Gateway Heartbeat Starvation
- 원인: 200ms RTT DB 쿼리가 단일 비동기 이벤트 루프를 블로킹해 하트비트 전송 누락과
1006연결 끊김이 발생했습니다. - 해결: 메인 루프에 전용
ThreadPoolExecutor(max_workers=20)를 할당하고asyncio.to_thread로 위임해 하트비트 지터를 14.6ms로 억제했습니다.
- 원인: 200ms RTT DB 쿼리가 단일 비동기 이벤트 루프를 블로킹해 하트비트 전송 누락과
- AI 생성 코드 수용 시 발생한 웹 보안 취약점 (SQLi & DOM XSS)
- 원인: 초기 프로토타입 개발 시 f-string 쿼리와 CSR 구조를 도입해 보안 취약점이 노출되었습니다.
- 해결: 전체 DB 쿼리를 파라미터 바인딩으로 전면 강제하고 Jinja2 SSR로 전환해 공격 표면을 원천 차단했습니다.
- 1GB RAM VM 환경에서 유저 사유 우회 중복 클릭 경쟁 상태
- 원인: 여러 운영진이 동일 유저의 접속 사유(
ReasonBypassView)를 동시에 승인/거절할 때 분산 경쟁 상태가 발생했습니다. - 해결: 별도 Watchdog 프로세스의 메모리 부담을 배제하고 15초 Safe TTL 기반 단발 분산 락(
SET key val EX 15 NX)을 도입하여 중복 승인 경쟁 상태를 해결했습니다.
- 원인: 여러 운영진이 동일 유저의 접속 사유(
시스템 기획부터 분산 인프라 구축, 웹 보안 셀프 레드티밍, 운영 장애 해결까지의 상세 엔지니어링 기록입니다.
| 편차 | 주제 | 핵심 다룸 내용 | 의사결정 로그 링크 |
|---|---|---|---|
| Part 1 | 아키텍처 & SSOT | 디스코드 중심 단일 진실 공급원 및 제로 코스트 분산 아키텍처 설계 | 포스트 보기 |
| Part 2 | 분산 연동 & 옵저버빌리티 | Tailscale 사설망 연동, Redis Pub/Sub, 관제 웹훅 알림 체계 | 포스트 보기 |
| Part 3 | 풀스택 웹 보안 | XSS 무해화, 순수 ASGI 보안 미들웨어, HSTS 락아웃 방어 | 포스트 보기 |
| Part 4 | 비동기 온보딩 | 3초 인터랙션 타임아웃 격리, 선제 defer, 세션 풀링 | 포스트 보기 |
| Part 5 | 데이터 엔지니어링 | 비정형 마크다운 정형화, 계층형 컨텍스트 파서, 일괄 적재 | 포스트 보기 |
| Part 6 | 실용적 엔지니어링 타협 | 1GB RAM & RTT 200ms 물리적 제약 속 4가지 실용 타협 | 포스트 보기 |
인프라 자원 회수 및 로컬 재현성 안내:
2026년 7월 서비스 운영이 정상 종료됨에 따라 사용하던 클라우드 자원은 모두 회수했습니다. 시스템 구성과 성능 측정은 아래 개발용 도커 환경(docker-compose.dev.yml)과 초기 스키마(init.sql)를 통해 로컬 환경에서 그대로 재현할 수 있습니다.
로컬 도커 테스트베드 환경에서 모든 수치를 직접 재현하고 계측할 수 있습니다.
# 1. 로컬 테스트 인프라 기동 (PostgreSQL 15 & Redis 7)
docker compose -f docker-compose.dev.yml up -d db redis
# 2. Part 1: 커넥션 풀 자가 치유 및 레이턴시 벤치마크 실행
uv run --with psycopg2-binary --with redis --with python-dotenv python tests/benchmark_connection.py
# 3. Part 2: 이벤트 루프 격리 및 Safe TTL 분산 락 동시성 벤치마크 실행
uv run --with psycopg2-binary --with redis --with python-dotenv python tests/benchmark_event_loop.py
# 4. Part 3: 웹 보안 미들웨어 및 레이트 리미팅 벤치마크 실행
docker compose -f docker-compose.dev.yml up -d api
uv run --with httpx --with pytest python tests/benchmark_web_security.py
# 5. Part 4: 계층형 버퍼 파서 및 벌크 UPSERT 벤치마크 실행
uv run --with psycopg2-binary --with python-dotenv python tests/benchmark_data_integrity.py
# 6. Part 5: 크로스 플랫폼 Pub/Sub 및 사후 대사 벤치마크 실행
uv run --with redis --with psycopg2-binary --with python-dotenv python tests/benchmark_pubsub.py
# 7. 인프라 종료
docker compose -f docker-compose.dev.yml stop