Devin.KR

측정 결과 집계

90분 안팎

학습 목표

제공된 시간대별 측정값에서 지연·손실·연결 실패 횟수를 집계합니다.

개념

평균이 좋아도 장애는 남습니다

학교 웹이 수업 시작 때 세 번 끊겼는데 하루 평균 응답 시간이 짧다고 보고하면 사용자의 문제를 놓칩니다. 실패한 요청은 응답 시간을 얻지 못해 목록에서 빠지는 경우가 많습니다. 이번 레슨은 제공된 시간대별 측정값을 집계하면서 무엇을 분모에 넣고 무엇을 제외했는지 설명하는 작업입니다. 숫자를 계산하기 전에 학생 웹이라는 대상과 출발지, 측정 구간, 실패 정의를 정합니다. 성공 지연과 실패 횟수를 함께 전달해야 다음 담당자가 느린 서비스와 연결되지 않는 서비스를 구분할 수 있습니다.

실습 환경과 자료의 성격

이 모듈의 브라우저 계산은 Python 표준 입력을 사용합니다. 실제 링크와 nftables를 다루는 단계는 앞에서 준비한 Linux VM의 소유 네임스페이스에서만 실행합니다. 맥에서는 파일과 순수 Python 테스트를 확인하며 실제망 단계는 external 대기로 남깁니다. 관측하지 않은 명령 결과는 따라하기 output에 채우지 않습니다. 각 압축 파일은 별도 빈 폴더에서 풉니다. 앞 모듈 파일을 덮어쓰지 않으며 이번 미션에는 m08 solution 사본과 추가 파일이 함께 들어 있습니다.

입력 한 행의 계약

브라우저 과제의 첫 줄은 행 수 N입니다. 뒤의 N줄에는 밀리초 지연, 보낸 ICMP 표본 수, 받은 표본 수, TCP 실패 표식이 공백으로 구분되어 들어갑니다. 지연 -1은 측정 불가이며 실제 0밀리초와 다릅니다. 실패 표식은 0 또는 1입니다. 수신 수는 송신 수 이하이며 음수 패킷 수는 입력하지 않습니다. 집계는 시간 순서에 영향을 받지 않지만 연속 실패 판정은 순서가 필요하므로 여기서는 총횟수만 계산합니다. 정해진 형식 밖 자료는 먼저 수집 단계에서 검토합니다.

손실률의 분모를 지킵니다

손실률은 전체 송신 수에서 전체 수신 수를 뺀 값에 100을 곱하고 전체 송신 수로 나눈 값입니다. 시간대별 손실률을 단순 평균하면 송신 수가 다른 행의 무게가 같아집니다. 한 행이 1개를 보내고 다른 행이 100개를 보냈다면 두 행의 비중은 같지 않습니다. 먼저 패킷 수를 합산한 뒤 나눕니다. 송신 합계가 0이면 측정한 표본이 없으므로 NA를 출력합니다. 수집 누락을 0퍼센트 정상으로 바꾸지 않는 것이 이 계산의 핵심입니다.

지연의 결측을 분리합니다

유효 지연은 0 이상인 값만 모읍니다. 이 목록의 평균과 최댓값을 출력하며 목록이 비면 둘 다 NA입니다. -1을 평균에 넣으면 연결이 끊길수록 평균이 낮아지는 이상한 결과가 나옵니다. 반대로 지연이 없는 행을 완전히 버리면 실패 횟수와 패킷 수가 사라집니다. 지연 계산에서만 제외하고 다른 집계는 그대로 수행합니다. 표본은 교육용 제공 자료입니다. 계산을 실행했다는 사실과 학교망에서 그 지연을 직접 측정했다는 주장은 구분해서 기록합니다.

연결 실패는 별도 합계입니다

TCP 실패 표식의 합을 마지막 항목으로 출력합니다. ICMP 표본 손실과 TCP 연결 실패는 서로 다른 관측이므로 한 숫자로 합치지 않습니다. ping 응답이 없어도 방화벽 정책에 따라 웹은 성공할 수 있습니다. TCP 연결이 성공해도 HTTP 503은 사용자 업무에 실패일 수 있습니다. 이번 입력은 HTTP 상태를 포함하지 않으므로 웹 가용성 전체를 계산했다고 쓰지 않습니다. 다음 레슨에서 DNS와 HTTP 결과를 함께 수집하여 이 관측 범위를 넓힙니다.

출력 순서와 소수 표현

출력은 평균 지연, 최대 지연, 패킷 손실률, TCP 실패 횟수 순서입니다. 앞의 세 수치가 존재하면 소수 첫째 자리까지 표현하고 실패 횟수는 정수로 적습니다. 0과 0.0은 의미가 같아도 제출 형식은 정해진 계약을 따릅니다. 평균에는 sum과 len을 사용할 수 있으며 표시에는 f-string의 .1f를 사용합니다. 계산 중간값을 먼저 반올림하지 말고 최종 표시 시점에 반올림합니다. 입력의 작은 오차를 여러 번 누적해서 해석하는 실수를 줄일 수 있습니다.

빈 시간대를 시험합니다

N이 0인 경우 유효 지연도 패킷 표본도 실패도 없습니다. 평균·최대·손실은 NA이고 실패 횟수는 0입니다. 이것은 서비스가 정상이라는 뜻이 아니라 계산할 자료가 없다는 뜻입니다. 모든 지연이 -1이지만 ICMP 표본은 있는 경우에는 지연 두 항목만 NA가 됩니다. 모든 패킷 수가 0이지만 지연 값이 있으면 지연을 출력하고 손실만 NA입니다. 결측의 이유를 항목별로 분리하면 한 지표가 비어 있어도 남은 근거를 보존할 수 있습니다.

오류 메시지에서 위치를 찾습니다

ValueError가 숫자 변환에서 나오면 입력에 NA 문자열이나 열 이름을 섞었는지 확인합니다. 이 과제의 입력 결측은 -1입니다. ZeroDivisionError는 빈 유효 지연 목록 또는 송신 합계 0을 검사하지 않은 흔적입니다. IndexError는 N과 실제 줄 수를 비교하지 않았거나 열 수가 달라졌을 가능성이 있습니다. 정상 계약의 입력부터 실행한 뒤 경계 입력을 추가합니다. 오류를 전부 잡아 0을 출력하면 계산 오류와 실제 정상값을 구분할 수 없어 원인을 숨기게 됩니다.

서로 다른 출발지를 합치지 않습니다

학생과 교직원, 게스트는 접근 정책이 다릅니다. 게스트의 학교 웹 실패는 m08에서 의도한 차단입니다. 그 실패를 학생 웹 가용성 분모에 넣으면 경보가 정책을 장애로 오인합니다. 실제 monitor.csv에서는 source를 보존하고 동일한 대상과 역할별로 묶습니다. 시간 창도 시작·끝을 함께 적습니다. 수업 시작 5분의 실패를 하루 전체 성공으로 희석하지 말고 해당 창의 표본 수와 비교합니다. 이번 단순 과제는 이미 같은 대상의 행을 제공한다고 가정합니다.

집계에서 진단으로 넘깁니다

집계 결과가 손실 증가를 보이면 인터페이스 누적 오류의 증가, 경로, 실제 웹 요청을 더 살펴볼 이유가 생깁니다. 손실 숫자만으로 케이블 불량이나 서버 과부하를 확정하지 않습니다. 평균이 낮고 최대가 높으면 시간대별 원자료를 다시 읽습니다. 결과 보고에는 입력 행 수, 유효 지연 개수, 송신 합계, 실패 정의를 함께 적습니다. 숫자를 계산하는 코드와 원인을 판단하는 문장을 분리해야 계산 결과를 고쳤을 때 기존 결론도 재검토할 수 있습니다.

완료 기준

제공된 여섯 경계 사례를 통과하고 서로 다른 송신 수의 행을 단순 평균하지 않는 이유를 설명하면 이 레슨의 목표를 수행한 것입니다. 수료 자료에는 입력 형식과 출력 순서, NA의 의미를 한 문단으로 남깁니다. 컨테이너 문법을 길게 다시 공부하려면 더 읽기의 Python 자료구조 장으로 이동합니다. 여기서는 목록을 수단으로 사용해 측정의 분모를 지키는 데 집중합니다. 이후 경보 조건은 실패 횟수 합계가 아니라 같은 출발지의 시간 순서로 계산한다는 차이를 기억합니다.

따라하기

입력 계약을 해석합니다

브라우저 과제의 가상 자료를 직접 입력합니다. 실제 학교망 측정값이 아닙니다. 지연 결측은 지연 목록에서만 제외합니다.

rows = [(10, 10, 10, 0), (20, 10, 8, 0), (-1, 10, 0, 1)]
valid = [r[0] for r in rows if r[0] >= 0]
print(valid)
print(sum(r[3] for r in rows))

실행 결과

[10, 20]
1

가중 손실을 계산합니다

송신 합계를 분모로 계산하고 소수 첫째 자리로 표시합니다.

sent = 1 + 99
received = 0 + 99
print(f"{100 * (sent - received) / sent:.1f}")

실행 결과

1.0

브라우저 제출을 실행합니다

아래 코드는 표준 입력 한 묶음을 집계합니다. 과제에 같은 형식으로 제출하고 빈 표본·결측·0 지연을 시험합니다.

import sys
lines=sys.stdin.read().splitlines()
n=int(lines[0])
rows=[list(map(int,line.split())) for line in lines[1:1+n]]
valid=[r[0] for r in rows if r[0]>=0]
sent=sum(r[1] for r in rows)
received=sum(r[2] for r in rows)
failed=sum(r[3] for r in rows)
avg=f"{sum(valid)/len(valid):.1f}" if valid else 'NA'
maximum=f"{max(valid):.1f}" if valid else 'NA'
loss=f"{100*(sent-received)/sent:.1f}" if sent else 'NA'
print(avg,maximum,loss,failed)

실행 결과

15.0 20.0 40.0 1

확인 문제

실습

첫 줄 N(0~1000), 뒤 N줄의 latency_ms sent received tcp_failed를 집계합니다. 지연은 -1 또는 0 이상 정수, 패킷은 0 ≤ received ≤ sent, 실패 표식은 0 또는 1입니다. 같은 대상·출발지 자료입니다. 유효 지연 평균·최대·합산 패킷 손실률·TCP 실패 횟수를 공백으로 출력합니다. 수치는 소수 첫째 자리, 결측은 NA, 실패 수는 정수입니다.

모범 답안
import sys
lines=sys.stdin.read().splitlines()
n=int(lines[0])
rows=[list(map(int,line.split())) for line in lines[1:1+n]]
valid=[r[0] for r in rows if r[0]>=0]
sent=sum(r[1] for r in rows)
received=sum(r[2] for r in rows)
failed=sum(r[3] for r in rows)
avg=f"{sum(valid)/len(valid):.1f}" if valid else 'NA'
maximum=f"{max(valid):.1f}" if valid else 'NA'
loss=f"{100*(sent-received)/sent:.1f}" if sent else 'NA'
print(avg,maximum,loss,failed)

더 읽기

면접 질문

  • ping이 실패해도 서비스가 정상일 수 있는 이유를 설명합니다.