2025년 4월 23일·7분

브렌든 그렉의 지연 및 프로파일링을 위한 성능 기법

브렌든 그렉의 실용적인 방법(USE, RED, 플레임 그래프)을 통해 추측이 아닌 데이터로 지연 및 프로덕션 병목을 조사하는 법을 배우세요.

브렌든 그렉의 지연 및 프로파일링을 위한 성능 기법

브렌든 그렉의 접근법이 추측을 줄이는 이유

브렌든 그렉은 특히 리눅스 생태계에서 시스템 성능 분야에 큰 영향을 준 인물입니다. 그는 널리 쓰이는 책을 집필하고 실용적인 도구를 만들었으며—무엇보다도—실제 프로덕션 문제를 조사하는 명확한 방법들을 공유했습니다. 팀이 그의 접근법을 채택하는 이유는 실무에서 효과가 있기 때문입니다. 지연이 급증하고 모두가 답을 원할 때, 최소한의 혼란으로 “아마 X일 것”에서 “확실히 Y다”로 옮겨갈 수 있어야 합니다.

‘성능 방법론’이 진짜로 의미하는 것

성능 방법론은 단일 도구나 멋진 커맨드가 아닙니다. 조사할 때 반복 가능한 방식입니다: 무엇을 먼저 볼지, 본 것을 어떻게 해석할지, 다음에 무엇을 할지 결정하는 체크리스트입니다.

그 반복 가능성이 추측을 줄입니다. 가장 직감 있는 사람(혹은 가장 목소리가 큰 사람)의 의견에 의존하는 대신, 다음과 같은 일관된 프로세스를 따릅니다:

  • 문제를 특정 자원, 서비스 또는 코드 경로로 좁힙니다
  • 사건과 동일한 시간 창에서 무슨 일이 일어났는지 측정합니다
  • 변경을 가하기 전에 증거로 병목을 확인합니다

흔한 실패 모드: 측정 전에 고치기

많은 지연 조사에서 처음 5분 안에 일이 잘못됩니다. 사람들은 곧바로 수정을 시도합니다: "CPU를 추가하자", "서비스를 재시작하자", "캐시 크기를 늘리자", "GC를 튜닝하자", "네트워크일 거야." 때로는 도움이 되지만—자주 신호를 가리거나 시간을 낭비하거나 새로운 위험을 초래합니다.

그렉의 방법은 더 간단한 질문에 답할 수 있을 때까지 "해결"을 미루도록 합니다: 무엇이 포화 상태인가? 무엇이 오류를 내고 있는가? 무엇이 느려졌는가—처리량, 큐잉, 아니면 개별 연산인가?

이 가이드를 통해 할 수 있는 일

이 가이드는 범위를 좁히고, 올바른 신호를 측정하고, 최적화 전에 병목을 확인하도록 돕습니다. 목표는 프로덕션에서 지연과 프로파일링 문제를 조사하기 위한 구조화된 워크플로우를 제공해, 결과가 운에 좌우되지 않도록 하는 것입니다.

지연 기초: 튜닝 전에 무엇을 측정할지

지연은 증상입니다: 사용자가 작업이 끝나기를 더 오래 기다립니다. 원인은 보통 다른 곳에 있습니다—CPU 경쟁, 디스크나 네트워크 대기, 락 경쟁, 가비지 컬렉션, 큐잉 또는 원격 의존성 지연. 지연만 측정하면 고통이 존재한다는 것만 알 뿐, 어디서 시작되었는지는 알 수 없습니다.

처리량, 지연, 오류는 함께 움직인다

이 세 신호는 연결되어 있습니다:

  • 처리량(요청/초)이 증가하면 큐잉이 늘어나고, 이는 지연을 증가시킬 수 있습니다.
  • 오류는 관찰되는 지연을 줄일 수도 있습니다(빠른 실패) 또는 증가시킬 수 있습니다(재시도와 타임아웃).
  • 처리량을 제한(레이트 리밋, 백프레셔)하면 성공하는 요청 수는 줄지만 꼬리 지연은 개선될 수 있습니다.

튜닝 전에 동일한 시간 창에서 이 세 가지를 모두 캡처하세요. 그렇지 않으면 작업을 떨어뜨리거나 빠르게 실패하게 만들어 지연을 "해결"할 수 있습니다.

평균을 믿지 마세요: 분위수와 꼬리 지연

평균 지연은 사용자가 기억하는 스파이크를 숨깁니다. 평균이 50ms인 서비스도 자주 2초짜리 정지를 가질 수 있습니다.

다음 분위수를 추적하세요:

  • p50: 일반적인 사용자 경험
  • p95/p99: 꼬리 지연(대부분의 사고 고통이 있는 곳)

또한 지연의 모양을 지켜보세요: 안정적인 p50에 p99가 오르면 간헐적 정지(예: 락 경쟁, I/O 히치, 멈춤-세계 정지)가 일반적인 속도 저하보다 더 가능성이 큽니다.

지연 예산: 시간이 허용되는 곳

지연 예산은 간단한 회계 모델입니다: "요청이 300ms 이내에 끝나야 한다면 시간은 어떻게 분배될 수 있는가?" 다음과 같은 버킷으로 나눕니다:

  • 서비스 내부 시간(연산 + 대기)
  • 하위 서비스에서의 시간
  • 데이터베이스/캐시에서의 시간
  • 네트워크 전송 및 TLS
  • 큐에 있는 시간(스레드, 커넥션 풀, 로드 밸런서)

이 예산은 첫 측정 작업의 틀을 제공합니다: 스파이크 동안 어떤 버킷이 늘었는지 확인한 다음 그 영역을 조사하세요. 무작정 튜닝하는 대신 그 영역을 조사합니다.

명확한 질문과 범위로 시작하라

시스템이 느리다라는 비특정한 설명이면 조사 작업이 빗나갑니다. 그렉의 방법은 더 일찍 시작합니다: 문제를 특정하고 검증 가능한 질문으로 강제합니다.

‘느리다’를 정의하라(누구에게 느린가)

어떤 도구도 손대기 전에 두 문장을 적어두세요:

  • 무엇이 느린가? (페이지 로드, API 엔드포인트, 배치 잡, 로그인, 체크아웃, 특정 SQL 쿼리)
  • 어디서 느린가 관찰되는가? (고객 브라우저, 모바일 앱, 특정 리전, 특정 파드, 특정 호스트, 내부 서비스)

이렇게 하면 한 엔드포인트나 한 하위 의존성에 국한된 고통을 무시하고 잘못된 계층(예: 호스트 CPU)을 최적화하는 일을 막습니다.

시간 창과 범위를 선택하라

불만과 일치하는 창을 선택하고 가능하면 "정상" 비교 기간을 포함하세요.

조사를 명시적으로 범위화하세요:

  • 호스트 vs 서비스 vs 엔드포인트: "하나의 쿠버네티스 노드"와 "하나의 API 라우트"는 다릅니다.
  • 어떤 트래픽 슬라이스인지: 리전, 고객 계층, 오류가 발생한 요청만, 또는 전체 요청.
  • 보고를 촉발한 신호: p95 지연, 타임아웃, 큐 깊이, 사용자 타이밍.

여기서 정확하면 나중 단계(USE, RED, 프로파일링)가 더 빨라집니다. 가설이 맞다면 어떤 데이터가 변해야 하는지 알기 때문입니다.

최근 변경은 가설로 다뤄라, 정답으로 보지 말라

디플로이, 설정 변경, 트래픽 변화, 인프라 이벤트를 기록하되 인과를 가정하지 마세요. "만약 X라면 우리는 Y를 기대할 것이다" 식으로 적어 빨리 확인하거나 배제할 수 있도록 하세요.

간단한 조사 로그를 유지하라

작은 로그는 팀원 간 중복 작업을 막고 인계 시 원활하게 합니다.

Time | Question | Scope | Data checked | Result | Next step

다섯 줄 정도라도 긴급한 사고를 반복 가능한 프로세스로 바꿉니다.

USE 방법: 자원 병목의 빠른 목록화

USE 방법(활용률 Utilization, 포화 Saturation, 오류 Errors)은 그렉의 빠른 체크리스트로, CPU·메모리·디스크(스토리지)·네트워크라는 "큰 네 가지" 자원을 스캔해 어디를 좁혀야 할지 알게 해줍니다.

무엇인가: 자원별 체크리스트

수십 개의 대시보드를 보는 대신, 각 자원에 대해 동일한 세 가지 질문을 던지세요:

  • 활용률: 지금 얼마나 바쁜가?
  • 포화: 일이 쌓이고 있는가(큐, 대기 시간), 활용률이 최대가 아니어도?
  • 오류: 실패하거나 재시도되어 지연을 유발하는가?

일관되게 적용하면 어디에 "압력"이 있는지 빠르게 목록화할 수 있습니다.

실제 적용 방법

CPU의 경우, 활용률은 CPU 바쁜 비율%, 포화는 런큐(run-queue) 압력이나 실행을 기다리는 스레드로 나타나며, 오류는(컨테이너 환경에서) 스로틀링이나 잘못된 인터럽트 동작 등이 포함될 수 있습니다.

메모리는 활용률이 사용 메모리, 포화는 페이징 또는 빈번한 가비지 컬렉션으로 나타나며, 오류는 할당 실패나 OOM 이벤트입니다.

디스크는 장치 바쁜 시간(device busy time)이 활용률, 포화는 큐 깊이와 읽기/쓰기 대기 시간, 오류는 I/O 오류나 타임아웃입니다.

네트워크는 활용률이 처리량, 포화는 드롭/큐/지연, 오류는 재전송, 리셋, 패킷 손실입니다.

지연 사건에서 가장 유용한 신호

사용자가 느림을 보고할 때, 포화 신호가 가장 많이 드러납니다: 큐, 대기 시간, 경쟁은 원시 활용률보다 지연과 더 직접적으로 상관관계가 있습니다.

USE는 서비스 메트릭을 대체하지 않는다

서비스 수준 메트릭(요청 지연, 오류율)은 **영향(impact)**을 말해줍니다. USE는 다음에 어디를 볼지 알려줍니다. 실용적인 루프는:

  1. 사용자 영향 확인(Duration/Errors)
  2. USE 목록 실행
  3. 의심 자원을 더 깊은 도구(프로파일, 트레이스, 커널 스탯)로 들여다보기

RED 방법: 영향에 기반한 서비스 우선 신호

RED 방법은 호스트 그래프에 뛰어들기 전에 사용자 경험에 고정되어 있도록 도와줍니다.

  • Rate: 서비스나 엔드포인트가 처리하는 요청 수
  • Errors: 실패하는 요청 수(앱에서 "실패"가 무엇을 의미하는지 포함)
  • Duration: 성공한 요청이 소요하는 시간(평균이 아니라 분위수로 추적)

RED가 우선순위에 도움이 되는 이유

RED는 사용자에 영향을 주지 않는 "흥미로운" 시스템 메트릭을 쫓는 일을 막아줍니다. 더 타이트한 루프를 강제합니다: 어떤 엔드포인트가, 어떤 사용자에게, 언제 느린가? Duration이 한 라우트에서만 급증하고 전체 CPU가 평탄하면 이미 더 날카로운 출발점을 가진 것입니다.

유용한 습관: RED를 서비스 및 상위 엔드포인트(또는 주요 RPC 메서드)별로 분해해 두세요. 그러면 광범위한 저하와 국소적 회귀를 구분하기 쉽습니다.

RED 증상을 USE 점검으로 매핑하기

RED는 어디가 아픈지 말해줍니다. USE는 어떤 자원이 책임이 있는지 테스트하도록 돕습니다.

예시:

  • Duration 상승 + Rate 안정 → 포화/큐잉 점검: CPU 런 큐, 스토리지 지연, DB 커넥션 풀.
  • Errors 상승 + Duration 상승 → 타임아웃/재시도 점검: 과부하된 하위 시스템, 스레드 풀, 네트워크 드롭.
  • Rate 상승 + Duration 상승 → 용량 한계 점검: CPU 활용률, 로드 밸런서 동작, 오토스케일 지연.

최소한의 “무엇이 바뀌었나?” 대시보드

레이아웃을 단순하게 유지하세요:

  1. RED 개요: 서비스의 Rate, Errors, p50/p95/p99 Duration
  2. 상위 엔드포인트: 트래픽이나 worst p95로 정렬된 엔드포인트별 RED
  3. 의존성: 주요 하위 시스템(DB, 캐시, 외부 API)에 대한 RED 스타일 패널
  4. 상관용 행: 시스템 메트릭(예: CPU, 메모리 압력, 디스크 I/O 지연, 네트워크 재전송)을 소량 배치해 서비스 뷰에서 근본 원인 테스트로 빠르게 이동할 수 있게 함

일관된 사고 워크플로우를 원한다면 이 섹션을 USE 목록과 /blog/use-method-overview에 연계해 "사용자가 느낀다"에서 "이 자원이 제약이다"로 덜 허둥대며 이동하게 하세요.

우선순위 정하기: 다음에 물어볼 최선의 질문 선택

인시던트 중 안전하게 변경하기
스냅샷을 찍고 하나의 수정만 시도한 뒤 결과가 만족스럽지 않으면 빠르게 롤백하세요.

성능 조사는 몇 분 안에 수십 개의 차트와 가설로 폭발할 수 있습니다. 그렉의 사고방식은 좁게 유지하는 것입니다: 당신의 임무는 "더 많은 데이터를 수집"하는 것이 아니라 불확실성을 가장 빠르게 제거하는 다음 질문을 던지는 것입니다.

병목에 대한 80/20 규칙

대부분의 지연 문제는 하나의 큰 비용(또는 두어 개의 쌍)에 의해 지배됩니다: 하나의 뜨거운 락, 하나의 느린 의존성, 하나의 과부하된 디스크, 하나의 GC 일관성 패턴. 우선순위는 그 지배적 비용을 먼저 찾는 것입니다. 서로 다른 다섯 곳에서 5%씩 깎는 것은 사용자 눈에 보이는 지연을 거의 줄이지 못합니다.

실용적 테스트: "우리 지연 변화의 대부분을 설명할 수 있는 것은 무엇인가?" 어떤 가설이 아주 작은 비율만 설명할 수 있다면 우선순위가 낮습니다.

탑다운 vs 바텀업: 어디서 시작할지

사용자 영향 여부를 답해야 할 때는 탑다운을 사용하세요. 엔드포인트(RED 스타일 신호)에서 시작합니다: 지연, 처리량, 오류. 이는 중요 경로에 있지 않은 것을 최적화하는 일을 피하게 합니다.

호스트가 명백히 아플 때는 바텀업을 사용하세요(예: USE 스타일 증상): CPU 포화, 통제 불능 메모리 압력, I/O 대기. 노드가 박혀 있으면 엔드포인트 분위수만 보며 제약을 이해하지 못한 채 시간을 낭비합니다.

허둥대지 않게 하는 간단한 결정 트리

알람이 울리면 분기를 하나 선택하고 그것을 확인하거나 배제할 때까지 그 경로를 고수하세요:

  • 지연 급증 + 오류 급증 → "의존성인가 용량 이벤트인가?" (타임아웃, 커넥션 풀 고갈, 하위 5xx)
  • 지연 급증 + CPU 급증 → "CPU가 실제로 유용한 작업을 하고 있는가 아니면 정지했는가?" (on-CPU vs off-CPU)
  • 지연 급증 + 높은 I/O 대기 → "어떤 디바이스나 파일시스템 큐가 밀리고 있는가?"
  • 자원 급증 없는 지연 급증 → "시간이 어디서 대기되고 있는가?" (락, 스케줄러, 네트워크, 원격 호출)

메트릭 과부하를 피하고 체계적으로 유지하라

시작 신호 집합을 작게 제한한 다음 무언가가 움직일 때만 드릴다운하세요. 초점을 유지할 체크리스트가 필요하면, 단계들을 /blog/performance-incident-workflow 같은 런북에 연결해 모든 새로운 메트릭이 특정 질문에 답하도록 하세요.

시스템을 내리지 않고 프로덕션에서 프로파일링하기

프로덕션 프로파일링은 라이브 시스템을 건드리기 때문에 위험하게 느껴질 수 있지만—토론을 증거로 바꾸는 가장 빠른 방법인 경우가 많습니다. 로그와 대시보드는 무엇이 느린지 말해주지만, 프로파일링은 시간이 어디로 가는지: 어떤 함수가 뜨겁게 실행되는지, 어떤 스레드가 대기하는지, 사고 동안 어떤 코드 경로가 지배적인지 알려줍니다.

프로파일링이 실제로 답하는 것

프로파일링은 "시간 예산" 도구입니다. 이론(예: "데이터베이스 탓" vs "GC 탓") 대신 "CPU 샘플의 45%가 JSON 파싱에서 발생" 또는 "대부분의 요청이 뮤텍스에서 블록" 같은 증거를 줍니다. 이는 다음 단계를 한두 가지 구체적인 수정으로 좁힙니다.

프로덕션에서 쓸 수 있는 일반적인 유형

  • CPU 프로파일링: on-CPU에서 어떤 코드가 실행되는지 보여줍니다.
  • Off-CPU(대기) 프로파일링: 스레드가 블록된 곳( I/O 대기, 스케줄러 지연, sleep, 네트워크, 디스크)을 보여줍니다.
  • 락 프로파일링: 락 경쟁—락, 뮤텍스, 읽기/쓰기 락을 기다리며 잃는 시간—을 보여줍니다.

각각 다른 질문에 답합니다. 지연이 높고 CPU가 낮으면 대개 off-CPU나 락 시간일 가능성이 큽니다.

항상 켜두기 vs 필요 시 켜기

  • 항상 켜진 프로파일링(연속, 낮은 오버헤드)은 "새벽 3시에 일어난 일" 같은 미스터리를 뒤져볼 수 있어 유용합니다.
  • 온디맨드 프로파일링은 스파이크 동안의 타깃 캡처입니다. 도입은 더 쉽지만 빠르게 트리거할 준비가 되어 있어야 합니다.

많은 팀이 온디맨드로 시작해 안전성을 신뢰하고 반복되는 문제를 보면서 항상 켜기로 확장합니다.

안전성: 오버헤드, 샘플링, 짧은 창

프로덕션 안전 프로파일링은 비용 제어입니다. 전체 이벤트를 추적하지 말고 샘플링을 선호하세요. 캡처 창을 짧게 유지(예: 10–30초)하고 캐너리에서 먼저 오버헤드를 측정하세요. 확신이 서지 않으면 낮은 빈도 샘플링으로 시작하고 신호가 너무 시끄러우면 늘리세요.

플레임 그래프: 읽는 법과 오판을 피하는 법

빌드로 배우며 크레딧 획득
만든 것을 공유하면 Koder.ai에서 계속 실험할 수 있는 크레딧을 얻습니다.

플레임 그래프는 프로파일링 창 동안 샘플된 시간이 어디로 갔는지를 시각화합니다. 각 "박스"는 함수(또는 스택 프레임)이고 각 스택은 해당 함수에 도달한 호출 경로를 보여줍니다. 패턴을 빠르게 찾는 데 탁월하지만—그 자체로 "버그가 여기 있다"고 말해주지 않습니다.

플레임 그래프가 보여주는 것(그리고 보여주지 않는 것)

플레임 그래프는 보통 on-CPU 샘플을 나타냅니다: 프로그램이 실제로 CPU 코어에서 실행된 시간. CPU 집약적인 코드 경로, 비효율적 파싱, 과도한 직렬화, 실제로 CPU를 태우는 핫스팟을 강조할 수 있습니다.

그러나 플레임 그래프는 디스크, 네트워크, 스케줄러 지연, 뮤텍스 블록 같은 대기를 직접 보여주지 않습니다(이것은 off-CPU 시간이며 다른 프로파일링이 필요). 또한 스코프된 증상에 연결하지 않으면 사용자 가시적 지연의 인과를 증명하지 않습니다.

너비와 스택 깊이 읽기

  • 너비: 해당 프레임이 샘플에서 얼마나 자주 나타났는지. 더 넓으면 대개 "더 많은 CPU 시간"을 의미하지만 선택된 시간 창 내에서만 그렇습니다.
  • 스택 깊이: 호출 깊이. 깊은 스택이 항상 나쁜 것은 아닙니다; 중요한 것은 어떤 경로가 지배적인지와 그것이 당신이 신경 쓰는 작업과 일치하는지입니다.

피해야 할 흔한 함정

가장 넓은 박스를 무조건 비난하는 유혹이 있습니다. 그러나 물어보세요: 이것이 바꿀 수 있는 핫스팟인가, 아니면 실제 문제는 상류에 있고 이 박스는 단지 "malloc, GC, 로깅에서 보낸 시간"을 나타내는 전달자일 뿐인가? 또한 JIT, 인라이닝, 심볼 누락 같은 문맥 부재가 박스를 잘못 보이게 할 수 있습니다.

플레임 그래프를 정밀한 질문과 함께 사용하라

플레임 그래프를 다음과 같은 범위된 질문에 대한 답으로 다루세요: 어떤 엔드포인트, 어떤 시간 창, 어떤 호스트, 무엇이 변경되었는가. "전(before) vs 후(after)" 또는 "건강한 상태 vs 저하 상태"의 플레임 그래프를 같은 요청 경로에 대해 비교하면 노이즈를 피할 수 있습니다.

Off-CPU 시간: 지연의 숨은 원천

지연이 급증하면 많은 팀이 먼저 CPU%를 봅니다. 이해할 만하지만—대부분 잘못된 방향을 가리킵니다. 서비스가 "CPU 20%만 사용"하고 있어도 스레드가 대부분 실행되지 않고 대기하고 있다면 여전히 심하게 느릴 수 있습니다.

CPU%만 믿으면 왜 오해하는가

CPU%는 "프로세서가 얼마나 바쁜가"에 대한 답입니다. "내 요청 시간이 어디로 갔는가"에 대한 답은 아닙니다. 요청의 월드클럭 시간은 on-CPU 작업과 off-CPU 대기 시간을 모두 포함합니다.

흔한 off-CPU 원인

Off-CPU 시간은 보통 의존성과 경쟁 뒤에 숨습니다:

  • 디스크 I/O: 동기식 읽기/쓰기, fsync, 느린 스토리지, 페이지 캐시 미스
  • 네트워크 대기: DNS 조회, TCP 재전송, 과부하된 업스트림 서비스
  • 락 및 뮤텍스 경쟁: 락, 읽기/쓰기 락, 할당기 경쟁에서 블록된 스레드
  • 큐잉: 스레드 풀, 커넥션 풀, 내부 작업 큐에서의 대기

주의할 증상

다음 신호는 종종 off-CPU 병목과 연관됩니다:

  • 증가하는 큐 대기 시간(요청이 실행되기 전 기다리는 시간)
  • 증가하는 runnable threads(CPU 시간 경쟁 증가)
  • 높은 I/O 대기 및 더 긴 디스크/네트워크 지연

이 신호들은 "우리는 기다리고 있다"고 알려주지만 무엇을 기다리는지는 말해주지 않습니다.

off-CPU 프로파일링이 "시간이 어디로 갔는지" 보여주는 방법

Off-CPU 프로파일링은 왜 실행되지 않았는지에 시간을 귀속시킵니다: 시스템 콜에서 블록, 락 대기, sleep, 디스케줄 등. 이는 지연 작업에서 모호한 느려짐을 실행 가능한 범주로 바꿉니다: "뮤텍스 X에서 블록", "디스크의 read()에서 대기", "업스트림에 대한 connect()에 걸림". 대기를 이름 붙이면 측정하고 확인하고 고칠 수 있습니다.

직감이 아닌 증거로 병목을 확인하라

성능 작업이 실패하는 순간은 보통 누군가 의심스러운 메트릭을 보고 그것이 "문제"라 선언하고 튜닝을 시작할 때입니다. 그렉의 방법은 속도를 늦추고 무엇이 시스템을 제한하는지 증명하라고 강제합니다.

병목, 핫스팟, 노이즈

병목은 현재 처리량을 제한하거나 지연을 일으키는 자원/구성 요소입니다. 이를 완화하면 사용자가 개선을 봅니다.

핫스팟은 시간이 많이 소비되는 곳(예: 프로파일에 자주 나타나는 함수)입니다. 핫스팟은 실제 병목일 수도 있고 단지 느린 경로에 영향을 주지 않는 바쁜 작업일 수도 있습니다.

노이즈는 의미 있어 보이지만 실제로는 그렇지 않은 모든 것: 백그라운드 잡, 일회성 스파이크, 샘플링 아티팩트, 캐싱 효과, 사용자-visible 문제와 상관없는 "top talkers" 등.

비교와 통제된 변경으로 증명하라

먼저 깨끗한 전(before) 스냅샷을 캡처하세요: 사용자-대면 증상(지연 또는 오류율)과 주요 후보 신호(CPU 포화, 큐 깊이, 디스크 I/O, 락 경쟁 등). 그런 다음 의심 원인만 영향을 줄 통제된 변경을 적용하세요.

인과 관계 테스트 예시:

  • 의심 자원에 용량을 추가(워커 하나 추가, CPU 쉐어 증가, 커넥션 풀 확장)하고 지연이 개선되는지 확인.
  • 수요를 일시적으로 줄여(시끄러운 엔드포인트 제한, 더 작은 워크로드 재생) 의심 제약이 완화되는지 확인.

상관관계는 힌트일 뿐 결론이 아닙니다. "지연이 올라갈 때 CPU도 올라간다"면, CPU 가용성을 변경하거나 CPU 작업을 줄여 지연이 따라오는지 확인하세요.

증명한 내용을 문서화하라

무엇을 측정했고, 정확히 어떤 변경을 했으며, 전/후 결과와 관찰된 개선을 적어두세요. 이는 일회성 성공을 재사용 가능한 플레이북으로 바꾸고 나중에 "직감"이 역사를 덮어쓰는 것을 막습니다.

성능 사고에 대한 반복 가능한 워크플로우 구축

백엔드 병목 반복 개선
Go 서비스 변경안을 작성하고 diff를 검토한 뒤 레포용 소스 코드를 내보내세요.

성능 사고는 긴박하게 느껴지므로 추측이 끼어들기 쉽습니다. 경량의 반복 가능한 워크플로우는 "뭔가 느리다"에서 "무엇이 바뀌었는지 안다"로 이동하는 데 도움이 됩니다.

사고 루프: 감지 → 분류 → 측정 → 수정

감지: CPU가 아니라 사용자-대면 지연과 오류율로 알람을 설정하세요. p95/p99 지연이 일정 시간 지속되면 페이지를 보냅니다.

분류: 즉시 세 가지 질문에 답하세요: 무엇이 느린가, 언제 시작되었는가, 누가 영향을 받는가? 범위(서비스, 엔드포인트, 리전, 코호트)를 말할 수 없다면 최적화할 준비가 안 된 것입니다.

측정: 병목을 좁히는 증거를 수집하세요. 비교를 쉽게 하기 위해 시간 제한 캡처(예: 60–180초)를 선호하세요.

수정: 한 번에 한 가지 변경만 하고 동일한 신호를 다시 측정해 개선을 확인하고 플라시보를 배제하세요.

작은 그래프 집합 표준화

사고 중에 모두가 사용하는 공유 대시보드를 유지하세요. 지루하고 일관되게 만드세요:

  • 지연: p50 / p95 / p99(핵심 엔드포인트별)
  • RED 신호: Rate, Errors, Duration(서비스 우선 뷰)
  • 몇 가지 USE 메트릭: CPU, 디스크, 네트워크의 활용률, 포화, 오류

목표는 모든 것을 그리는 것이 아니라 첫 사실(First-Fact)을 얻는 시간을 줄이는 것입니다.

핵심 엔드포인트별 “골든 신호” 정의

가장 중요한 엔드포인트(체크아웃, 로그인, 검색)에 계측을 집중하세요. 각 엔드포인트에 대해 기대되는 p95, 최대 오류율, 주요 의존성(DB, 캐시, 서드파티)을 합의하세요.

사고 중 캡처할 항목 결정

다음 장애가 발생하기 전에 캡처 킷을 합의하세요:

  • 프로파일(CPU 및 off-CPU)과 플레임 그래프
  • 느린 엔드포인트용 트레이스
  • 오류/타임아웃 로그(샘플링)

이를 /runbooks/latency 같은 짧은 런북에 문서화하고 누가 캡처를 실행할 수 있는지와 아티팩트가 어디에 저장되는지 포함하세요.

Koder.ai가 그렉 스타일 워크플로우에서 차지하는 위치

그렉의 방법론은 본질적으로 통제된 변경과 빠른 검증에 관한 것입니다. 팀이 Koder.ai(웹·백엔드·모바일 앱을 생성하고 반복하는 챗 중심 플랫폼)를 사용해 서비스를 구축한다면, 두 가지 기능이 그 사고방식에 잘 맞습니다:

  • Planning Mode는 "아마 X일 것이다"를 명시적 가설과 작고 검증 가능한 변경 집합으로 바꾸는 데 도움을 줍니다.
  • 스냅샷과 롤백은 안전한 단일 변수 실험을 지원합니다: 하나의 변경을 적용하고 RED/USE 신호를 재측정한 뒤 증거가 "아니다"면 빠르게 롤백합니다.

사고 중에 새 코드를 생성하지 않더라도, 작은 차이, 측정 가능한 결과, 빠른 되돌리기라는 습관은 그렉이 권장하는 습관과 같습니다.

실용적 워크스루: 지연 스파이크에서 검증된 수정까지

시나리오: 피크 트래픽에서 p99 급증

오전 10:15, 대시보드에서 API의 p99 지연이 피크에서 약 120ms에서 900ms로 상승했습니다. 오류율은 평탄하지만 고객이 "느리다"고 보고합니다.

1단계 — 사용자 영향 파악을 위해 RED로 시작

서비스 우선으로 시작하세요: Rate, Errors, Duration.

Duration을 엔드포인트별로 분해하면 하나의 경로가 p99를 지배하는 것을 봅니다: POST /checkout. 처리량은 2×로 증가했고 오류는 정상, 그러나 동시성이 증가할 때 특히 Duration이 급증합니다. 이는 큐잉 또는 경쟁을 가리키며 전반적 실패는 아닙니다.

다음으로 지연이 계산 시간인지 대기 시간인지 확인하세요: 애플리케이션의 "핸들러 시간" vs 전체 요청 시간(스팬이 있다면 업스트림 vs 다운스트림). 핸들러 시간은 낮고 전체 시간이 높았습니다—요청이 기다리고 있습니다.

2단계 — 의심 호스트에 USE 적용

가능성 있는 병목을 목록화하세요: CPU, 메모리, 디스크, 네트워크의 활용률, 포화, 오류.

CPU 활용률은 약 35%였지만 CPU 런 큐와 컨텍스트 스위치가 증가했습니다. 디스크와 네트워크는 안정적입니다. 이 불일치(낮은 CPU%, 높은 대기)는 스레드가 CPU를 태우고 있지 않고 블록되고 있다는 고전적 힌트입니다.

3단계 — 증상에 따라 프로파일링 선택

  • CPU가 높다면: CPU 프로파일링(on-CPU 플레임 그래프)으로 시간이 어디로 가는지 확인.
  • 요청이 기다린다면: off-CPU 프로파일링으로 스레드가 락, I/O, 스케줄링 어디에 블록되는지 확인.

스파이크 동안 off-CPU 프로파일을 캡처하니 공유된 "프로모션 검증" 캐시 주변의 뮤텍스에서 많은 시간이 소비되는 것이 드러났습니다.

4단계 — 수정하고 검증

전역 락을 키별 락 또는 락-프리 읽기 경로로 교체하고 배포하니 p99가 기준선으로 돌아왔고 처리량은 높은 상태를 유지했습니다.

사후 점검 목록:

  • 정확한 RED 증상과 좁아진 엔드포인트를 기록.
  • 프로파일과 그 시간 창을 저장.
  • 특정 포화 신호(예: 락 대기 / 런 큐)에 대한 알람 추가.
  • 다시 발생하면 물어볼 "다음 질문"을 적어두기.

Related posts