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

브렌든 그렉은 특히 리눅스 생태계에서 시스템 성능 분야에 큰 영향을 준 인물입니다. 그는 널리 쓰이는 책을 집필하고 실용적인 도구를 만들었으며—무엇보다도—실제 프로덕션 문제를 조사하는 명확한 방법들을 공유했습니다. 팀이 그의 접근법을 채택하는 이유는 실무에서 효과가 있기 때문입니다. 지연이 급증하고 모두가 답을 원할 때, 최소한의 혼란으로 “아마 X일 것”에서 “확실히 Y다”로 옮겨갈 수 있어야 합니다.
성능 방법론은 단일 도구나 멋진 커맨드가 아닙니다. 조사할 때 반복 가능한 방식입니다: 무엇을 먼저 볼지, 본 것을 어떻게 해석할지, 다음에 무엇을 할지 결정하는 체크리스트입니다.
그 반복 가능성이 추측을 줄입니다. 가장 직감 있는 사람(혹은 가장 목소리가 큰 사람)의 의견에 의존하는 대신, 다음과 같은 일관된 프로세스를 따릅니다:
많은 지연 조사에서 처음 5분 안에 일이 잘못됩니다. 사람들은 곧바로 수정을 시도합니다: "CPU를 추가하자", "서비스를 재시작하자", "캐시 크기를 늘리자", "GC를 튜닝하자", "네트워크일 거야." 때로는 도움이 되지만—자주 신호를 가리거나 시간을 낭비하거나 새로운 위험을 초래합니다.
그렉의 방법은 더 간단한 질문에 답할 수 있을 때까지 "해결"을 미루도록 합니다: 무엇이 포화 상태인가? 무엇이 오류를 내고 있는가? 무엇이 느려졌는가—처리량, 큐잉, 아니면 개별 연산인가?
이 가이드는 범위를 좁히고, 올바른 신호를 측정하고, 최적화 전에 병목을 확인하도록 돕습니다. 목표는 프로덕션에서 지연과 프로파일링 문제를 조사하기 위한 구조화된 워크플로우를 제공해, 결과가 운에 좌우되지 않도록 하는 것입니다.
지연은 증상입니다: 사용자가 작업이 끝나기를 더 오래 기다립니다. 원인은 보통 다른 곳에 있습니다—CPU 경쟁, 디스크나 네트워크 대기, 락 경쟁, 가비지 컬렉션, 큐잉 또는 원격 의존성 지연. 지연만 측정하면 고통이 존재한다는 것만 알 뿐, 어디서 시작되었는지는 알 수 없습니다.
이 세 신호는 연결되어 있습니다:
튜닝 전에 동일한 시간 창에서 이 세 가지를 모두 캡처하세요. 그렇지 않으면 작업을 떨어뜨리거나 빠르게 실패하게 만들어 지연을 "해결"할 수 있습니다.
평균 지연은 사용자가 기억하는 스파이크를 숨깁니다. 평균이 50ms인 서비스도 자주 2초짜리 정지를 가질 수 있습니다.
다음 분위수를 추적하세요:
또한 지연의 모양을 지켜보세요: 안정적인 p50에 p99가 오르면 간헐적 정지(예: 락 경쟁, I/O 히치, 멈춤-세계 정지)가 일반적인 속도 저하보다 더 가능성이 큽니다.
지연 예산은 간단한 회계 모델입니다: "요청이 300ms 이내에 끝나야 한다면 시간은 어떻게 분배될 수 있는가?" 다음과 같은 버킷으로 나눕니다:
이 예산은 첫 측정 작업의 틀을 제공합니다: 스파이크 동안 어떤 버킷이 늘었는지 확인한 다음 그 영역을 조사하세요. 무작정 튜닝하는 대신 그 영역을 조사합니다.
시스템이 느리다라는 비특정한 설명이면 조사 작업이 빗나갑니다. 그렉의 방법은 더 일찍 시작합니다: 문제를 특정하고 검증 가능한 질문으로 강제합니다.
어떤 도구도 손대기 전에 두 문장을 적어두세요:
이렇게 하면 한 엔드포인트나 한 하위 의존성에 국한된 고통을 무시하고 잘못된 계층(예: 호스트 CPU)을 최적화하는 일을 막습니다.
불만과 일치하는 창을 선택하고 가능하면 "정상" 비교 기간을 포함하세요.
조사를 명시적으로 범위화하세요:
여기서 정확하면 나중 단계(USE, RED, 프로파일링)가 더 빨라집니다. 가설이 맞다면 어떤 데이터가 변해야 하는지 알기 때문입니다.
디플로이, 설정 변경, 트래픽 변화, 인프라 이벤트를 기록하되 인과를 가정하지 마세요. "만약 X라면 우리는 Y를 기대할 것이다" 식으로 적어 빨리 확인하거나 배제할 수 있도록 하세요.
작은 로그는 팀원 간 중복 작업을 막고 인계 시 원활하게 합니다.
Time | Question | Scope | Data checked | Result | Next step
다섯 줄 정도라도 긴급한 사고를 반복 가능한 프로세스로 바꿉니다.
USE 방법(활용률 Utilization, 포화 Saturation, 오류 Errors)은 그렉의 빠른 체크리스트로, CPU·메모리·디스크(스토리지)·네트워크라는 "큰 네 가지" 자원을 스캔해 어디를 좁혀야 할지 알게 해줍니다.
수십 개의 대시보드를 보는 대신, 각 자원에 대해 동일한 세 가지 질문을 던지세요:
일관되게 적용하면 어디에 "압력"이 있는지 빠르게 목록화할 수 있습니다.
CPU의 경우, 활용률은 CPU 바쁜 비율%, 포화는 런큐(run-queue) 압력이나 실행을 기다리는 스레드로 나타나며, 오류는(컨테이너 환경에서) 스로틀링이나 잘못된 인터럽트 동작 등이 포함될 수 있습니다.
메모리는 활용률이 사용 메모리, 포화는 페이징 또는 빈번한 가비지 컬렉션으로 나타나며, 오류는 할당 실패나 OOM 이벤트입니다.
디스크는 장치 바쁜 시간(device busy time)이 활용률, 포화는 큐 깊이와 읽기/쓰기 대기 시간, 오류는 I/O 오류나 타임아웃입니다.
네트워크는 활용률이 처리량, 포화는 드롭/큐/지연, 오류는 재전송, 리셋, 패킷 손실입니다.
사용자가 느림을 보고할 때, 포화 신호가 가장 많이 드러납니다: 큐, 대기 시간, 경쟁은 원시 활용률보다 지연과 더 직접적으로 상관관계가 있습니다.
서비스 수준 메트릭(요청 지연, 오류율)은 **영향(impact)**을 말해줍니다. USE는 다음에 어디를 볼지 알려줍니다. 실용적인 루프는:
RED 방법은 호스트 그래프에 뛰어들기 전에 사용자 경험에 고정되어 있도록 도와줍니다.
RED는 사용자에 영향을 주지 않는 "흥미로운" 시스템 메트릭을 쫓는 일을 막아줍니다. 더 타이트한 루프를 강제합니다: 어떤 엔드포인트가, 어떤 사용자에게, 언제 느린가? Duration이 한 라우트에서만 급증하고 전체 CPU가 평탄하면 이미 더 날카로운 출발점을 가진 것입니다.
유용한 습관: RED를 서비스 및 상위 엔드포인트(또는 주요 RPC 메서드)별로 분해해 두세요. 그러면 광범위한 저하와 국소적 회귀를 구분하기 쉽습니다.
RED는 어디가 아픈지 말해줍니다. USE는 어떤 자원이 책임이 있는지 테스트하도록 돕습니다.
예시:
레이아웃을 단순하게 유지하세요:
일관된 사고 워크플로우를 원한다면 이 섹션을 USE 목록과 /blog/use-method-overview에 연계해 "사용자가 느낀다"에서 "이 자원이 제약이다"로 덜 허둥대며 이동하게 하세요.
성능 조사는 몇 분 안에 수십 개의 차트와 가설로 폭발할 수 있습니다. 그렉의 사고방식은 좁게 유지하는 것입니다: 당신의 임무는 "더 많은 데이터를 수집"하는 것이 아니라 불확실성을 가장 빠르게 제거하는 다음 질문을 던지는 것입니다.
대부분의 지연 문제는 하나의 큰 비용(또는 두어 개의 쌍)에 의해 지배됩니다: 하나의 뜨거운 락, 하나의 느린 의존성, 하나의 과부하된 디스크, 하나의 GC 일관성 패턴. 우선순위는 그 지배적 비용을 먼저 찾는 것입니다. 서로 다른 다섯 곳에서 5%씩 깎는 것은 사용자 눈에 보이는 지연을 거의 줄이지 못합니다.
실용적 테스트: "우리 지연 변화의 대부분을 설명할 수 있는 것은 무엇인가?" 어떤 가설이 아주 작은 비율만 설명할 수 있다면 우선순위가 낮습니다.
사용자 영향 여부를 답해야 할 때는 탑다운을 사용하세요. 엔드포인트(RED 스타일 신호)에서 시작합니다: 지연, 처리량, 오류. 이는 중요 경로에 있지 않은 것을 최적화하는 일을 피하게 합니다.
호스트가 명백히 아플 때는 바텀업을 사용하세요(예: USE 스타일 증상): CPU 포화, 통제 불능 메모리 압력, I/O 대기. 노드가 박혀 있으면 엔드포인트 분위수만 보며 제약을 이해하지 못한 채 시간을 낭비합니다.
알람이 울리면 분기를 하나 선택하고 그것을 확인하거나 배제할 때까지 그 경로를 고수하세요:
시작 신호 집합을 작게 제한한 다음 무언가가 움직일 때만 드릴다운하세요. 초점을 유지할 체크리스트가 필요하면, 단계들을 /blog/performance-incident-workflow 같은 런북에 연결해 모든 새로운 메트릭이 특정 질문에 답하도록 하세요.
프로덕션 프로파일링은 라이브 시스템을 건드리기 때문에 위험하게 느껴질 수 있지만—토론을 증거로 바꾸는 가장 빠른 방법인 경우가 많습니다. 로그와 대시보드는 무엇이 느린지 말해주지만, 프로파일링은 시간이 어디로 가는지: 어떤 함수가 뜨겁게 실행되는지, 어떤 스레드가 대기하는지, 사고 동안 어떤 코드 경로가 지배적인지 알려줍니다.
프로파일링은 "시간 예산" 도구입니다. 이론(예: "데이터베이스 탓" vs "GC 탓") 대신 "CPU 샘플의 45%가 JSON 파싱에서 발생" 또는 "대부분의 요청이 뮤텍스에서 블록" 같은 증거를 줍니다. 이는 다음 단계를 한두 가지 구체적인 수정으로 좁힙니다.
각각 다른 질문에 답합니다. 지연이 높고 CPU가 낮으면 대개 off-CPU나 락 시간일 가능성이 큽니다.
많은 팀이 온디맨드로 시작해 안전성을 신뢰하고 반복되는 문제를 보면서 항상 켜기로 확장합니다.
프로덕션 안전 프로파일링은 비용 제어입니다. 전체 이벤트를 추적하지 말고 샘플링을 선호하세요. 캡처 창을 짧게 유지(예: 10–30초)하고 캐너리에서 먼저 오버헤드를 측정하세요. 확신이 서지 않으면 낮은 빈도 샘플링으로 시작하고 신호가 너무 시끄러우면 늘리세요.
플레임 그래프는 프로파일링 창 동안 샘플된 시간이 어디로 갔는지를 시각화합니다. 각 "박스"는 함수(또는 스택 프레임)이고 각 스택은 해당 함수에 도달한 호출 경로를 보여줍니다. 패턴을 빠르게 찾는 데 탁월하지만—그 자체로 "버그가 여기 있다"고 말해주지 않습니다.
플레임 그래프는 보통 on-CPU 샘플을 나타냅니다: 프로그램이 실제로 CPU 코어에서 실행된 시간. CPU 집약적인 코드 경로, 비효율적 파싱, 과도한 직렬화, 실제로 CPU를 태우는 핫스팟을 강조할 수 있습니다.
그러나 플레임 그래프는 디스크, 네트워크, 스케줄러 지연, 뮤텍스 블록 같은 대기를 직접 보여주지 않습니다(이것은 off-CPU 시간이며 다른 프로파일링이 필요). 또한 스코프된 증상에 연결하지 않으면 사용자 가시적 지연의 인과를 증명하지 않습니다.
가장 넓은 박스를 무조건 비난하는 유혹이 있습니다. 그러나 물어보세요: 이것이 바꿀 수 있는 핫스팟인가, 아니면 실제 문제는 상류에 있고 이 박스는 단지 "malloc, GC, 로깅에서 보낸 시간"을 나타내는 전달자일 뿐인가? 또한 JIT, 인라이닝, 심볼 누락 같은 문맥 부재가 박스를 잘못 보이게 할 수 있습니다.
플레임 그래프를 다음과 같은 범위된 질문에 대한 답으로 다루세요: 어떤 엔드포인트, 어떤 시간 창, 어떤 호스트, 무엇이 변경되었는가. "전(before) vs 후(after)" 또는 "건강한 상태 vs 저하 상태"의 플레임 그래프를 같은 요청 경로에 대해 비교하면 노이즈를 피할 수 있습니다.
지연이 급증하면 많은 팀이 먼저 CPU%를 봅니다. 이해할 만하지만—대부분 잘못된 방향을 가리킵니다. 서비스가 "CPU 20%만 사용"하고 있어도 스레드가 대부분 실행되지 않고 대기하고 있다면 여전히 심하게 느릴 수 있습니다.
CPU%는 "프로세서가 얼마나 바쁜가"에 대한 답입니다. "내 요청 시간이 어디로 갔는가"에 대한 답은 아닙니다. 요청의 월드클럭 시간은 on-CPU 작업과 off-CPU 대기 시간을 모두 포함합니다.
Off-CPU 시간은 보통 의존성과 경쟁 뒤에 숨습니다:
다음 신호는 종종 off-CPU 병목과 연관됩니다:
이 신호들은 "우리는 기다리고 있다"고 알려주지만 무엇을 기다리는지는 말해주지 않습니다.
Off-CPU 프로파일링은 왜 실행되지 않았는지에 시간을 귀속시킵니다: 시스템 콜에서 블록, 락 대기, sleep, 디스케줄 등. 이는 지연 작업에서 모호한 느려짐을 실행 가능한 범주로 바꿉니다: "뮤텍스 X에서 블록", "디스크의 read()에서 대기", "업스트림에 대한 connect()에 걸림". 대기를 이름 붙이면 측정하고 확인하고 고칠 수 있습니다.
성능 작업이 실패하는 순간은 보통 누군가 의심스러운 메트릭을 보고 그것이 "문제"라 선언하고 튜닝을 시작할 때입니다. 그렉의 방법은 속도를 늦추고 무엇이 시스템을 제한하는지 증명하라고 강제합니다.
병목은 현재 처리량을 제한하거나 지연을 일으키는 자원/구성 요소입니다. 이를 완화하면 사용자가 개선을 봅니다.
핫스팟은 시간이 많이 소비되는 곳(예: 프로파일에 자주 나타나는 함수)입니다. 핫스팟은 실제 병목일 수도 있고 단지 느린 경로에 영향을 주지 않는 바쁜 작업일 수도 있습니다.
노이즈는 의미 있어 보이지만 실제로는 그렇지 않은 모든 것: 백그라운드 잡, 일회성 스파이크, 샘플링 아티팩트, 캐싱 효과, 사용자-visible 문제와 상관없는 "top talkers" 등.
먼저 깨끗한 전(before) 스냅샷을 캡처하세요: 사용자-대면 증상(지연 또는 오류율)과 주요 후보 신호(CPU 포화, 큐 깊이, 디스크 I/O, 락 경쟁 등). 그런 다음 의심 원인만 영향을 줄 통제된 변경을 적용하세요.
인과 관계 테스트 예시:
상관관계는 힌트일 뿐 결론이 아닙니다. "지연이 올라갈 때 CPU도 올라간다"면, CPU 가용성을 변경하거나 CPU 작업을 줄여 지연이 따라오는지 확인하세요.
무엇을 측정했고, 정확히 어떤 변경을 했으며, 전/후 결과와 관찰된 개선을 적어두세요. 이는 일회성 성공을 재사용 가능한 플레이북으로 바꾸고 나중에 "직감"이 역사를 덮어쓰는 것을 막습니다.
성능 사고는 긴박하게 느껴지므로 추측이 끼어들기 쉽습니다. 경량의 반복 가능한 워크플로우는 "뭔가 느리다"에서 "무엇이 바뀌었는지 안다"로 이동하는 데 도움이 됩니다.
감지: CPU가 아니라 사용자-대면 지연과 오류율로 알람을 설정하세요. p95/p99 지연이 일정 시간 지속되면 페이지를 보냅니다.
분류: 즉시 세 가지 질문에 답하세요: 무엇이 느린가, 언제 시작되었는가, 누가 영향을 받는가? 범위(서비스, 엔드포인트, 리전, 코호트)를 말할 수 없다면 최적화할 준비가 안 된 것입니다.
측정: 병목을 좁히는 증거를 수집하세요. 비교를 쉽게 하기 위해 시간 제한 캡처(예: 60–180초)를 선호하세요.
수정: 한 번에 한 가지 변경만 하고 동일한 신호를 다시 측정해 개선을 확인하고 플라시보를 배제하세요.
사고 중에 모두가 사용하는 공유 대시보드를 유지하세요. 지루하고 일관되게 만드세요:
목표는 모든 것을 그리는 것이 아니라 첫 사실(First-Fact)을 얻는 시간을 줄이는 것입니다.
가장 중요한 엔드포인트(체크아웃, 로그인, 검색)에 계측을 집중하세요. 각 엔드포인트에 대해 기대되는 p95, 최대 오류율, 주요 의존성(DB, 캐시, 서드파티)을 합의하세요.
다음 장애가 발생하기 전에 캡처 킷을 합의하세요:
이를 /runbooks/latency 같은 짧은 런북에 문서화하고 누가 캡처를 실행할 수 있는지와 아티팩트가 어디에 저장되는지 포함하세요.
그렉의 방법론은 본질적으로 통제된 변경과 빠른 검증에 관한 것입니다. 팀이 Koder.ai(웹·백엔드·모바일 앱을 생성하고 반복하는 챗 중심 플랫폼)를 사용해 서비스를 구축한다면, 두 가지 기능이 그 사고방식에 잘 맞습니다:
사고 중에 새 코드를 생성하지 않더라도, 작은 차이, 측정 가능한 결과, 빠른 되돌리기라는 습관은 그렉이 권장하는 습관과 같습니다.
오전 10:15, 대시보드에서 API의 p99 지연이 피크에서 약 120ms에서 900ms로 상승했습니다. 오류율은 평탄하지만 고객이 "느리다"고 보고합니다.
서비스 우선으로 시작하세요: Rate, Errors, Duration.
Duration을 엔드포인트별로 분해하면 하나의 경로가 p99를 지배하는 것을 봅니다: POST /checkout. 처리량은 2×로 증가했고 오류는 정상, 그러나 동시성이 증가할 때 특히 Duration이 급증합니다. 이는 큐잉 또는 경쟁을 가리키며 전반적 실패는 아닙니다.
다음으로 지연이 계산 시간인지 대기 시간인지 확인하세요: 애플리케이션의 "핸들러 시간" vs 전체 요청 시간(스팬이 있다면 업스트림 vs 다운스트림). 핸들러 시간은 낮고 전체 시간이 높았습니다—요청이 기다리고 있습니다.
가능성 있는 병목을 목록화하세요: CPU, 메모리, 디스크, 네트워크의 활용률, 포화, 오류.
CPU 활용률은 약 35%였지만 CPU 런 큐와 컨텍스트 스위치가 증가했습니다. 디스크와 네트워크는 안정적입니다. 이 불일치(낮은 CPU%, 높은 대기)는 스레드가 CPU를 태우고 있지 않고 블록되고 있다는 고전적 힌트입니다.
스파이크 동안 off-CPU 프로파일을 캡처하니 공유된 "프로모션 검증" 캐시 주변의 뮤텍스에서 많은 시간이 소비되는 것이 드러났습니다.
전역 락을 키별 락 또는 락-프리 읽기 경로로 교체하고 배포하니 p99가 기준선으로 돌아왔고 처리량은 높은 상태를 유지했습니다.
사후 점검 목록: