5-3. 요청 단위 원인 조사¶
이번 페이지의 업무는 대시보드에서 함께 변한 신호를 실제 요청의 처리 경로와 연결해, 무엇을 더 측정해야 하는지 보고할 수 있게 만드는 것입니다. QA 담당자는 운영 회의 전에 current-shift에서 high_risk 예측 비율이나 지연이 커진 이유를 설명해야 하지만, 그 사실만으로 모델 결함을 선언하지 않고 같은 범위의 요청·로그·trace를 따라가며 원인 후보를 좁힙니다.
조사 범위는 앞에서 고정한 동일한 모델 정보, 시나리오, 절대 UTC 시간 범위를 그대로 이어받습니다. 입력 분포 비교에서 확인한 변화와 점수·예측 분포 비교의 요약값을 출발점으로 삼고, 관측 실습의 요청 단위 조사에서 제공한 실시간 또는 준비된 오프라인 자료의 범위 밖으로 임의로 넓히지 않습니다.
이 페이지의 산출물은 대표 요청의 선택 이유, request_id와 로그·trace의 연결 결과, 처리 단계별 시간, 경쟁하는 설명, 아직 확인하지 못한 추가 측정을 한 묶음으로 남기는 것입니다. 대표 요청 한 건은 전체 추세의 증명이 아니므로, 조사 결과는 원인을 확정하는 문장보다 근거의 범위와 다음 확인 조건을 분명히 하는 문장으로 작성합니다.
세 시나리오가 각각 답하는 질문¶
세 시나리오는 같은 관측 묶음 안에 있어도 서로 다른 질문에 답하므로 먼저 분석 목적과 예상 HTTP 상태를 분리합니다. baseline은 비교의 출발점이고, current-shift는 입력 조건이 달라졌을 때 출력과 지연이 어떻게 달라지는지 보는 대상이며, invalid는 입력 계약을 지키지 않은 요청이 API에서 어떻게 거부되는지 확인하는 대상입니다.
준비된 관측 자료의 표본 구성과 예상 결과는 다음과 같이 기록합니다. baseline과 current-shift는 각각 60건의 정상 처리 요청이고, invalid는 3건의 입력 검증 실패 요청이므로 행 수와 상태 코드만 보아도 같은 계산에 넣을 자료가 아님을 확인할 수 있습니다.
| 시나리오 | 표본과 입력 목적 | 예상 HTTP 상태 | 점수·예측 분포에 포함하는가 | 이 시나리오가 답하는 질문 |
|---|---|---|---|---|
baseline |
기준 입력 60건 | 200 | 포함. 비교의 출발점 | 기준 조건에서 지연과 출력은 어느 수준인가 |
current-shift |
변화 입력 60건 | 200 | 포함. 기준과 같은 모델·임계값으로 비교 | 입력 조건 변화와 출력·지연 변화가 함께 나타나는가 |
invalid |
입력 계약을 위반한 3건 | 422 | 제외. 점수가 생성되지 않은 검증 결과 | 모델 실행 전에 어떤 입력 오류가 거부되는가 |
이 구분은 422와 5xx를 같은 실패로 세지 않게 해 줍니다. invalid의 422는 입력 검증 결과이며 서비스 내부 실패를 뜻하지 않고, 모델 점수나 high_risk 비율의 분모에도 넣지 않습니다. 반대로 baseline과 current-shift의 200 응답은 점수와 최종 예측을 비교할 수 있는 요청입니다.
시나리오를 나눈 뒤에는 각 질문에 맞는 관측값만 보고서에 옮깁니다. 초기 표본이나 다른 시간대의 숫자를 이 15분 범위의 직접 증감으로 이어 쓰지 않으며, invalid가 정상 요청보다 빠르거나 느리다는 사실도 모델 성능 변화로 해석하지 않습니다. 이렇게 범위를 먼저 고정해야 이후 대표 요청을 고를 때 선택 기준이 흔들리지 않습니다.
같은 범위의 전체 추세 비교¶
전체 추세 비교의 핵심은 세 시나리오를 동일한 15분 UTC 범위와 동일한 모델 정보 안에서 가로로 읽는 것입니다. 요청 수와 상태 코드, 지연 P95, 점수 P95, 결측 특성 수 P95, high_risk 예측 비율을 함께 보면 어느 신호가 같이 달라졌는지와 어떤 요청을 더 조사할지 정할 수 있습니다.
준비된 오프라인 관측 자료의 집계값은 다음과 같습니다. 이 수치는 실시간 운영 성공을 재현한 값이 아니라 고정된 분석 절차를 연습하기 위한 자료이므로, 표의 범위를 넘어 대상 환경의 발생량이나 원인을 주장하지 않습니다.
| 시나리오 | 요청 수 | 상태 코드 구성 | 지연 P95 | 점수 P95 | 결측 특성 수 P95 | high_risk 예측 |
|---|---|---|---|---|---|---|
baseline |
60 | 200: 60, 422: 0, 5xx: 0 | 55ms | 0.40 | 0.5 | 4건, 6.67% |
current-shift |
60 | 200: 60, 422: 0, 5xx: 0 | 640ms | 0.56 | 2.0 | 11건, 18.33% |
invalid |
3 | 200: 0, 422: 3, 5xx: 0 | 30ms | 해당 없음 | 1.0 | 0건, 0% |
표에서 current-shift는 기준보다 지연 P95, 점수 P95, 결측 특성 수 P95, high_risk 비율이 모두 높아졌으므로 입력 조건과 처리 경로를 함께 조사할 근거가 커집니다. 그러나 이 동행만으로 모델 성능 저하나 단일 원인을 확정하지 않습니다. invalid의 점수 P95가 비어 있는 것은 계산 누락이 아니라 점수 생성 전에 422로 거부되었기 때문입니다.
이 단계의 보고서 행에는 “같은 15분 범위에서 current-shift의 60건 중 11건이 high_risk로 분류되었고 지연 P95는 640ms였으며, baseline의 4건·55ms와 달랐다”처럼 직접 읽은 사실을 적습니다. 이어서 입력 조건 변화, 결측 처리, 처리 경로 지연을 원인 후보로 열어 두고, 정답이 없는 운영 요청에서 재현율·정밀도 같은 모델 성능 지표를 새로 계산하지 않았다는 한계를 함께 남깁니다.
시간축에서 조사 구간 고르기¶
평균이나 전체 P95는 순간적인 이상이 언제 생겼는지 숨길 수 있으므로, 같은 UTC 시간축의 시계열 점을 읽어 조사 구간을 고릅니다. 각 점은 해당 시각에 수집된 요약 구간을 뜻하며 점과 점 사이를 측정된 연속 곡선으로 보지 않아야 합니다.
준비된 자료의 시계열은 다음처럼 읽습니다. current-shift의 06:08 UTC 점에서 지연 P95가 960ms로 높아지고 점수 P95와 결측 특성 수 P95도 함께 높아지므로, 이 시각을 대표 요청을 찾을 조사 시작점으로 삼을 수 있습니다.
| UTC 시각 | 시나리오 | 요청 수 | 지연 P95 | 점수 P95 | 결측 특성 수 P95 | high_risk 비율 |
조사 의미 |
|---|---|---|---|---|---|---|---|
| 06:01 | baseline |
20 | 42ms | 0.37 | 0.0 | 5% | 기준 구간 |
| 06:03 | baseline |
20 | 45ms | 0.38 | 0.0 | 5% | 기준 구간 |
| 06:05 | baseline |
20 | 58ms | 0.42 | 1.0 | 10% | 기준의 마지막 변화 |
| 06:06 | current-shift |
20 | 120ms | 0.52 | 1.0 | 15% | 변화 조건 시작 |
| 06:08 | current-shift |
20 | 960ms | 0.58 | 2.0 | 20% | 느린 요청을 찾을 우선 구간 |
| 06:10 | current-shift |
20 | 220ms | 0.55 | 2.0 | 20% | 이상 뒤의 회복 구간 |
| 06:12 | invalid |
3 | 30ms | 해당 없음 | 1.0 | 0% | 입력 검증 결과 구간 |
06:08이라는 점은 “그 시각에 관측 신호가 가장 크게 달랐다”는 뜻이지 “06:08의 한 원인이 확정됐다”는 뜻이 아닙니다. 앞뒤 시점의 current-shift 요청과 baseline의 같은 위치를 같이 확인해 일시적인 지연인지, 변화 조건 전체에 지속되는 지연인지 구분하고, 선택한 구간과 선택하지 않은 구간의 차이를 기록합니다.
시간축에서 고른 구간은 대표 요청의 선택 조건으로만 사용합니다. 보고서에는 절대 UTC 시작·종료, 시나리오, 그 구간의 표본 수, 변화한 지표를 적고, 자료가 준비된 오프라인 범위라면 고정된 시나리오 시각임을 명시합니다. 이 기록이 있어야 요청 하나의 trace를 전체 추세의 어느 점과 연결했는지 나중에 다시 확인할 수 있습니다.
조사 질문에 맞는 대표 요청 선택¶
대표 요청은 전체 현상을 대신할 한 건이 아니라 특정 조사 질문을 시작할 한 건이므로, 가장 눈에 띄는 고위험 요청을 무조건 고르지 않습니다. 지연 구간을 조사할 때는 current-shift의 HTTP 200 가운데 500ms를 넘은 요청을, 입력 계약을 조사할 때는 invalid의 422 요청을, 정상 경로의 기준을 확인할 때는 baseline의 200 요청을 고릅니다.
준비된 자료에서 사용할 수 있는 대표 사례와 선택 이유는 다음과 같습니다. 표시된 request_id는 로그와 trace를 연결하기 위한 예시 식별값이며 인증 정보가 아니므로, 실시간 자료를 사용할 때는 실제 조회 범위 안에서 확인한 값을 기록합니다.
| 조사 사례 | 시나리오와 선택 이유 | request_id 예시 |
HTTP·처리 시간 | 출력 또는 오류 |
|---|---|---|---|---|
normal |
baseline의 정상 경로 기준 |
<BASELINE_REQUEST_ID> |
200, 44ms | score=0.31, prediction=low_risk |
slow |
current-shift에서 500ms를 넘은 지연 경로 |
<SLOW_REQUEST_ID> |
200, 920ms | score=0.61, prediction=high_risk |
invalid_422 |
invalid의 제한된 입력 검증 오류 |
<INVALID_REQUEST_ID> |
422, 31ms | error_code=MODEL_INPUT_INVALID, validation_category=missing |
표의 slow 사례는 06:08의 지연을 구체적으로 확인하는 시작점이고, normal 사례는 같은 방식으로 처리된 기준 경로를 비교할 때 유용합니다. invalid_422는 모델 점수와 처리 지연의 원인을 설명하는 사례가 아니라 입력 검증이 모델 실행 전에 종료되었는지 확인하는 별도 사례이므로 두 정상 시나리오의 분포와 섞지 않습니다.
대표 요청을 고른 뒤에는 선택 이유와 한계를 함께 기록합니다. 선택한 한 건이 집계값과 다른 결과를 보이면 요청을 임의로 바꾸어 기대값에 맞추지 말고, 같은 시나리오·시간 범위에 속하는지와 로그·trace 연결 가능성을 먼저 확인합니다. 연결 가능한 사례가 하나뿐이라는 사실도 표본의 한계로 남겨야 전체 추세에 대한 과도한 일반화를 막을 수 있습니다.
request_id로 로그 연결하기¶
request_id는 대시보드의 한 점을 특정 요청의 상태와 모델 정보로 좁혀 주는 연결값입니다. 로그를 찾을 때는 request_id만 보지 말고 동일한 environment, run_id, 시나리오, 절대 UTC 범위, 상태 코드, 모델 프로필·버전을 함께 대조해야 다른 실행의 요청을 잘못 연결하지 않습니다.
로그에서 먼저 확인할 필드와 그 필드가 답하는 질문은 다음과 같습니다.
| 로그 필드 | 확인할 값 | 조사 질문 |
|---|---|---|
request_id |
선택한 요청의 식별값 | 이 로그가 조사하려는 바로 그 요청인가 |
run_id, scenario |
실행 묶음과 baseline·current-shift·invalid |
같은 시나리오와 실행에 속하는가 |
status_code, error_code, validation_category |
200, 422, 5xx와 제한된 검증 분류 | 입력 거부와 서비스 실패를 구분할 수 있는가 |
model_profile, model_version |
응답과 로그에 기록된 실행 모델 | 기대한 모델 정보와 일치하는가 |
trace_id, span_id, duration_ms |
처리 경로로 넘어갈 연결값과 요청 시간 | 같은 요청의 trace를 열 수 있는가 |
실시간 경로에서는 동일한 절대 UTC 범위와 실제 환경·실행 값을 넣어 다음처럼 로그를 좁힙니다. request_id는 요청별 지표 레이블로 계속 쌓는 값이 아니라, 로그와 trace를 찾을 때 사용하는 상관값이므로 집계 지표의 분류 항목으로 만들지 않습니다.
{service_name="risk-api", environment="<ENVIRONMENT>"}
| json
| run_id="<RUN_ID>"
| request_id="<REQUEST_ID>"
조회한 로그의 trace_id와 상태·모델·처리 시간을 대표 요청 표에 옮기고, 값이 빠졌거나 서로 다르면 연결 실패를 관측 공백으로 기록합니다. 시간 범위를 무작정 넓혀 다른 실행의 로그를 섞지 않으며, 준비된 오프라인 자료를 사용할 때는 제공된 representative_requests의 제한된 로그 필드만 확인하고 원본 입력이나 확인하지 않은 운영 상태를 만들어 쓰지 않습니다.
처리 경로에서 지연 구간 좁히기¶
trace는 지연이 발생한 처리 단계를 좁혀 주지만, 가장 긴 span의 이름만으로 그 단계가 단일 원인이라고 말해 주지는 않습니다. 동일한 trace_id의 부모·자식 관계를 먼저 확인한 뒤 전체 요청 시간과 API, 내부 계산 span의 시간을 같은 단위로 비교해야 합니다.
느린 대표 요청의 정본 처리 경로는 다음과 같습니다. 전체 요청은 traffic.generate에서 924ms였고, 호출 측 risk-api.predict CLIENT span은 922ms, Risk API의 POST /v1/predict SERVER span은 API 처리 920ms, 그 안의 risk.predict 계산 span은 861ms였습니다.
traffic.generate (전체 924ms)
└─ risk-api.predict (CLIENT 922ms)
└─ POST /v1/predict (API SERVER 920ms)
└─ risk.predict (계산 861ms)
| 처리 단계 | span 종류 | 시간 | 이 값으로 좁힐 수 있는 범위 |
|---|---|---|---|
traffic.generate |
호출 전체 | 924ms | 요청 전체에서 관측된 종료까지의 시간 |
risk-api.predict |
CLIENT | 922ms | 호출 측에서 API 왕복을 기다린 시간 |
POST /v1/predict |
SERVER | 920ms | Risk API가 요청을 처리한 시간 |
risk.predict |
내부 계산 | 861ms | API 처리 안에서 계산 span으로 계측된 구간 |
API 920ms와 내부 계산 861ms의 차이인 약 59ms에는 전처리, 입력 정리, 직렬화, 대기처럼 아직 세분화되지 않은 시간이 포함될 수 있습니다. 전체 924ms와 API 920ms의 약 4ms 차이도 호출 측·네트워크·기록 오버헤드의 후보로 남으므로, 861ms를 보는 즉시 모델 계산이 유일한 원인이라고 확정하지 않습니다.
보고서에는 “같은 trace_id에서 POST /v1/predict 920ms와 risk.predict 861ms를 확인했고, 전체 요청은 924ms였다”처럼 직접 본 구간을 적습니다. 이어서 계산 내부의 하위 단계, API와 predictor 사이 대기, 직렬화 시간을 분리해 측정해야 한다는 다음 확인 조건을 남기며, 처리 경로에서 위치를 좁힌 사실과 원인을 확인한 사실을 서로 다른 문장으로 씁니다.
여러 설명을 관측값과 비교하기¶
하나의 관측값에는 여러 설명이 가능하므로, 원인 후보마다 현재 자료가 지지하는 부분과 아직 필요한 측정을 나란히 적습니다. 예를 들어 결측 특성 수 P95가 2.0으로 높아진 것, risk.predict가 861ms인 것, API와 전체 요청 시간이 서로 다른 것은 각각 관련 후보를 열지만 어느 하나를 단독 원인으로 확정하지 않습니다.
다음 표는 느린 current-shift 요청을 설명할 때 경쟁시킬 후보의 예입니다. “조사 우선순위가 높아졌다”는 판단과 “원인이 확인됐다”는 판단을 분리해 읽습니다.
| 관측값 | 가능한 설명 | 현재 자료로 말할 수 있는 것 | 원인 확인에 필요한 추가 자료 |
|---|---|---|---|
| 결측 특성 수 P95 2.0과 지연 P95 960ms가 같은 구간에 나타남 | 결측 처리나 입력 정리 비용 증가 | 결측 처리 경로를 함께 조사할 근거가 커짐 | 결측 개수별 전처리 시간과 동일 입력의 비교 재실행 |
risk.predict 내부 계산 span 861ms |
모델 계산 또는 계산 전후의 내부 처리 | API 지연 안에서 긴 계측 구간의 위치를 확인함 | 계산 하위 span, 모델 실행 시간, 대기 시간의 분리 계측 |
| 전체 924ms, CLIENT 922ms, API SERVER 920ms | 네트워크 왕복·대기·직렬화·기록 오버헤드 | API 안팎에 계측되지 않은 시간이 남아 있음 | 호출 측·서버 측 timestamp와 큐·네트워크·직렬화 시간 |
점수 P95 0.56과 high_risk 18.33% |
입력 조건 또는 임계값 근처 사례의 구성 변화 | 출력 분포가 기준과 달라진 사실을 확인함 | 같은 입력 조건·모델·임계값의 통제 재실행과 정답 자료 |
표의 각 행은 같은 사건을 서로 다른 각도에서 설명할 수 있음을 보여 줍니다. 결측 처리 후보가 조사 우선순위가 높아져도 내부 계산이나 네트워크 대기 후보가 자동으로 제외되지 않으며, 출력 분포의 변화도 지연 원인과 동일하다고 가정하지 않습니다. 후보를 강화, 약화, 유지로 표시할 때는 반드시 표의 관측값과 다음 자료를 함께 적습니다.
이 비교가 끝나면 보고서의 “원인 후보” 열에는 후보별 현재 상태와 남은 반증 가능성을 기록합니다. 대상 환경이나 세부 계측을 확인하지 못한 후보는 억지로 제외하지 않고 유지로 남기며, 한 대표 요청에서 보이지 않은 경로를 정상이라고 추정하지 않습니다. 이렇게 해야 다음 측정 담당자가 무엇을 수집해야 하는지 바로 이어받을 수 있습니다.
상관과 원인을 구분해 확인하기¶
상관관계는 두 신호가 같은 범위에서 함께 움직였다는 관찰이고, 원인 확인은 한 요인을 통제하거나 추가 측정해 다른 설명을 줄이는 과정입니다. current-shift의 점수·예측·지연·결측 신호가 함께 높아졌다는 사실은 조사 방향을 정하지만, 운영 요청에 정답이 없다는 조건에서는 모델 성능 저하나 단일 원인을 증명하지 않습니다.
관찰에서 허용되는 주장과 원인 주장을 위해 필요한 확인은 다음처럼 나눕니다.
| 함께 관찰된 신호 | 지금 쓸 수 있는 상관 관찰 | 원인이라고 쓰기 전에 필요한 확인 |
|---|---|---|
current-shift의 점수 P95 0.56, high_risk 18.33%, 결측 P95 2.0 |
변화 입력 구간에서 입력·출력·결측 요약이 기준과 함께 달라짐 | 같은 모델·임계값에서 입력 조건만 통제한 재실행과 정답 기반 평가 |
| 06:08 UTC의 지연 P95 960ms와 결측 P95 2.0 | 해당 시점에 지연과 결측 신호가 동행함 | 결측 수준을 고정·변경한 비교와 전처리 시간 계측 |
| API 920ms, 계산 861ms, 전체 924ms | 지연 위치가 risk.predict 주변으로 좁혀짐 |
계산·대기·네트워크·직렬화 하위 시간을 분리 측정 |
invalid의 422와 점수 없음 |
입력 검증에서 모델 실행 전 종료된 요청이 존재함 | 의도한 입력 계약 위반과 오류 분류가 일치하는지 검증 |
통제된 재실행은 한 번에 하나의 조건만 바꾸고 나머지 모델·임계값·경로·시간 범위를 고정해야 해석할 수 있습니다. 재실행이 불가능한 운영 범위라면 호출 측과 서버 측 timestamp, 전처리와 계산의 세부 span, 입력 검증 결과처럼 현재 자료에 없는 추가 측정을 요청하고, 그 자료가 오기 전까지는 후보 상태를 유지합니다.
최종 기록에는 다음처럼 관찰과 한계를 한 문장에 함께 남깁니다.
같은 15분 UTC 범위에서
current-shift의 점수 P95·high_risk비율·지연 P95·결측 P95가baseline과 함께 달라졌고, 대표request_id의 trace에서 API 920ms·내부 계산 861ms·전체 924ms를 확인했습니다. 이 결과는 입력 조건·결측 처리·계산·네트워크 대기를 조사할 단서이지만, 대표 요청과 관측 자료만으로 단일 원인은 확정하지 않으며 통제 재실행 또는 추가 계측 결과로 판단을 갱신합니다.