HexVM 엔지니어링 실무

클라우드 Mac 저품질 네트워크 재현과 복구 절차

클라우드 Mac 저품질 네트워크 재현과 복구 절차

iOS 클라이언트를 원격으로 디버깅할 때 가장 재현하기 어려운 상황은 완전한 연결 끊김이 아니라 “연결은 되지만 응답이 매우 느린” 네트워크다. 핸드셰이크 지연이 늘어나고 업로드 속도가 떨어지며 일부 요청이 유실되면 중복 제출, 무한 재시도, 화면의 장시간 대기 같은 문제가 발생한다. HexVM 클라우드 Mac에서 이런 테스트를 수행할 때는 속도 제한보다 먼저 앱의 테스트 트래픽을 SSH, VNC 등의 관리 트래픽과 분리해야 한다. 범위가 지나치게 넓은 규칙 하나만으로도 원격 관리 경로가 차단될 수 있기 때문이다.

검증 가능한 저품질 네트워크 시나리오 정의

“네트워크가 나쁘다”는 표현을 테스트 조건으로 사용해서는 안 된다. 재현할 수 없고 수정의 효과도 판단할 수 없기 때문이다. 먼저 시나리오를 고정된 매개변수로 작성하고 각 시나리오에서 기대하는 클라이언트 동작을 정의한다.

시나리오 다운로드 및 업로드 제한 추가 지연 패킷 손실률 주요 검증 항목
기준선 제한 없음 0 ms 0 정상 요청의 소요 시간과 성공률
높은 지연 8 Mbit/s 120 ms 0 로딩 상태, 취소 및 시간 초과
낮은 대역폭 1 Mbit/s 80 ms 0 업로드 진행률과 백그라운드 전환
불안정한 연결 4 Mbit/s 100 ms 2% 재시도 상한과 멱등성 처리

이 매개변수는 테스트 입력값이지 노드의 네트워크 품질을 설명하는 수치가 아니다. 팀은 API 시간 초과, 파일 크기, 사용자의 네트워크 환경에 맞춰 값을 조정해야 하지만 동일한 회귀 테스트 주기에는 같은 매개변수를 유지해야 한다.

저품질 네트워크 테스트의 목적은 요청이 결국 성공한다는 사실을 증명하는 것이 아니다. 실패가 발생했을 때 클라이언트가 적시에 대기를 끝내고 이해하기 쉬운 상태를 표시하며 중복 데이터를 만들지 않는지 확인하는 것이 핵심이다.

속도 제한 없는 기준선 측정

트래픽 셰이핑 규칙을 적용하지 않은 상태에서 DNS, 라우팅, 엔드포인트 응답을 먼저 기록한다. 테스트 엔드포인트는 팀이 직접 관리해야 하며 프로덕션 데이터를 변경하지 않는 프로브 경로를 제공해야 한다.

export TEST_URL="https://test-endpoint.invalid/health"
scutil --dns | grep 'nameserver\[[0-9]*\]'
route -n get default
networkQuality
curl -sS -o /dev/null \
  -w 'code=%{http_code} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}
' \
  "$TEST_URL"

예시 도메인은 실제로 관리되는 테스트 주소로 바꿔야 한다. 최소 세 번 요청한 결과의 중앙값을 기록하고 가장 좋은 결과 하나만 저장해서는 안 된다. 기준선 측정 단계에서 이미 DNS 실패, 인증서 오류, 라우팅 이상이 발생한다면 먼저 기반 문제를 해결해야 하며 재시도를 늘려 이를 숨겨서는 안 된다.

대상 주소가 여러 IP를 통해 서비스되는지도 확인해야 한다. IP 하나만 제한하면 요청이 다른 주소로 해석되어 같은 테스트에서도 속도가 들쭉날쭉해질 수 있다. 저품질 네트워크 검증용 고정 엔드포인트를 준비하고 실행 전에 DNS 조회 결과를 저장하는 방식이 더 안정적이다.

대상 엔드포인트 트래픽만 셰이핑

macOS의 dnctl은 대역폭과 지연을 제한하는 파이프를 만들고, pf는 일치하는 트래픽을 해당 파이프로 전달한다. 규칙은 대상 IP, 프로토콜, 포트를 모두 제한해야 하며 모든 아웃바운드 연결을 포괄하는 와일드카드 조건을 사용해서는 안 된다.

다음 스크립트는 8 Mbit/s 대역폭, 120 ms 지연, 2% 패킷 손실을 적용하는 테스트 파이프를 생성한다. TARGET_IP에는 관리되는 엔드포인트의 고정 주소를 입력해야 한다.

set -euo pipefail

TARGET_IP="${TARGET_IP:?set TARGET_IP first}"
PIPE_ID=310
ANCHOR="com.apple/hexvm-nettest"

cleanup() {
  sudo pfctl -a "$ANCHOR" -F all >/dev/null 2>&1 || true
  sudo dnctl delete "$PIPE_ID" >/dev/null 2>&1 || true
}

trap cleanup EXIT INT TERM

sudo dnctl pipe "$PIPE_ID" config bw 8Mbit/s delay 120 plr 0.02
printf 'dummynet out quick proto tcp from any to %s port 443 pipe %s
' \
  "$TARGET_IP" "$PIPE_ID" |
  sudo pfctl -a "$ANCHOR" -f -

sudo pfctl -E >/dev/null
sudo pfctl -a "$ANCHOR" -sr -v

curl -sS -o /dev/null \
  -w 'code=%{http_code} connect=%{time_connect} total=%{time_total}
' \
  "$TEST_URL"

먼저 읽기 전용 상태 확인 요청으로 규칙이 적용되는지 검증한 뒤 데이터를 쓰는 비즈니스 테스트를 실행한다. 정리 목적으로 pfctl -d를 실행해서는 안 된다. 머신에 다른 방화벽 규칙이 이미 적용되어 있을 수 있기 때문이다. 스크립트는 자체 anchor만 비우고 자체 pipe만 삭제하므로 병렬 작업에 영향을 주지 않는다.

원격 세션이 실수로 차단되지 않도록 보호

실행 전에 두 번째 관리 터미널을 열어 두고 규칙에 관리 포트, 기본 게이트웨이 또는 임의 대상을 가리키는 와일드카드가 없는지 확인한다. 테스트 대상과 관리 연결이 같은 IP를 사용한다면 규칙 순서에 기대지 말고 별도의 테스트 엔드포인트를 사용해야 한다.

클라이언트 동작을 자동화된 단언으로 전환

저품질 네트워크 검증에서는 요청이 “돌아왔는지”만 확인해서는 안 된다. 테스트 코드는 시도 횟수, 최종 오류 유형, 총 대기 시간, 요청 식별자를 기록해야 한다. 쓰기 작업에는 서버와 클라이언트 모두 안정적인 멱등성 키를 사용해야 한다. 시간 초과가 발생하면 클라이언트는 먼저 처리 결과를 조회한 다음 재시도 여부를 결정한다.

네트워크 계층을 관측 가능한 래퍼로 교체하고 다음 경계 조건을 검사할 수 있다.

  1. 단일 연결이 임계 시간을 초과하면 무한정 기다리지 않고 취소할 수 있어야 한다.
  2. 재시도 횟수에 상한이 있고 간격에 백오프가 적용되어 요청 폭주가 발생하지 않아야 한다.
  3. 사용자가 직접 취소한 뒤에는 백그라운드 작업이 몰래 다시 요청해서는 안 된다.
  4. 업로드가 중단되면 명확한 상태를 유지하고 실패를 완료로 표시해서는 안 된다.
  5. 네트워크가 복구되면 작업을 계속할 수 있어야 하지만 레코드가 중복 생성되어서는 안 된다.

시뮬레이터 테스트는 명시적인 기기 식별자로 실행해 머신에 우연히 존재하는 기기 이름에 의존하지 않도록 한다.

export SIMULATOR_UDID="replace-with-booted-simulator-udid"

xcodebuild test \
  -scheme NetworkBehaviorTests \
  -destination "platform=iOS Simulator,id=${SIMULATOR_UDID}" \
  -resultBundlePath build/NetworkBehavior.xcresult

각 네트워크 시나리오의 결과 번들을 별도로 저장하고 시나리오 매개변수를 테스트 로그에 기록한다. 그래야 실패 기록을 통해 “어떤 지연과 패킷 손실 조건에서 실패했는지”를 확인할 수 있으며, 재현할 수 없는 빨간색 상태만 남는 일을 피할 수 있다.

규칙 정리 및 회귀 테스트 완료

스크립트가 정상 종료되거나 인터럽트 신호를 받으면 정리 작업이 실행된다. 하지만 원격 세션이 비정상적으로 종료된 경우에는 직접 상태를 확인해야 한다. 다시 연결한 뒤 다음 명령을 실행한다.

sudo pfctl -a com.apple/hexvm-nettest -sr
sudo dnctl list
curl -sS -o /dev/null \
  -w 'code=%{http_code} connect=%{time_connect} total=%{time_total}
' \
  "$TEST_URL"

전용 anchor는 비어 있어야 하며 목록에 번호가 310인 pipe가 남아 있으면 안 된다. 그런 다음 기준선 요청을 다시 실행해 연결 시간과 총 소요 시간이 테스트 전의 정상 범위로 돌아왔는지 확인한다.

마지막으로 셰이핑을 적용하지 않은 상태에서 회귀 테스트를 수행한다. 특히 저품질 네트워크 대응 수정으로 인해 정상 네트워크 환경의 요청 순서, 캐시 적중, 화면 응답이 달라지지 않았는지 확인해야 한다. 시나리오 매개변수, 클라이언트 버전, 대상 엔드포인트 버전, 결과 번들 경로, 정리 결과를 하나의 실행 기록에 저장한다. 그래야 저품질 네트워크 테스트를 일회성 수동 시연이 아니라 감사 가능하고 재현 가능하며 안전하게 종료할 수 있는 엔지니어링 절차로 만들 수 있다.

자주 묻는 질문

원격 Mac의 전체 송신 트래픽을 제한하면 안 되는 이유는 무엇인가요?

전역 규칙은 SSH, VNC, 의존성 다운로드까지 함께 제한해 관리 세션을 끊을 수 있습니다. 테스트 대상의 IP, 프로토콜, 포트만 일치시켜야 합니다.

임시 네트워크 규칙이 제거됐는지 어떻게 확인하나요?

전용 pf anchor를 비우고 연결된 dnctl pipe를 삭제한 뒤 anchor에 남은 규칙이 없는지 확인합니다. 마지막으로 기준 요청을 다시 실행합니다.

저품질 네트워크에서 확인할 핵심 앱 동작은 무엇인가요?

연결 시간 초과, 제한된 재시도, 요청 취소, 오프라인 안내, 중복 제출 방지, 네트워크 복구 후 정상 재개를 확인해야 합니다.

독점 Apple Silicon

다음 빌드를 위한 독점 클라우드 Mac 선택

워크로드에 맞춰 Mac mini 모델, 대여 기간 및 리전을 선택하세요. 각 주문에는 독립된 물리 노드가 할당되며, 실제 이용 가능 여부는 콘솔의 실시간 응답을 기준으로 합니다.

클라우드 Mac 요금제 선택