누적 손실률이 통화가 끊긴 순간을 가리는 이유

통화는 뚝뚝 끊기는데 손실률은 1%도 안 된다고 하자. 숫자만 보면 꽤 평온하다. 귀로 들은 통화와 숫자가 딴소리를 하는 셈이다.

그렇다고 계산이 틀렸다고 단정할 수는 없다. 끊긴 순간의 손실을 통화 전체에 나눠 놓았을 수 있기 때문이다. 작은 계산 예시와 VoiceLink의 품질 수집 코드를 같이 보면 차이가 드러난다.

열 개를 잃었는데 0.91%와 10%가 된다

다음은 실제 통화 측정값이 아닌 설명용 예시다. 앞 구간에는 패킷 천 개가 모두 도착했고, 뒤의 짧은 구간에서는 백 개 중 열 개를 잃었다고 하자.

관찰 구간 받은 패킷 잃은 패킷 손실률
앞선 정상 구간 1,000 0 0%
문제가 생긴 짧은 구간 90 10 10%
두 구간을 합친 누적 1,090 10 약 0.91%

전체로 보면 10 ÷ 1,100 ≈ 0.91%, 뒤 구간만 보면 10 ÷ 100 = 10%다. 잃은 열 개는 그대로인데, 앞서 잘 도착한 천 개가 분모에 함께 들어가면서 비율이 작아졌다.

누적값은 틀린 숫자가 아니다. 다만 “지금 끊긴 구간이 얼마나 나빴나”에 답하기에는 이전의 정상 구간이 너무 많이 섞여 있다.

5초마다 보내면 최근 5초의 값일까

VoiceLink의 CallQualityMonitor는 기본 5초마다 표본을 만든다. 수신 통계 이벤트에서 받은 packetsLost와 packetsReceived를 보관하고, 손실률은 아래처럼 계산한다. 실제 함수에서 필드 이름만 줄여 표현한 계산식이다.

lost = 수신 통계의 packetsLost
received = 수신 통계의 packetsReceived
둘 중 하나가 없거나 lost + received <= 0이면 미측정
그 외에는 lost / (lost + received)

이전 표본을 빼는 처리는 없다. 누적 카운터를 넣으면 5초마다 누적 비율을 다시 계산할 뿐이다. 자주 꺼내 본다고 숫자의 시작점까지 최근으로 옮겨지지는 않는다.

위 예시에서 최근 구간만 보려면, 앞 구간 끝과 뒤 구간 끝의 두 표본을 비교하면 된다. 같은 수신 스트림의 카운터가 이어졌다는 조건에서 계산한 증가분이다.

잃은 패킷 증가분 = 10 - 0 = 10
받은 패킷 증가분 = 1,090 - 1,000 = 90
구간 손실률 = 10 / (10 + 90) = 10%

이 계산은 구간 분석을 위한 제안이며 현재 구현된 기능은 아니다. 누적 비율을 없애기보다는 전체 상태를 볼 때 쓰고, 끊긴 시점을 좁힐 때 증가분을 나란히 보면 각각 다른 질문에 답할 수 있다.

두 숫자를 빼기 전에 맞춰야 할 것

먼저 같은 사람이 받은 패킷끼리 비교해야 한다. 서버 타임라인에는 두 참가자의 표본이 함께 들어가므로 submittedByUserId로 나눠야 한다. 보내는 쪽과 받는 쪽을 섞으면 앞의 계산부터 의미가 달라진다.

시각도 필요하다. capturedAtEpochMillis는 앱이 표본을 만든 시각이고, 그 안의 패킷 수는 마지막 수신 통계 이벤트에서 받은 값이다. 원본 통계의 측정 시각을 따로 담지는 않는다. 따라서 표본 두 개가 5초 간격이라고 해서 패킷 통계도 정확히 그 5초를 나타낸다고 단정할 수 없다. 구간 분석을 구현한다면 원본 통계의 시각과 같은 스트림인지 식별할 정보도 함께 남기는 편이 맞다.

재연결 뒤 통계 대상이 바뀌거나 카운터가 초기화됐다면 이전 값과 이어서 빼면 안 된다. 새 기준 표본을 잡고 다음 값을 기다려야 한다. 손실 카운터는 추정 방식상 음수도 가능하므로, 감소를 무조건 초기화로 해석해서는 안 된다. W3C의 통계 정의에 따라 같은 대상을 비교하는지부터 확인해야 한다.

값이 없을 때는 계산을 쉬어야 한다. 모니터는 필요한 카운터가 없으면 손실률을 null로 두고, 수신 통계 자체가 없으면 품질을 POOR로 분류한다. 이 경고는 손실을 실제로 관측했다는 뜻이 아니다. 앞뒤 표본이 없거나 비교할 패킷 증가분이 없다면 0%로 채우지 말고 미측정으로 남겨야 한다.

누적 0.91%가 짧은 구간의 10%를 지운 것은 아니다. 앞서 잘 도착한 패킷까지 함께 셌기 때문에 작게 보인 것이다. 끊긴 순간을 설명하려면 수집 횟수보다, 그 비율이 언제부터 언제까지를 세고 있는지가 먼저다.

근거와 범위

VoiceLink 37109d5의 CallQualityMonitor, 모니터 테스트, CallQualityService·응답 DTO·저장 테스트, application.yml, docs/matching-call-lifecycle.md를 대조했다. 2026년 10월 12일 Linux·Flutter 3.38.3에서 품질 모니터 테스트 10개가 통과했다. 수신 손실률 계산, 송신 통계와의 분리, 수신 통계가 없는 경우의 분류 등이 검사 대상이다. 실제 통화 실험은 하지 않았다. 0.91%와 10%는 설명용 계산이고 실제 음질 장애의 측정값은 아니다.

Leave a Comment