Dev SLI SLO 기준 - 100-hours-a-week/KTB4-2nd-Cloud GitHub Wiki
V1의 주요 기능이 정상적으로 동작하는지 같은 기준으로 판단하기 위해 SLI/SLO를 구성했습니다. 운영 로그와 부하 테스트 결과를 이 기준에 맞춰 확인하고, 측정 결과가 쌓이면 목표값을 조정합니다.
현재 목표값은 운영 데이터가 충분히 쌓이기 전에 정한 초기 기준입니다.
다음 데이터가 CloudWatch에 수집됩니다.
| 데이터 | 확인할 수 있는 내용 |
|---|---|
| Nginx JSON Access Log | 요청 경로, 상태 코드, 전체 요청시간, Backend 응답시간 |
| Backend JSON Log | 로그인, 여행 생성, 원본 저장, AI 요청, 여행 조회의 성공/실패와 처리시간 |
| AI JSON Log | AI 작업 결과, 단계별 처리시간과 실패 지점 |
| EC2/CloudWatch Agent Metric | CPU, Memory, Disk, Network와 주요 Process 상태 |
flowchart LR
subgraph APP["App EC2"]
NG["Nginx<br/>Access, Error Log"] --> AG["CloudWatch Agent"]
HOST["메모리, 디스크, 프로세스"] --> AG
BE["Backend 컨테이너<br/>stdout JSON"]
end
subgraph WK["Worker EC2"]
AI["AI 컨테이너<br/>stdout JSON"]
end
AWS["EC2 기본 지표<br/>CPU, 네트워크, 상태 검사"]
AG -- "로그" --> CWL[("CloudWatch Logs")]
AG -- "지표" --> CWM[("CloudWatch Metrics")]
BE -- "awslogs 드라이버" --> CWL
AI -- "awslogs 드라이버" --> CWL
AWS --> CWM
CWL --> Q["Logs Insights<br/>request_id, trip_id, job_id"]
CWL --> D["Dashboard<br/>yeodam-v1-operations"]
CWM --> D
Dashboard yeodam-v1-operations에서 요청 현황, Backend와 AI의 결과와 지연시간, 최근 실패와 Host 상태를 한 화면에서 봅니다.
개별 요청이나 작업의 원인은 Logs Insights에서 request_id, trip_id, job_id로 검색합니다.
| 기능 | 성공 기준 | SLI | 초기 SLO | 지연시간 기준 |
|---|---|---|---|---|
| 카카오 로그인 | 인증 처리 후 서비스 또는 신규 사용자 등록 화면으로 이동 | 로그인 성공 건수 / 유효한 로그인 종료 건수 | 99% 이상 | Backend 처리 p95 3초 이하 |
| 여행 생성 | 요청한 원본이 모두 보존되고 AI 결과가 여행에 반영됨 | 여행 생성 성공 건수 / 여행 생성 종료 건수 | 99% 이상 | Upload Batch 구간 분리 후 확정 |
| AI 처리 | Backend가 요청한 작업이 최종 성공함 | AI 작업 성공 건수 / AI 작업 종료 건수 | 95% 이상 | 전체 처리 p95 30분 이하 |
| 완료 여행 조회 | 완료된 여행의 필수 사진, 장소, 경로가 반환됨 | 조회 성공 건수 / 유효한 조회 종료 건수 | 99% 이상 | Backend 처리 p95 1초 이하 |
started 로그는 작업 시작을 추적하는 보조 이벤트입니다. 성공률에는 success, failure처럼 결과가 확정된 종료 이벤트만 사용합니다.
| 구분 | 기준 |
|---|---|
| ✅ 성공 | 인증이 끝나고 서비스 또는 신규 사용자 등록 화면으로 이동 |
| ❌ 실패 | Callback, Token, 내부 처리 오류로 로그인을 완료하지 못함 |
| ➖ 제외 | 사용자가 직접 취소한 로그인, 잘못된 형식의 요청 |
Backend의 auth_login 이벤트로 서버 처리 결과와 시간을 측정합니다. 브라우저 Redirect와 화면 진입까지 포함한 전체 흐름은 FE E2E 테스트로 확인합니다.
| 구분 | 기준 |
|---|---|
| ✅ 성공 | 여행 정보가 저장되고 요청한 원본 수와 S3 저장 수가 일치하며 AI 결과가 반영됨 |
| ❌ 실패 | 원본 일부 누락, DB와 S3 불일치, AI 작업 등록 또는 결과 반영 실패 |
| ➖ 제외 | 파일 형식, 개수, 용량 제한을 정상적으로 거부한 요청, 사용자 취소 |
원본 사진 유실은 허용 실패율과 관계없이 바로 확인해야 하는 데이터 무결성 문제로 봅니다.
FE는 사진을 최대 10장 단위로 나눠 보냅니다. BE는 중간 Batch에서는 사진을 저장한 뒤 바로 응답하고, 마지막 Batch에서는 전체 저장을 확인한 뒤 AI 분석과 결과 저장까지 끝내고 응답합니다.
sequenceDiagram
participant FE
participant BE as Backend
participant S3
participant AI as AI Worker
loop 중간 Batch (최대 10장씩)
FE->>BE: 사진 업로드
BE->>S3: 원본 저장
BE-->>FE: 204
end
FE->>BE: 마지막 Batch
BE->>S3: 원본 저장, 전체 수 확인
BE->>AI: 분석 요청
AI-->>BE: 분석 결과
BE-->>FE: 200
그래서 사진 업로드 시간과 AI 처리 시간은 나눠서 측정합니다.
| 구분 | 기준 |
|---|---|
| ✅ 성공 | 요청된 작업이 완료되고 결과가 Backend에 반영됨 |
| ❌ 실패 | 최종 실패, 제한시간 초과, Callback 실패 또는 작업 유실 |
| ⏳ 진행 중 | 목표 시간 안에서 대기하거나 실행 중인 작업 |
Worker EC2 시작과 컨테이너 준비 시간도 사용자가 기다리는 AI 처리 시간에 포함합니다. 단계별 병목은 ai_pipeline_step으로 따로 봅니다.
| 구분 | 기준 |
|---|---|
| ✅ 성공 | 소유자가 완료된 여행을 조회하고 화면에 필요한 사진, 장소, 경로를 받음 |
| ❌ 실패 | 5xx, Timeout, 완료 상태인데 필수 결과가 빠진 경우 |
| ➖ 제외 | 존재하지 않는 여행, 권한 없는 접근, 아직 처리 중인 여행의 정상 응답 |
| Service | Event | 용도 |
|---|---|---|
| Backend | auth_login |
로그인 성공률과 처리시간 |
| Backend | trip_creation |
여행 생성 최종 결과 |
| Backend | photo_originals_saved |
예상 원본 수와 저장 수 비교 |
| Backend | ai_job |
Backend 쪽에서 본 AI 요청과 완료 결과 |
| Backend | worker_ready |
Worker 준비시간 |
| Backend | trip_view |
완료 여행 조회 성공률과 처리시간 |
| AI | ai_job |
AI API가 받은 작업의 최종 결과 |
| AI | ai_worker_execution |
Worker 실행 결과 |
| AI | ai_pipeline_step |
단계별 처리시간과 실패 위치 |
| AI | ai_callback |
Backend 결과 전달 성공 여부 |
| 지표 | 계산식 |
|---|---|
| 로그인 성공률 |
auth_login 성공 / auth_login 종료 결과 |
| 여행 생성 성공률 |
trip_creation 성공 / trip_creation 종료 결과 |
| 원본 보존율 |
saved_count 합계 / expected_count 합계 |
| AI 완료율 |
ai_job 성공 / ai_job 종료 결과 |
| 여행 조회 성공률 |
trip_view 성공 / trip_view 종료 결과 |
성공률만 보지 않고 전체 건수를 같이 봅니다. V1처럼 요청이 적을 때는 한두 건의 실패가 비율을 크게 바꾸기 때문입니다.
Nginx와 애플리케이션 로그의 시간은 재는 구간이 다릅니다.
Client ── Request Body 전송 ──▶ Nginx ──▶ Backend ──▶ (MySQL, S3, AI) ──▶ 응답
|◀─────────────────────── request_time ───────────────────────▶|
|◀──── upstream_response_time ────▶|
|◀─ duration_ms ─▶|
| 필드 | 측정 범위 |
|---|---|
request_time |
Client가 Request Body를 보내는 시간까지 포함한 전체 요청시간 |
upstream_response_time |
Nginx가 Backend에 요청을 넘긴 뒤 응답을 받기까지의 시간 |
duration_ms |
Backend 또는 AI가 기록한 업무 처리시간 |
업로드가 느릴 때 request_time만 길면 Client 네트워크나 파일 전송부터 확인합니다.
upstream_response_time과 Backend duration_ms도 같이 길면 App, MySQL, S3 처리 구간을 확인합니다.
아래 항목은 SLO 계산에 들어가지 않고, 실패 원인과 자원 한계를 찾을 때 씁니다.
| 대상 | 지표 |
|---|---|
| App EC2 | CPU, CPU Credit, Memory, Swap, Disk, I/O Wait, Network |
| App Process | Nginx, MySQL, Docker 실행 여부와 사용량 |
| Worker EC2 | CPU, Network, Instance 상태와 Worker 준비시간 |
| Nginx | 경로별 요청 수, 5xx, request_time, upstream_response_time
|
| Container | Health, 비정상 재시작, Exit Code, OOM, 배포 Release |
| SLO | 허용 실패율 | 평가 기간 |
|---|---|---|
| 99% | 1% | 30일 |
| 95% (AI 처리) | 5% | 30일 |
요청이 적으면 비율만 보지 않고 실패 건수와 주간 추세를 같이 봅니다.
⚠️ 원본 사진 유실, 복구할 수 없는 데이터 불일치, 보안 문제는 Error Budget으로 허용하지 않습니다.
| 항목 | 판정선 |
|---|---|
| HTTP 오류 | 유효 HTTP 요청의 5xx와 Timeout 비율 1% 미만 |
| 지연시간 | 로그인과 완료 여행 조회 p95가 초기 목표 이내 |
| 데이터 | 원본 사진 누락 0건 |
| AI | AI 작업 유실 0건, 테스트 종료 후 대기 작업 감소 |
| 안정성 | 컨테이너 비정상 재시작과 OOM 0건 |
| 저장 공간 | Filesystem 사용률 80% 미만 |
| 회복 | 부하 종료 후 CPU, Memory, 응답시간이 정상 범위로 회복 |
flowchart LR
B["Baseline<br/>기능, 측정 경로 확인"] --> P["Peak<br/>예상 최대 부하"]
P --> S["Spike<br/>급증 후 회복"]
S --> A["AI 처리량<br/>처리 경계 확인"]
| 단계 | 확인 목적 |
|---|---|
| Baseline | 적은 부하에서 기능과 측정 경로가 정상인지 확인 |
| Peak | V1 예상 최대 부하에서 오류율과 지연시간 확인 |
| Spike | 짧은 요청 급증 후 실패와 회복시간 확인 |
| AI 처리량 | 작업 유입보다 처리가 느려지는 경계 확인 |
테스트마다 시작과 종료 시각, 동시 사용자 수, 사진 수와 크기, Cloud Commit, FE/BE/AI Release를 기록해서 같은 조건끼리 비교합니다.
실제 사용자나 팀원의 디버깅과 겹칠 수 있으면 별도 Runtime과 Test Data를 씁니다. Subdomain만 나눠서는 부하가 분리되지 않습니다.
실행 결과는 부하 테스트에 있습니다.