프로필 사진
Jeongwoo Seo
  • Blog
  • Series
  • Tags
  • Portfolio
BLOG

a developer who never stops growing.

Contact
Email
Github
Subscribe

새 글을 구독해보세요

Explore
Blog
Series
Portfolio
Tags
Admin

© 2024 Seo Jeongwoo. All rights reserved.

프리뷰 | 네트워크 기반 동적 품질 조절 기능 개발 2편 Thumbnail

네트워크 보고서 저장 및 계산

프로필 사진
개발자 서정우
2025. 3. 31.11 min read
네트워크

이전 글에서는 네트워크 품질을 측정하기 위한 지표들에 대해서 공부한 글을 올렸었다. 이후 5초에 한번씩 피어 커넥션을 순회하며 네트워크 지표들을 측정했다. 이걸 평균내서 하나의 NetworkStat 객체로 만들어내는 것까지 했다.

프리뷰 | 네트워크 기반 동적 품질 조절 기능 개발 2편

오늘은 네트워크 스탯을 저장하고 이를 토대로 품질을 결정하는 훅들을 만들었다. 그리고 이를 시각적으로 확인할 수 있는 컴포넌트도 만들었다.

네트워크 모니터 컴포넌트네트워크 모니터 컴포넌트

최근 5회의 평균

네트워크 품질 프리셋을 결정짓는 방법은 전역 상태에 관리되는 네트워크 상태 스택의 최근 5회의 평균으로 계산하기로 결정했다. 이렇게 한 이유는 최근 한 번에 대해서 평균을 내게 될 경우 급격하게 프리셋이 변경될 가능성이 있기 때문이다. 만약 5초 간격으로 화질이 좋고 나쁘게 바뀔 경우 너무 불편할 것이라고 생각이 들었다.

품질 단계

품질 단계를 결정하는 코드는 아래와 같다. calculateAverageStats는 매개변수로 들어오는 count 값에 맞춰서 최근 N회의 스탯을 통계내는 함수이다. 해당 함수로 반환된 averageStats의 값을 기준으로 현재 currentNetworkQuality를 판단한다.

0점 부터 시작해서 네트워크 지표가 좋으면 점수를 부여하는 방식으로 계산했다. 대역폭은 좀 더 중요한 지표이기 때문에 대역폭에 좀 더 많은 점수를 주고, 그 외 지표의 점수를 계산하는 방식으로 했다.

  const getNetworkQuality = () => {
    const averageStats = calculateAverageStats(5);
    if (!averageStats) return null; 
    const { jitter, rtt, packetsLossRate, bandwidth } = averageStats;

    const bandwidthMbps = bandwidth / 1000 / 1000;
    const rttMs = rtt * 1000; // 초를 밀리초로 변환
    const packetLossPercent = packetsLossRate * 100;
    const jitterMs = jitter * 1000; // 초를 밀리초로 변환

    let qualityScore = 0;

    if (bandwidthMbps >= 2.5) qualityScore += 40;
    else if (bandwidthMbps >= 1.0) qualityScore += 30;
    else if (bandwidthMbps >= 0.5) qualityScore += 20;
    else if (bandwidthMbps >= 0.25) qualityScore += 10;
    else qualityScore += 0;

    if (rttMs < 50) qualityScore += 25;
    else if (rttMs < 100) qualityScore += 20;
    else if (rttMs < 300) qualityScore += 15;
    else if (rttMs < 500) qualityScore += 5;
    else qualityScore += 0;

    if (packetLossPercent < 0.5) qualityScore += 25;
    else if (packetLossPercent < 2) qualityScore += 20;
    else if (packetLossPercent < 5) qualityScore += 15;
    else if (packetLossPercent < 10) qualityScore += 5;
    else qualityScore += 0;

    if (jitterMs < 10) qualityScore += 10;
    else if (jitterMs < 30) qualityScore += 8;
    else if (jitterMs < 50) qualityScore += 5;
    else if (jitterMs < 100) qualityScore += 2;
    else qualityScore += 0;
 
    if (qualityScore > 80) {
      return "ultra";
    } else if (qualityScore > 60) {
      return "high";
    } else if (qualityScore > 40) {
      return "medium";
    } else if (qualityScore > 20) {
      return "low";
    } else {
      return "very-low";
    }
  };

점수를 20 점 단위로 자르고, 각각 ultra, high, medium, low, very-low 의 5단계로 나누었다. 3단계할까 5단계할까 고민했는데, 좀 더 드라마틱한 효과를 보기 위해서 5단계로 쪼개었다.

왜 안바뀌지..?

최근 5번의 평균을 내는 로직을 구현했는데 어째선지 최근 5회 보고서에 같은 값만 찍히는 버그가 있었다. 디버깅 후에 알아낸 사실은

콘솔 같은거 찍힘..콘솔 같은거 찍힘..

const {
  networkStats,
  updateNetworkStats,
  setCurrentNetworkQuality,
  currentNetworkQuality,
} = useNetworkStore();

const recentStats = networkStats.length > count ? networkStats.slice(-count) : networkStats;

이 코드에 있었다. networkStats는 네트워크 데이터가 담기는 배열인데, 이렇게 계산하고 있었다. recentStats를 불러오는 로직은 틀리지 않았는데 이상하게 값이 변경되지 않았다.

그래서 찾아보니 useNetworkStore()를 구조분해해서 가져오는 networkStats는 이 훅이 마운트 될 때 캡쳐되고 바뀌지 않는다고 한다. 그러니까 나는 변경되지 않는 배열을 가지고 5회 평균을 내고 있었던 것이었다..

그래서 const networkStats = *useNetworkStore*.getState().networkStats; 같은 형식으로 항상 새로운 값을 가져오도록 하여 해결했다.

네트워크 테스트

기존에 네트워크 테스트는 개발자도구에서 4G나 3G 속도로 제한하는 정도 밖에 해보지 않았다. 하지만 네트워크가 아닌 WebRTC 의 P2P 통신에서는 효과가 없는 것을 확인했다.

다른 네트워크 에뮬레이터 테스트 도구가 있을까 찾아봤다. 처음에는 js 라이브러리 중 찾아보려고 했는데 라이브러리를 사용하는 방법 보다는 외부에서 제어해주는 도구를 쓰는게 더 나을 것 같다고 판단했다.

그래서 찾아본 결과 clumsy라는 도구를 발견했다. 이 도구는 다양한 네트워크 지연 현상을 시뮬레이션하는 도구였다. 랙, 쓰로틀, 대역폭 제한 등의 다양한 상황을 조절해가면서 테스트할 수 있는 도구다.

https://jagt.github.io/clumsy/index.html

결과적으로 내가 원하는 것은 네트워크 품질이 안좋아지면 품질 프리셋이 낮아지는 것이다. 그래서 극한의 네트워크 상황을 테스트해야했다.

테스트에 사용한 설정은 아래와 같다. 전반적인 네트워크 품질을 떨어뜨려야했기 때문에 랙, 드랍, 쓰로틀을 걸어줬고, 대역폭을 제한하기 위해서 초당 200KB로 제한했다.

나의 클럼시 세팅나의 클럼시 세팅

해당 영상은 clumsy 테스트 하기 전과 후를 보여주는 영상 테스트이다. 테스트 하기 전에는 ultra 품질을 유지하다가, clumsy를 켜는 순간 low로 점점 떨어지는 모습을 볼 수 있다.

테스트 영상

클럼시 테스트 전클럼시 테스트 전

화질이 좀 안좋은데 네트워크 품질이 ultra인 것을 볼 수 있다. 이건 클럼시 테스트를 하기 전의 상태이다.

클럼시 테스트 후클럼시 테스트 후

이 사진은 클럼시 테스트 시작 후 20초 정도가 지났을 때의 사진이다. 대역폭이 많이 떨어져서 네트워크 품질은 최하인 'Very-low'에 도달했다.

이제 네트워크 상태에 따른 품질을 조절하는 것은 모두 완성됐다. 여기서 계산 식만 조율해가면서 최적의 식을 찾으면 되는 정도만 남았다. 이 다음 글에서는 이렇게 결정된 프리셋 단계를 가지고 webrtc 비디오 컴포넌트에 적용하는 것을 해보려고 한다. 👻👻👻👻

📌 Table of Contents

  • 🌲 프리뷰 | 네트워크 기반 동적 품질 조절 기능 개발 2편
  • 🪓 최근 5회의 평균
  • 🪵 품질 단계
  • 🪵 왜 안바뀌지..?
  • 🪓 네트워크 테스트
0
추천 글