RUM이란?
RUM(Real User Monitoring)은 실제 사용자의 브라우저에서 수집하는 성능 데이터입니다. 서버에서는 API가 200ms에 응답했다고 보이지만, 사용자의 브라우저에서는 3초 이상 걸릴 수 있습니다. RUM은 이런 "실제 사용자가 겪는 경험"을 측정합니다.
RUM vs Synthetic Monitoring
| RUM | Synthetic | |
|---|---|---|
| 데이터 소스 | 실제 사용자 | 시뮬레이션 봇 |
| 커버리지 | 모든 페이지, 모든 환경 | 설정한 시나리오만 |
| 네트워크 조건 | 다양 (3G~WiFi) | 일정 |
| 비용 | 트래픽 비례 | 테스트 수 비례 |
| 장점 | 실제 사용자 경험 반영 | 일관된 기준선 제공 |
Datadog RUM SDK 설치
Datadog RUM을 사용하려면 애플리케이션에 SDK를 설치하고 초기화해야 합니다.
// npm 설치
npm install @datadog/browser-rum
// 초기화
import { datadogRum } from '@datadog/browser-rum';
datadogRum.init({
applicationId: 'YOUR_APPLICATION_ID',
clientToken: 'YOUR_CLIENT_TOKEN',
site: 'datadoghq.com',
service: 'my-web-app',
env: 'production',
version: '1.0.0',
sessionSampleRate: 100, // 100% 세션 샘플링
sessionReplaySampleRate: 20, // 20% 세션 리플레이
trackUserInteractions: true,
trackResources: true,
trackLongTasks: true,
defaultPrivacyLevel: 'mask-user-input'
});
핵심 포인트
RUM은 '실제로 사용자가 겪는 경험'을 측정합니다. 서버에서는 200ms면 빠르다고 생각하지만, 사용자 브라우저에서는 네트워크 지연, 느린 단말기, 브라우저 렌더링 시간 등으로 인해 3초 이상 걸릴 수 있습니다. 따라서 백엔드 성능 지표만으로는 사용자 경험을 온전히 파악할 수 없습니다.
Core Web Vitals 깊이 읽기
Google이 정의한 Core Web Vitals는 웹 사용자 경험의 핵심 지표입니다. 로딩 성능, 인터랙티브성, 시각적 안정성 세 가지 측면을 측정합니다.
1. LCP (Largest Contentful Paint)
페이지에서 가장 큰 콘텐츠가 렌더링되는 시간입니다. 일반적으로 히어로 이미지, 제목, 비디오 등이 LCP 요소가 됩니다.
LCP 임계값
LCP 개선 방법
- › 이미지 최적화: WebP 포맷 사용, 압축, lazy loading
- › 서버 응답 시간 단축: CDN 활용, 캐싱, 데이터베이스 최적화
- › 렌더 블로킹 리소스 제거: CSS/JS 비동기 로딩, 인라인 critical CSS
- › 리소스 우선순위 설정: <link rel="preload"> 활용
2. INP (Interaction to Next Paint)
사용자가 인터랙션(클릭, 탭, 키보드 입력)한 후 다음 페인트까지의 시간입니다. 2024년 3월부터 FID(First Input Delay)를 대체하여 Core Web Vitals의 공식 지표가 되었습니다.
INP 임계값
INP 개선 방법
- › 긴 JavaScript 작업 분할: 50ms 이상 작업을 여러 청크로 나눔
- › 이벤트 핸들러 최적화: debounce, throttle 기법 적용
- › Web Worker 활용: 무거운 연산을 백그라운드로 이동
- › Third-party 스크립트 최소화: 불필요한 외부 라이브러리 제거
3. CLS (Cumulative Layout Shift)
페이지 로드 중 예상치 못한 레이아웃 이동 정도를 측정합니다. 이미지가 로드되면서 텍스트가 밀리거나, 광고가 삽입되면서 버튼이 이동하는 등의 현상을 수치화합니다.
CLS 임계값
CLS 개선 방법
- › 이미지/영상에 width, height 속성 명시
- › 동적 콘텐츠(광고, 배너)를 위한 공간 미리 확보
- › 폰트 로딩 전략: font-display: swap 사용
- › 기존 콘텐츠 위에 새 콘텐츠를 삽입하지 않기
Core Web Vitals 종합
| 지표 | 측정 대상 | Good | Needs Improvement | Poor |
|---|---|---|---|---|
| LCP | 로딩 성능 | < 2.5s | 2.5s - 4.0s | > 4.0s |
| INP | 인터랙티브성 | < 200ms | 200ms - 500ms | > 500ms |
| CLS | 시각적 안정성 | < 0.1 | 0.1 - 0.25 | > 0.25 |
SEO 영향
CWV는 Google 검색 순위에도 영향을 미칩니다. 2021년 6월부터 페이지 경험(Page Experience)이 공식 랭킹 요소가 되었으며, CWV는 그 핵심 지표입니다. 따라서 SEO 관점에서도 매우 중요한 지표입니다.
p99/p95/p50 레이턴시 이해
퍼센타일(Percentile)은 데이터를 정렬했을 때 특정 비율의 사용자가 경험하는 값을 의미합니다.
퍼센타일의 의미
- p50: 중앙값. 50%의 사용자가 이 시간 안에 응답을 받음
- p95: 상위 5%를 제외한 95%의 사용자가 이 시간 안에 응답을 받음
- p99: 상위 1%를 제외한 99%의 사용자가 이 시간 안에 응답을 받음
평균의 함정 (매우 중요한 개념)
평균은 이상치(outlier)에 민감하여 실제 사용자 경험을 왜곡할 수 있습니다. 다음 예시를 살펴보세요.
예시 데이터셋 (10개 요청, 단위: ms)
평균(296ms)만 보면 괜찮아 보이지만, 실제로는 90%의 사용자는 52ms에 응답을 받고, 10%의 사용자는 2.5초나 걸립니다. 평균은 이 극단적인 차이를 숨깁니다.
왜 p99가 중요한가?
1. 1%는 무시할 수 없는 숫자
하루 100만 요청이 발생하는 서비스에서 1%는 1만 건입니다. 1만 명의 사용자가 느린 응답을 경험하면 그것은 결코 작은 문제가 아닙니다.
2. 파워 유저가 p99에 해당
많은 요청을 보내는 파워 유저일수록 지연을 경험할 확률이 높습니다. 이들은 보통 가장 중요한 고객이므로, 이들의 경험을 무시하면 비즈니스에 큰 타격을 입습니다.
3. 마이크로서비스에서 p99 전파
각 서비스의 p99가 100ms라고 가정할 때, 10개 서비스를 거치는 요청의 경우:
즉, 10개 서비스를 거치면 약 10%의 요청이 지연을 겪습니다. 서비스가 늘어날수록 p99는 더욱 중요해집니다.
Datadog RUM에서 p99 조회
# RUM 쿼리 예시: /checkout 페이지의 로딩 시간
@type:view @view.url_path:/checkout
그래프 설정: p50, p95, p99 비교
Datadog RUM Dashboard에서 "Loading Time" 지표를 선택하고, 다음과 같이 퍼센타일을 추가할 수 있습니다.
Tip: SLO는 평균이 아닌 p99 기준으로
SLO(Service Level Objective)를 설정할 때 평균이 아닌 p99를 기준으로 하세요. "평균 응답시간 200ms 이하"보다 "p99 응답시간 500ms 이하"가 훨씬 의미 있는 목표입니다. 평균은 outlier를 숨기지만, p99는 최악의 사용자 경험까지 고려합니다.
에러 추적 & 세션 분석
Datadog RUM은 성능 지표뿐만 아니라 에러 추적과 세션 분석도 제공합니다. 사용자가 겪는 모든 에러를 자동으로 수집하고, Session Replay를 통해 문제 상황을 재현할 수 있습니다.
1. JavaScript Error Rate
브라우저에서 발생하는 JavaScript 에러를 자동으로 수집합니다.
-
›
window.onerror: 전역 에러 핸들러 -
›
unhandledrejection: Promise rejection 에러 - › 에러 스택 트레이스, 소스 맵 지원
2. Resource Error
네트워크 요청 실패, 리소스 로드 실패 등을 추적합니다.
- › API 호출 실패 (4xx, 5xx 에러)
- › 이미지, CSS, JS 파일 로드 실패
- › CORS 에러
3. Long Task
50ms 이상 메인 스레드를 블로킹하는 작업을 자동으로 감지합니다.
Long Task는 브라우저가 사용자 입력에 응답하지 못하게 만들어 INP 지표를 악화시킵니다. Datadog RUM은 Long Task의 발생 빈도, 소요 시간, 발생 위치를 추적합니다.
예시: 200ms 걸리는 JavaScript 함수 = 4x Long Task 임계값
4. Session Replay
사용자 세션을 영상으로 재생하여 문제 상황을 정확히 재현할 수 있습니다.
- › 사용자의 모든 클릭, 스크롤, 입력을 기록
- › 개인정보 보호: 민감한 입력은 자동 마스킹
- › 에러 발생 전후 맥락을 영상으로 확인
Datadog RUM 쿼리 예시
# /checkout 페이지의 모든 에러
@type:error @error.source:source @view.url_path:/checkout
# 특정 API 호출 실패
@type:resource @resource.url:"/api/v1/payment/*" @resource.status_code:>=500
# Long Task 50ms 이상
@type:long_task @long_task.duration:>=50000000
에러 분류
| 에러 타입 | 설명 | 예시 |
|---|---|---|
| Source Error | JavaScript 런타임 에러 | TypeError, ReferenceError |
| Network Error | 네트워크 요청 실패 | fetch failed, 500 error |
| Custom Error | 애플리케이션 정의 에러 | datadogRum.addError() |
실전: 사용자 불만 → RUM 추적 워크스루
시나리오
CS팀으로부터 "결제 페이지가 너무 느려요"라는 고객 불만이 접수되었습니다. RUM 데이터를 활용하여 문제를 추적하고 원인을 찾아봅시다.
RUM Dashboard 열기 → /checkout 페이지 필터
먼저 Datadog RUM Dashboard에서 Views 탭을 선택하고, /checkout 페이지만 필터링합니다.
@type:view @view.url_path:/checkout
p99 Loading Time 시계열 확인 → 스파이크 발견
"Loading Time" 지표를 선택하고 p99 그래프를 확인합니다. 특정 시간대에 급격한 스파이크가 발견됩니다.
해당 시간대 세션 드릴다운 → Resource Waterfall 확인
스파이크가 발생한 시간대의 세션을 클릭하여 상세 페이지로 이동합니다. "Resources" 탭에서 Waterfall 차트를 확인합니다.
APM으로 전환 → 해당 API Trace 확인
Waterfall에서 /api/v1/payment/validate API가 6.2초 소요된 것을 확인했습니다.
이제 APM(Application Performance Monitoring)으로 전환하여 백엔드 trace를 분석합니다.
결론: 백엔드 DB 쿼리 최적화 필요
RUM → APM → DB 순서로 추적한 결과, 문제의 원인은 백엔드 데이터베이스 쿼리 최적화 부족이었습니다.
해결 방안
-
›
payment_hist테이블에(user_id, created_at)복합 인덱스 추가 -
›
order_items테이블에order_id인덱스 추가 - › 쿼리 최적화 후 p99 Loading Time: 8.5s → 1.2s (86% 개선)
핵심 인사이트
RUM → APM → DB 순서로 추적하면 프론트엔드 문제인지 백엔드 문제인지 빠르게 판별할 수 있습니다. 만약 RUM Waterfall에서 API 응답 시간이 정상이지만 LCP가 느리다면 프론트엔드 렌더링 문제입니다. 반대로 이번 케이스처럼 API 응답 시간이 느리다면 백엔드 문제입니다.
퀴즈
학습한 내용을 확인해봅시다. 5문제를 모두 풀어보세요.