Sentry 브라우저 프로파일링 (Browser Profiling)

"이 화면이 느리다"는 건 알겠는데, 왜 느린지 모르겠다면? Sentry 브라우저 프로파일링이 콜스택 단위로 원인 함수를 직접 짚어줍니다.

Sentry 브라우저 프로파일링 (Browser Profiling)

"이 화면이 느리다"는 건 알겠는데, 왜 느린지 모르겠다면? Sentry 브라우저 프로파일링이 콜스택 단위로 원인 함수를 직접 짚어줍니다.


목차

  1. 브라우저 프로파일링이란?
  2. 동작 조건 체크리스트
  3. 현재 설정 코드 해설
  4. 실전 활용법
  5. 기대 효과
  6. 소스맵 업로드와 함수명 복원
  7. 운영 비용 관리

브라우저 프로파일링이란? {#개요}

Sentry 브라우저 프로파일링은 브라우저의 JS Self-Profiling API를 활용해, 성능 트레이스가 수집되는 구간 동안 어떤 JavaScript 함수가 CPU 시간을 얼마나 점유하는지를 함수·콜스택 단위로 기록하는 기능입니다.

기존 트레이싱이 "이 화면 전환이 2.4초 걸렸다"까지 알려준다면, 프로파일링은 그 2.4초 안에서 "그중 1.1초를 buildPricingTable 재귀 계산이 차지했다"처럼 원인 함수까지 정확히 짚어줍니다. 추측 기반의 최적화가 아닌, 측정 기반의 핀포인트 최적화가 비로소 가능해집니다.

구분트레이싱(기존)프로파일링(추가)
답하는 질문"무엇이 느린가" (페이지/요청 단위)"왜 느린가" (함수/콜스택 단위)
데이터 단위Transaction / SpanCPU 샘플 + 콜스택 (Flame Graph)
활용 시점느린 화면·요청 탐지탐지된 병목의 근본 원인 함수 식별

동작 조건 체크리스트 {#prerequisites}

브라우저 프로파일링은 아래 조건이 모두 충족되어야 데이터가 수집됩니다. 하나라도 빠지면 프로파일이 조용히 수집되지 않을 뿐, 앱 동작이나 에러 보고에는 영향이 없습니다.

① Document-Policy: js-profiling 응답 헤더

HTML 문서 응답에 이 헤더가 있어야 브라우저가 프로파일러 시작을 허용합니다. AWS Amplify로 배포하는 프로젝트라면 amplify.yml의 customHeaders(**/*.html)에 설정해야 합니다.

② Chromium 계열 브라우저

JS Self-Profiling API는 현재 Chrome·Edge 등 Chromium 기반 브라우저에서만 동작합니다. Firefox·Safari에서는 에러 없이 자동으로 비활성화됩니다.

③ Secure Context (HTTPS)

Self-Profiling API는 HTTPS 환경(Secure Context)에서만 작동합니다. 로컬 개발 환경(http://localhost)은 예외적으로 허용되는 경우도 있으나, 운영 도메인은 반드시 HTTPS여야 합니다.

④ browserProfilingIntegration + BrowserTracing 동시 활성화

프로파일은 트레이스에 첨부되는 방식으로 전송됩니다. 따라서 browserProfilingIntegration과 BrowserTracing(또는 라우터 연동 변형)이 함께 활성화되어야 합니다.


현재 설정 코드 해설 {#설정}

구현 위치: apps/web/src/shared/util/sentry.ts, amplify.yml

Sentry.init({
    // ...
    integrations: [
        Sentry.tanstackRouterBrowserTracingIntegration(router), // 라우터 연동 트레이싱
        Sentry.browserProfilingIntegration(),                   // 브라우저 프로파일링
    ],
    tracesSampleRate: 0.1,         // 트레이스 10% 샘플링 (비용 정책상 유지)
    profileSessionSampleRate: 1.0, // 모든 세션을 프로파일링 대상으로 (init 시점 1회 결정)
});

샘플링 구조 이해하기

profileSessionSampleRate와 tracesSampleRate의 관계를 정확히 이해하는 것이 중요합니다.

  • profileSessionSampleRate: 1.0 — 세션 시작 시 "이 세션을 프로파일링할지" 여부를 1회 결정합니다. 1.0은 모든 세션을 대상으로 함을 의미합니다.
  • 실제 프로파일 수집량은 tracesSampleRate에 종속됩니다. 프로파일은 샘플링된 트레이스 구간에만 첨부되므로, profileSessionSampleRate를 1.0으로 설정해도 최종 프로파일 수집량은 트레이스 볼륨(약 10%)을 초과하지 않습니다. 비용이 자동으로 통제되는 구조입니다.
  • 활성 환경: 운영(main 브랜치 + origindrop 호스트)에서만 초기화됩니다(isOriginDropProduction 게이트). 로컬·테스트 환경에서는 동작하지 않습니다.

실전 활용법 {#활용법}

병목 함수 찾기 (가장 기본적인 워크플로)

  1. Sentry → Performance 또는 Profiling 탭 진입
  2. 느린 Transaction(예: Find products 라우트 로드, Image Editor 진입)을 선택
  3. 해당 트레이스의 Flame Graph(불꽃 그래프) 확인
    • 가로 폭이 넓은 막대 = CPU 시간을 많이 차지한 함수
    • src/... 경로의 우리 코드 중 폭이 넓은 함수가 1차 최적화 후보
  4. 후보 함수를 useMemo / 가상화 / 디바운스 / 알고리즘 개선 등으로 최적화 → 재배포 후 동일 트랜잭션의 Flame Graph로 개선 효과를 수치로 검증

"체감상 느린데 원인을 모를 때"

트레이싱만으로는 "이 화면이 느리다"까지만 보이고, 원인 함수는 추측에 의존하게 됩니다. 프로파일링을 활성화하면 추측 없이 실측 콜스택으로 원인을 좁힐 수 있습니다. 이는 "Measure First(추측 말고 측정)" 원칙과 정확히 맞닿아 있습니다.

회귀 감시 (릴리스 간 비교)

  • 특정 함수(예: 가격 규칙 계산, 캔버스 렌더, 대량 목록 렌더)가 배포 이후 CPU 점유가 늘었는지 릴리스 간 비교가 가능합니다.
  • 무거운 계산이 메인 스레드를 오래 점유하면 입력 지연(끊김)으로 직결됩니다. Flame Graph에서 메인 스레드 장시간 점유 함수를 우선 분리·최적화 대상으로 삼으세요.

우리 서비스에서 기대되는 효과 {#기대효과}

클라이언트 연산이 집중되는 서비스라면 브라우저 프로파일링의 효과가 특히 뚜렷합니다. 다음과 같은 영역에서 즉각적인 인사이트를 기대할 수 있습니다.

기능 영역프로파일링으로 확인 가능한 것
상품 목록·그리드lazy render·가상화가 실제로 효과를 내는지, 카드 렌더 함수가 병목인지 실측 검증
이미지 에디터 (Fabric.js)렌더·변환 연산 중 어떤 호출이 프레임 드랍을 유발하는지 식별
가격 규칙·집계 계산중첩 배열 연산이 메인 스레드를 막는 구간을 콜스택으로 특정

결과적으로 "느리다는 제보 → 추측 수정 → 재배포"의 반복 사이클에서 벗어나, 측정 기반의 핀포인트 최적화로 전환할 수 있습니다.


소스맵 업로드와 함수명 복원 {#소스맵}

운영 번들은 minify되어 함수명이 t, e 같은 한 글자로 압축됩니다. Sentry는 업로드된 소스맵으로 이를 원래 함수명으로 복원합니다. 소스맵이 없으면 Flame Graph와 에러 스택트레이스가 모두 minify된 채로 표시되어 분석이 사실상 불가능합니다.

구현 위치: apps/web/vite.config.ts

// main 브랜치 + 빌드 환경에 SENTRY_AUTH_TOKEN이 있을 때만 동작
const enableSentrySourcemaps = isMainBranch && Boolean(process.env.SENTRY_AUTH_TOKEN);

// build.sourcemap: 'hidden' → 소스맵 생성하되 번들에 참조 주석(sourceMappingURL) 미삽입
sentryVitePlugin({
    org: 'type-b',
    project: 'origin-drop',
    authToken: process.env.SENTRY_AUTH_TOKEN,
    sourcemaps: { filesToDeleteAfterUpload: ['./dist/**/*.map'] },
});

소스코드 노출 방지 (보안 핵심)

소스맵을 그대로 public 배포하면 소스코드가 외부에 노출됩니다. 아래 4단계 구조로 이를 차단합니다.

  1. build.sourcemap: 'hidden' — 소스맵을 생성하되 번들 JS에 //# sourceMappingURL 주석을 삽입하지 않음 → 브라우저가 소스맵을 요청조차 하지 않음
  2. @sentry/vite-plugin — 빌드 중 소스맵을 Sentry 서버로만 업로드 (비공개 처리)
  3. filesToDeleteAfterUpload — dist/**/*.map을 빌드 후 즉시 삭제 → 배포 서버에 .map 파일 자체가 남지 않음
  4. debug ID 기반 매칭 — 번들과 소스맵에 자동 주입되는 debug ID로 함수명을 매칭하므로 별도 release 설정이 불필요

주의: SENTRY_AUTH_TOKEN은 빌드 시점에만 사용되는 시크릿으로, 클라이언트 번들에 포함되지 않습니다. 공개 가능한 DSN과 달리, 이 토큰은 외부에 절대 노출되어서는 안 됩니다.

토큰 발급 및 등록 절차

① 토큰 발급

Sentry → Settings → Auth Tokens (Organization Auth Token 권장) → 생성. 소스맵 업로드에 필요한 scope는 project:releases + org:read이며, 조직 토큰은 기본적으로 충분한 권한을 포함합니다.

② 환경 변수 등록

AWS Amplify 콘솔 → 해당 앱 → App settings → Environment variables에 SENTRY_AUTH_TOKEN = 발급한 토큰을 추가합니다. 전 브랜치 공유로 설정해도 코드 가드(isMainBranch)로 인해 실제 업로드는 main 브랜치에서만 실행됩니다.

③ 재배포로 활성화

토큰 등록 후 main 브랜치를 재배포하면 해당 빌드부터 소스맵 업로드가 시작됩니다.

안전장치: 토큰이 없거나 잘못되어도 빌드 자체는 실패하지 않습니다. 토큰이 없으면 플러그인을 로드하지 않고(소스맵 미생성), 토큰이 틀려 업로드에 실패하더라도 경고(warning) 로그만 출력하며 애플리케이션 빌드 및 배포는 그대로 정상 완료됩니다. CI/CD 파이프라인의 중단 걱정 없이 안전하게 적용할 수 있습니다.


운영 비용 관리 {#비용}

Sentry 프로파일링은 강력한 도구이지만, 대규모 트래픽 환경에서는 적절한 샘플링 전략이 동반되지 않으면 비용이 급격히 증가할 수 있습니다. 수집 볼륨을 스마트하게 통제하는 세 가지 핵심 운영 팁을 소개합니다.

1. 2단계 샘플링 파이프라인 유지

앞서 살펴본 바와 같이, 프로파일링 데이터는 독립적으로 전송되지 않고 항상 트랜잭션 트레이스에 종속됩니다.

$$\text{최종 프로파일 볼륨} \le \text{전체 트랜잭션} \times \text{tracesSampleRate} \times \text{profileSessionSampleRate}$$

  • 트래픽이 많다면 tracesSampleRate를 0.05 ~ 0.1(5~10%) 수준으로 낮게 유지하세요.
  • 대표적인 성능 지표를 도출하는 데는 전체 트래픽의 5~10% 샘플만으로도 통계적으로 충분합니다.
  • 특정 병목 조사가 필요할 때만 일시적으로 특정 라우트의 샘플링 비율을 올리는 Dynamic Sampling 기법을 활용할 수 있습니다.

2. 특정 중요 라우트 맞춤형 샘플링

전체 페이지에 일률적인 비율을 적용하는 대신, 무거운 연산이 일어나는 핵심 화면 위주로 샘플링을 차등 적용할 수 있습니다.

Sentry.init({
    // ...
    tracesSampler: (samplingContext) => {
        // 이미지 에디터, 결제 등 연산 집중 라우트는 20% 수집
        if (samplingContext.location?.pathname.startsWith('/editor')) {
            return 0.2;
        }
        // 단순 정적 페이지/안내 화면은 1%만 수집
        if (samplingContext.location?.pathname.startsWith('/about')) {
            return 0.01;
        }
        // 기본 5%
        return 0.05;
    },
    profileSessionSampleRate: 1.0,
});

3. Sentry 사용량 경고 및 Spike Protection 설정

  • Spike Protection: 일시적인 트래픽 폭증으로 인해 한 달 치 프로파일링 쿼터가 단 몇 시간 만에 소진되는 사고를 방지합니다. Sentry 대시보드의 Settings → Subscription → Spike Protection을 활성화해 두세요.
  • Quota Alert: 월간 허용량의 80%, 100% 도달 시 슬랙이나 이메일로 알림을 받도록 구성하여 예상치 못한 초과 과금을 원천 차단합니다.

요약 및 마무리

지금까지 프론트엔드 성능 최적화의 게임 체인저인 Sentry 브라우저 프로파일링의 동작 원리부터 실전 설정, 소스맵 보안, 비용 통제 전략까지 살펴보았습니다.

핵심 요점 요약

  1. 원인 규명 혁신: 트레이싱이 "느린 페이지"를 감지한다면, 프로파일링은 메인 스레드를 독점한 "범인 함수"를 Flame Graph로 특정합니다.
  2. 동작 필수 요건: HTTPS, Chromium 브라우저, 그리고 Document-Policy: js-profiling 응답 헤더가 설정되어 있어야 합니다.
  3. 소스맵 보안: build.sourcemap: 'hidden'과 빌드 후 소스맵 삭제 설정을 통해 코드는 외부에 노출하지 않고 Sentry 상에서만 완벽히 복원합니다.
  4. 비용 효율성: 트레이스 샘플링 비율(tracesSampleRate)과 연동되어 안전하고 경제적으로 운영할 수 있습니다.

성능 이슈 해결의 출발점은 정확한 측정입니다. 감(Gut Feeling)에 의존한 무의미한 리팩토링을 멈추고, 지금 바로 Sentry 브라우저 프로파일링을 활성화하여 병목 함수를 단번에 찾아보세요.

댓글 0개

댓글

댓글을 불러오는 중…

지원 문의