콘텐츠로 이동

세션 리플레이 수집 원리와 데이터 무결성

세션 리플레이(Session Replay)는 사용자가 웹 페이지에서 수행한 작업 과정을 재현하는 데 사용됩니다. 화면 녹화가 아닙니다. 브라우저 SDK가 페이지의 전체 스냅샷과 이후 변경 사항을 기록하고, 데이터를 압축하여 분할 업로드합니다. 재생 시 플랫폼이 이 데이터를 기반으로 페이지를 재구성합니다.

이를 이해하면 다음 세 가지 현상을 구분하는 데 도움이 됩니다.

  • 수집되지 않음: 녹화가 시작되지 않았거나, 샘플링에 포함되지 않았거나, 브라우저 기능이 충족되지 않음
  • 수집 체인에 갭 발생: 페이지 변경이 보호 예산을 초과하거나, 네트워크가 영구적으로 실패하거나, 페이지가 갑자기 종료됨
  • 데이터가 업로드되었으나 시각적으로 불완전함: 이미지, 글꼴 또는 스타일을 재생 시 액세스할 수 없거나, 콘텐츠가 개인정보 보호 규칙 및 기능 경계의 제한을 받음

데이터 생성 방식

초기화 및 녹화 시작
세션 샘플링 및 녹화 자격 판단
전체 스냅샷(페이지 베이스라인)
DOM, 입력, 스크롤, 마우스, 스타일, Canvas 등의 증분
압축 및 정렬된 세그먼트 생성
일반 네트워크 전송; 페이지 이탈 시 beacon / XHR 시도
플랫폼 처리 및 재생 가능한 파일 생성

1. 초기화 및 샘플링

SDK init() 완료 후, 반드시 명시적으로 호출해야 합니다.

datafluxRum.startSessionReplayRecording()

호출 전에 발생한 페이지 상태와 작업은 소급하여 기록되지 않습니다. 녹화가 실제로 시작되는지 여부는 현재 Session이 sessionReplaySampleRate 또는 sessionReplayOnErrorSampleRate에 포함되는지에 따라 결정됩니다.

다음을 사용하세요.

datafluxRum.isRecording()

현재 페이지가 이미 녹화 상태인지 확인할 수 있습니다.

startSessionReplayRecording({ force: true })는 현재 Session에 리플레이 자격을 강제로 부여합니다. 이 옵션은 샘플링 동작을 변경하므로, 명확하게 강제 녹화가 필요한 비즈니스 시나리오에서만 사용하는 것이 좋습니다.

2. 전체 스냅샷

녹화가 시작되면 SDK는 먼저 재생 가능한 페이지 베이스라인을 생성합니다. 여기에는 다음이 포함됩니다.

  • 현재 페이지 주소 및 뷰포트
  • 포커스 상태
  • DOM 구조, 속성, 텍스트 및 스크롤 위치
  • 브라우저가 지원하는 경우 Visual Viewport 정보

전체 스냅샷 생성 중에 페이지 DOM이 계속 빠르게 변경되면 SDK는 서로 다른 시간 상태가 혼합된 스냅샷을 폐기하고 다시 생성합니다. 매우 큰 페이지나 지속적으로 고주파로 변경되는 페이지는 여러 번 실패할 수 있습니다. 연속 복구에 실패하면 SDK는 현재 페이지의 녹화를 중단하여 올바르게 재생할 수 없는 데이터가 계속 생성되는 것을 방지합니다.

3. 증분 기록

전체 스냅샷 이후 SDK는 지속적으로 다음을 기록합니다.

  • DOM 노드 추가, 삭제, 텍스트 및 속성 변경
  • 마우스, 터치, 클릭 및 스크롤
  • 입력 필드 값 변경
  • 뷰포트 크기 변경
  • 오디오/비디오 요소의 재생, 일시 중지 및 진행 상태
  • 스타일 규칙 변경
  • 활성화된 Canvas 기록

이러한 증분은 이전의 전체 스냅샷에 의존합니다. 예를 들어 증분이 노드 ID를 참조하지만 해당 베이스라인이 성공적으로 업로드되지 않으면 재생 측에서 이 변경 사항을 올바르게 적용할 수 없습니다.

4. 세그먼트화 및 업로드

SDK는 기록을 압축하여 정렬된 세그먼트로 만듭니다. 일반 녹화 중에는 약 5초마다, 내부 크기 목표에 근접할 때, View 전환이 발생하거나 페이지 수명 주기가 변경될 때 세그먼트가 새로 고쳐집니다.

일반 네트워크 실패는 순서대로 메모리 재시도 큐에 들어갑니다. 오프라인, HTTP 408, 4295xx는 재시도됩니다. 대부분의 다른 4xx는 재시도할 수 없는 오류로, 해당 세그먼트가 영구적으로 폐기됩니다.

특정 세그먼트를 전달할 수 없다고 판단되면 SDK는 이에 의존하는 동일한 베이스라인 세대를 무효화하고 새 전체 스냅샷 생성을 시도합니다. 새 스냅샷이 성공하면 이후의 페이지 상태는 계속 재생할 수 있지만, 영구적으로 손실된 세그먼트가 포함하는 작업 과정은 복구할 수 없습니다.

오류 리플레이에서 오류 전 데이터를 유지하는 방법

sessionReplayOnErrorSampleRate를 구성하면, 여기에 포함된 Session은 먼저 브라우저 메모리에 잠긴 리플레이 세그먼트를 저장합니다. 오류가 발생한 후에야 SDK가 잠금을 해제하여 최근 페이지 베이스라인과 증분을 업로드하고 Session이 종료될 때까지 녹화를 계속합니다.

이는 오류 전 최대 약 1분의 컨텍스트를 제공하며, 무한 기록을 제공하지 않습니다.

  • Session에서 오류가 발생하지 않으면 잠긴 데이터는 업로드되지 않습니다.
  • 오류 발생 전에 페이지가 종료되면 메모리 데이터는 업로드 체인에 진입하지 않습니다.
  • 메모리 캐시가 보호 상한에 도달하면 SDK는 새 전체 스냅샷에서 재생 가능한 베이스라인을 다시 설정합니다.

따라서 오류 리플레이는 오류 전 작업을 파악하는 데 적합하며, 모든 오류 없는 Session을 저장하는 일반 리플레이를 대체하기에는 적합하지 않습니다.

DOM 데이터가 누락될 수 있는 경우

브라우저 SDK는 세션 리플레이가 메인 스레드를 장시간 점유하는 것을 방지하기 위해 직렬화 및 캐시에 보호 경계를 설정합니다. 현재 구현에서 전체 스냅샷은 최대 20만 개의 노드를 처리하며, 예상 크기는 약 4 MiB입니다. DOM 트리 깊이, 단일 노드 속성 수, 텍스트 길이, 스타일 규칙 및 증분 큐에도 모두 경계가 있습니다.

다음 시나리오에서 잘림, 폐기 또는 베이스라인 재설정이 발생할 수 있습니다.

  • 페이지가 한 번에 대규모 DOM 서브트리를 생성하거나 교체하는 경우
  • 단일 텍스트, 속성 또는 인라인 스타일이 비정상적으로 큰 경우
  • 고주파 DOM 업데이트가 너무 오래 지속되어 안정적인 스냅샷을 얻을 수 없는 경우
  • Mutation 증분 생성 속도가 SDK의 처리 속도보다 지속적으로 빠른 경우
  • 페이지에 많은 수의 Shadow Root, 스타일 규칙 및 대규모 목록이 동시에 포함된 경우
  • 브라우저가 DOM 또는 CSSOM을 읽는 과정 자체에서 장시간 블로킹이 발생하는 경우

SDK는 반쪽짜리 구조 변경을 전송하지 않습니다. 분할할 수 없는 DOM 변경이 너무 크면 전체 변경을 폐기하고 새 전체 스냅샷을 요청합니다. 이를 통해 이후 페이지의 일관된 상태를 복구할 수 있지만, 갭 기간의 모든 중간 단계는 복구할 수 없습니다.

위의 수치는 현재 SDK의 내부 보호 임계값이며, 구성 가능한 항목이 아니며 장기적으로 안정적인 공개 API로 간주되지 않습니다. 문제 해결 시 실제 사용 중인 SDK 버전을 기준으로 해야 합니다.

개인정보 보호 규칙으로 인한 예상되는 누락

기본 개인정보 보호 수준은 mask-user-input입니다. 다음 데이터는 마스킹, 숨김 또는 플레이스홀더 콘텐츠로 대체될 수 있습니다.

  • 비밀번호, 이메일, 전화번호, 숨겨진 입력
  • 신용카드 자동 완성 관련 필드
  • 개인정보 보호 속성 또는 개인정보 보호 클래스명으로 표시된 노드
  • shouldMaskNode가 마스킹해야 한다고 반환하는 사용자 정의 노드
  • 스크립트 콘텐츠 및 숨겨진 노드의 서브트리

이러한 콘텐츠 누락은 데이터 보안 정책에 해당하며, 네트워크 패킷 손실이 아닙니다. "입력란이 비어 있음" 또는 "특정 영역에 콘텐츠가 없음"을 확인할 때는 먼저 개인정보 보호 구성을 확인해야 합니다.

HTML 및 Shadow DOM의 기능 경계

현재 수집 경계는 다음과 같습니다.

콘텐츠 수집 상황
일반 DOM 지원
open Shadow DOM 액세스 가능한 구조, 변경 및 관련 스타일 지원
closed Shadow DOM 수집 보장 불가
Web Components Shadow Root의 개방 여부 및 내부에서 사용하는 콘텐츠 유형에 따라 다름
iframe iframe 요소 자체는 기록 가능하나, 내부 문서는 완전 재현을 위해 기록하지 않음
video / audio 요소 및 재생 상태는 기록 가능하나, 미디어 트랙 또는 프레임별 비디오 콘텐츠는 수집하지 않음

Canvas 및 WebGL에서 프레임 누락이 발생하는 이유

Canvas 녹화는 기본적으로 비활성화되어 있습니다. 다음 조건이 모두 충족되어야 합니다.

  • Session Replay가 샘플링에 포함되어 녹화 중인 경우
  • replayCanvasEnabled: true
  • 대상 Canvas가 수집 가능한 DOM에 진입한 경우
  • WebGL/WebGL2 장면에 WebGL Replay 플러그인이 추가로 등록된 경우

Canvas 자동 녹화는 예산 기반 스케줄링을 사용하며, 프레임별 수집을 보장하지 않습니다. 다음 상황에서 시각적 프레임 갭이 발생할 수 있습니다.

  • 애니메이션 속도가 수집 리듬보다 빠른 경우
  • 페이지가 숨겨져 자동 스케줄링이 일시 중지된 경우
  • 여러 Canvas가 공정한 라운드 로빈 또는 동시 인코딩을 기다리는 경우
  • 화면 변경이 없어 백오프에 진입한 경우
  • Canvas 크기, 인코딩 결과 또는 단일 명령이 너무 큰 경우
  • Canvas가 아직 DOM에 연결되지 않았거나 해당 DOM 베이스라인이 아직 게시되지 않은 경우
  • WebGL 플러그인이 엔진이 Context를 생성하고 드로잉 메서드를 캐시한 후에 초기화된 경우
  • 마지막 WebGL 드로잉이 쿨링 또는 인코딩 기간에 발생했고, 이후 수집을 트리거하는 새 드로잉이 없는 경우

WebGL Replay는 드로잉에 의해 구동되는 예산 기반의 픽셀 스냅샷으로, WebGL 명령 수준의 리플레이 또는 프레임별 비디오가 아닙니다. 자세한 구성 및 성능 경계는 Canvas 녹화 연동 방법을 참조하세요.

페이지 종료 시 데이터 손실이 발생하기 쉬운 이유

리플레이의 인코딩 결과와 재시도 큐는 모두 브라우저 메모리에만 저장됩니다. 페이지가 숨겨지거나, 고정(freeze)되거나, 언로드될 때 SDK는 대기 중인 레코드를 적극적으로 새로 고치고 sendBeacon 또는 XHR을 통해 전달을 시도합니다.

종료 단계에서도 다음과 같은 제한이 있습니다.

  • 브라우저가 JavaScript에 할당하는 시간이 매우 짧음
  • 종료 단계에는 제한된 전송 예산이 있으며, 전송할 데이터가 너무 많으면 테일이 폐기됨
  • sendBeacon() 성공 반환은 브라우저가 큐잉 작업을 수신했음을 의미할 뿐, 서버 측이 이미 영속화했음을 의미하지 않음
  • 브라우저 강제 종료, 브라우저 충돌, 모바일 시스템 프로세스 회수, 정전 또는 네트워크 끊김은 메모리 큐를 직접 지움
  • 페이지 종료 전에 아직 잠금 해제되지 않은 오류 리플레이 데이터는 업로드되지 않음

중요 데이터의 안정적인 전달을 beforeunload에 완전히 의존하지 마십시오. 녹화를 일찍 시작하고, 페이지가 중요한 작업 후 정상적인 전송 시간을 확보하도록 하는 것이 페이지 이탈 로직을 추가하는 것보다 더 효과적입니다.

데이터가 업로드되었는데도 재생이 불완전한 이유

세션 리플레이는 DOM 및 리소스 주소를 기반으로 페이지를 재구성하며, 모든 이미지, 글꼴 및 외부 스타일을 리플레이 데이터에 완전히 패키징하지 않습니다. 리플레이 세그먼트가 모두 성공적으로 업로드되었더라도 다음과 같은 이유로 비정상적으로 표시될 수 있습니다.

  • 이미지, 글꼴 또는 스타일 리소스가 서비스 종료되었거나 주소가 변경된 경우
  • 리소스에 로그인 상태, 서명 또는 내부 네트워크 액세스가 필요한 경우
  • CORS가 재생 페이지에서 리소스 로드를 허용하지 않는 경우
  • CSP가 Worker, Blob URL 또는 리소스 로드를 차단하는 경우
  • 교차 출처 스타일시트의 CSSOM을 읽을 수 없어 재생 시 원본 링크를 다시 요청해야 하는 경우
  • 플랫폼 측 데이터 처리, 인덱싱 또는 리플레이 파일 생성이 아직 완료되지 않았거나 실패한 경우

리소스 문제는 일반적으로 DOM 구조는 그대로 있지만 글꼴, 이미지, 레이아웃 또는 호버 스타일이 올바르지 않은 형태로 나타납니다.

데이터 갭 분류

분류 일반적인 원인 이후 계속 가능 여부
녹화되지 않음 시작 API 호출 안 함, 샘플링 미포함, 브라우저 미지원 성공적으로 시작되면 기록 가능, 이전은 복구 불가
시작 부분 누락 SDK 초기화 또는 녹화 시작이 너무 늦음 이후는 계속 가능, 시작 부분은 복구 불가
개인정보 마스킹 기본 개인정보 보호 규칙 또는 사용자 정의 차단 예상된 동작이므로 원본 텍스트를 복원해서는 안 됨
기능 경계 closed Shadow DOM, iframe 내 문서, 미디어 콘텐츠, Canvas 미활성화 지원되지 않는 데이터는 복구 불가
DOM 보호 경계 페이지 너무 큼, 지속적인 진동, 증분 큐 오버플로우 새 전체 스냅샷 후 일관성 복구 가능, 갭 과정은 복구 불가
Canvas 스케줄링 경계 쿨링, 백오프, 숨겨진 페이지, 인코딩 또는 크기 제한 이후 스냅샷으로 현재 화면 복구 가능, 중간 프레임은 보장되지 않음
Worker/인코딩 실패 CSP, Worker 생성 실패, 인코딩 예외 또는 지속적인 백프레셔 녹화를 다시 시작하면 복구 가능할 수 있음
네트워크 영구 실패 재시도 불가능한 4xx, 메모리 큐 가득 참, 프록시 차단 새 베이스라인 후 계속 가능, 이전 세그먼트는 복구 불가
페이지 갑작스러운 종료 강제 종료, 충돌, 시스템 회수, 종료 시간 부족 테일은 일반적으로 복구 불가
리소스 로드 실패 CORS, 인증, 리소스 만료 또는 CSP 리소스 접근성 수정 후 표시가 개선될 수 있음
플랫폼 처리 예외 업로드는 성공했지만 처리 또는 파일 생성 실패 서버 측 처리 결과에 따라 다름

문제 해결 방법

다음 순서로 확인하는 것이 좋습니다.

  1. 녹화 자격: 샘플링 비율을 확인하고, startSessionReplayRecording() 호출 여부를 확인하며, isRecording()을 검사합니다.
  2. Session 및 View: getInternalContext()를 실행하여 Application ID, Session ID 및 View ID가 존재하고 예상과 일치하는지 확인합니다.
  3. 클라이언트 요청: 브라우저 개발자 도구에서 /v1/write/rum/replay를 필터링하여 요청 시간, 상태 코드, 응답 및 실패 이유를 기록합니다.
  4. Worker 및 보안 정책: 콘솔에서 Worker, Blob URL, CSP 및 Canvas 인코딩 오류를 확인합니다.
  5. 개인정보 보호 및 기능 경계: 누락된 영역이 마스킹, closed Shadow DOM, iframe, 오디오/비디오 또는 비활성화된 Canvas에 속하는지 확인합니다.
  6. 리소스 접근성: 리플레이 환경에서 이미지, 글꼴 및 CSS URL의 유효 기간, 인증, CORS 및 CSP를 확인합니다.
  7. 플랫폼 처리 상태: 클라이언트 요청이 성공했지만 데이터가 없으면 Session ID, Application ID, 발생 시간, SDK 버전 및 요청 응답을 기록한 후 계속 문제를 해결합니다.

데이터 갭을 줄이기 위한 제안

  • SDK를 일찍 초기화하고 녹화를 시작하십시오.
  • 비즈니스 볼륨에 따라 명확한 일반 리플레이 및 오류 리플레이 샘플링 비율을 설정하십시오.
  • 매우 큰 DOM 서브트리, 텍스트, 속성 및 인라인 스타일을 한 번에 쓰지 마십시오.
  • 대규모 목록 및 고주파 페이지 상태는 배치로 업데이트하십시오.
  • 이미지, 글꼴 및 CSS에 안정적인 주소를 제공하고 CORS 및 CSP를 올바르게 구성하십시오.
  • 필요한 페이지에서만 Canvas를 활성화하고, 시나리오에 따라 수동, 자동 스냅샷 또는 고충실도 모드를 선택하십시오.
  • WebGL 엔진을 시작하기 전에 WebGL Replay 플러그인을 초기화하십시오.
  • /v1/write/rum/replay4xx, 429, 5xx 및 네트워크 실패를 모니터링하십시오.
  • 문제 해결 시 Session ID, View ID, SDK 버전, 브라우저 버전 및 페이지 수명 주기 정보를 보관하십시오.

추가 자료

문서 평가

이 페이지가 도움이 되었나요?