본문으로 건너뛰기
고급약 45분

실행 인프라 — 러너·그리드·디바이스 팜 운영과 용량·비용

테스트를 실제로 돌리는 설비를 용량 문제로 다룬다. 러너·Selenium Grid·디바이스 팜의 운영 관점(이미지 관리, 대기 시간, 활용률), 셀프호스티드와 클라우드를 고르는 기준, 동시 실행 수를 근거 있게 정하는 계산, 그리고 실행이 밀릴 때 무엇부터 줄일지 사전에 정하는 감축 계획을 다룬다.

  • #TestOps
  • #러너
  • #SeleniumGrid
  • #디바이스팜
  • #용량산정
  • #병렬실행

개념

실행 인프라는 성능 문제가 아니라 용량 문제다

"테스트가 느리다"는 말에는 두 개의 다른 문제가 섞여 있다. 하나는 테스트 하나가 오래 걸리는 문제(성능), 다른 하나는 테스트 묶음 전체가 제 시간에 안 끝나는 문제(용량) 다. 전자는 대기 전략과 테스트 설계로 줄이고, 그건 m13·m55 의 영역이다. 이 레슨은 후자를 다룬다.

용량 문제로 보는 순간 질문이 바뀐다. "왜 느릴까"가 아니라 "몇 개를 동시에 돌릴 수 있고, 수요가 그보다 많을 때 얼마나 기다리는가" 가 된다. 이 질문은 테스트 코드를 전혀 보지 않고도 답할 수 있고, 답에 따르는 조치도 코드 수정이 아니다 — 설비를 늘리거나, 수요를 줄이거나, 둘 다다.

실행 설비 세 종류와 각각의 운영 부담

설비무엇을 제공하는가운영에서 실제로 손이 가는 곳
러너(runner / agent / executor)테스트 프로세스를 실행하는 컴퓨트실행 이미지 버전, 의존성 캐시, 작업 공간 정리, 비밀값 주입, 동시 실행 상한
브라우저 그리드(Selenium Grid 등)브라우저 세션을 원격으로 제공브라우저·드라이버 버전 조합, 세션 대기열, 좌석 수, 세션 누수
디바이스 팜실기기·에뮬레이터 단말단말 재고와 상태(배터리·OS 버전), 점유 시간, 초기화, 설치 실패

세 설비는 직렬로 쌓인다. 러너가 비어 있어도 그리드 좌석이 없으면 기다리고, 좌석이 있어도 단말이 점유 중이면 기다린다. 그래서 용량을 볼 때는 가장 좁은 구간 하나를 찾아야 한다. 러너를 두 배로 늘렸는데 완료 시간이 안 줄었다면, 병목은 러너가 아니었던 것이다.

러너 — 호스티드와 셀프호스티드의 운영 차이

관리형 호스티드 러너는 실행마다 깨끗한 환경을 받는다는 큰 장점이 있다. 대신 매 실행이 의존성 설치부터 시작하므로 준비 시간이 고정비로 붙고, 사내망 안의 테스트 대상에 접근하려면 별도 경로가 필요하다. 셀프호스티드 러너는 그 둘을 해결하지만 깨끗함을 스스로 보장해야 한다. 실무에서 셀프호스티드가 만드는 문제는 거의 늘 이 셋이다.

  1. 잔여 상태 오염 — 앞 실행이 남긴 파일·프로세스·포트·캐시가 다음 실행 결과를 바꾼다. 매 실행 전 작업 공간을 지우고, 컨테이너로 한 겹 감싸는 것이 기본이다.
  2. 디스크 고갈 — 아티팩트·이미지 레이어·캐시가 쌓여 어느 날 전부 실패한다. 용량 경보와 주기적 정리(prune)를 설비 쪽 운영 작업으로 등록해 둬야 한다.
  3. 버전 표류 — 러너 A 와 러너 B 의 브라우저·런타임 버전이 달라져, 같은 테스트가 어느 러너에 배치되느냐에 따라 결과가 갈린다. 이건 플래키로 오진되기 가장 쉬운 원인이다.

세 문제의 공통 해법은 실행 환경을 이미지로 고정하고 그 이미지 태그를 결과에 기록 하는 것이다. m14 레슨 3에서 다룬 Docker 재현성이 여기서 운영 규칙으로 올라온다 — 재현 가능한 이미지를 만드는 것(m14)과, 어느 실행이 어느 이미지 태그로 돌았는지를 추적 가능하게 유지하는 것(m59)은 다른 일이다.

러너 풀 운영 체크 항목 (주 1회)
- 풀의 각 러너가 보고하는 이미지 태그가 모두 같은가
- 디스크 여유가 임계 이하인 러너가 있는가 (임계: 전체의 20% 권장)
- 마지막 24시간 안에 '오프라인' 으로 전환된 러너가 있는가
- 작업 공간 정리 단계가 실패한 실행이 있는가 — 실패하면 다음 실행이 오염된다
- 러너별 평균 대기 시간 편차가 큰가 — 라벨 배치가 한쪽으로 몰렸다는 신호

그리드 — 좌석 수와 세션 누수

Selenium Grid 는 브라우저 세션을 중앙에서 배분하는 설비다. 구성 형태는 단독 (standalone), 허브-노드(hub and node), 그리고 역할을 쪼갠 완전 분산형이 있고, 분산형은 라우터·디스트리뷰터·세션 대기열·세션 맵·이벤트 버스 같은 구성 요소로 나뉜다. 구성 요소의 정확한 이름과 기동 옵션은 버전마다 바뀌므로 공식 문서 원문 확인이 필요하다.

운영 관점에서 중요한 것은 구성도가 아니라 세 숫자다.

  • 총 좌석 수 — 노드들이 제공하는 동시 세션 수의 합. 브라우저별로 따로 센다.
  • 세션 대기열 길이 — 좌석을 기다리는 요청 수. 이 값이 지속적으로 0 이 아니면 좌석이 부족하다는 뜻이다.
  • 세션 평균 수명 — 테스트 하나가 좌석을 점유하는 시간. 이 값이 서서히 늘고 있으면 세션 누수(테스트가 끝나며 브라우저를 닫지 않음)를 의심한다.

세션 누수는 그리드 운영의 고전적 사고다. 좌석이 하나씩 잠기고, 어느 시점부터 전체 실행이 대기로 밀리고, 겉보기로는 "오늘 유독 느리다"로 나타난다. 대책은 두 겹이다 — 테스트 쪽에서 종료를 보장하는 것(픽스처 해제)과, 설비 쪽에서 세션 유휴 제한을 둬 오래 잡힌 세션을 강제 회수하는 것. 설비 쪽 방어가 없으면 테스트 하나의 버그가 전체 용량을 먹는다.

디바이스 팜 — 단말은 재고다

모바일 실행 설비는 소프트웨어가 아니라 재고처럼 다뤄야 한다. 단말에는 상태가 있고, 상태는 시간이 지나면 나빠진다.

선택지적합한 상황운영에서 드는 비용
로컬 에뮬레이터·시뮬레이터기능 회귀의 대부분, 개발 중 빠른 확인러너의 CPU·메모리, 기동 시간, 그래픽 가속 설정
사내 실기기 팜기기 고유 문제(카메라·센서·지문·푸시), 보안상 외부 금지단말 구매·보관·전원·OS 업데이트 통제, 케이블·허브 고장
클라우드 디바이스 팜폭넓은 단말·OS 조합 커버, 단기 수요 급증좌석 동시성 제약, 네트워크 지연, 사내망 접근 경로, 재현 시 같은 단말 확보

실무 기본형은 섞어 쓰는 것이다. 에뮬레이터로 넓게 자주 돌리고, 실기기는 좁게 정기적으로 돌린다. m13 레슨 8(크로스 브라우저·디바이스 전략)이 "어느 조합을 고를 것인가"를 다뤘다면, 여기서는 고른 조합을 유지하는 비용을 본다. 단말 재고 장부에는 최소한 이 네 열이 필요하다 — 모델·OS 버전·마지막 정상 실행 시각·현 상태(가용/점검/폐기).

단말 운영에서 가장 흔한 숨은 비용은 설치 실패 다. 앱 설치가 실패하면 테스트는 "실패"로 기록되지만 제품과는 아무 상관이 없다. 설치 단계를 테스트 본문이 아니라 준비 단계로 분리해 별도 상태 코드로 기록하면, 이 소음이 통과율 지표에서 빠진다. 레슨 7의 트리아지 규칙이 이 신호를 쓴다.

동시 실행 수를 정하는 계산

필요한 동시 실행 수는 추측하지 않고 계산한다. 네 숫자만 있으면 된다.

N  = 테스트 개수
T  = 테스트 평균 실행 시간(초)  ← 꼬리값이 크면 평균보다 p90 을 쓴다
D  = 목표 완료 시간(초)
O  = 실행 1회의 고정 준비 시간(초) — 체크아웃·의존성·이미지 준비
 
필요 동시 실행 수 C ≈ (N × T) / (D − O)
 
예) N=600, T=25초, D=1200초(20분), O=180초
    C ≈ (600 × 25) / (1200 − 180) = 15000 / 1020 ≈ 14.7 → 15

여기에 두 가지 보정을 반드시 넣는다.

첫째, 활용률 보정. 대기열이 있는 시스템은 활용률이 올라갈수록 대기 시간이 비선형으로 늘어난다. 설비를 수요에 딱 맞추면(활용률 100%) 작은 변동에도 대기가 크게 튄다. 그래서 산정값에 여유를 얹는다 — 평상시 활용률 목표를 70% 전후로 두는 것이 운영하기 편한 지점이다. 위 예라면 15가 아니라 20 전후를 확보한다.

둘째, 상한 제약 확인. 계산값이 커도 실제로 올릴 수 없는 경우가 많다. 상한을 만드는 요인은 네 가지다.

  • 테스트 대상 시스템의 처리량 — 동시 실행을 올리면 대상 서버가 먼저 무너진다. 테스트가 대상을 부하 테스트하는 상태가 되면 결과 전체가 의미를 잃는다.
  • 데이터 충돌 — 같은 계정·같은 레코드를 여러 실행이 동시에 건드린다. 레슨 3의 데이터 격리가 풀리지 않으면 병렬을 올릴 수 없다.
  • 좌석·라이선스 동시성 — 그리드 좌석, 클라우드 팜 동시 세션 수.
  • 러너 호스트 자원 — 브라우저 하나가 쓰는 메모리를 기준으로 호스트당 가능한 동시 수가 정해진다. 이 값을 넘기면 느려지고, 느려지면 대기가 터지고, 대기가 터지면 플래키가 늘어난다.

마지막 항목이 실무에서 가장 과소평가된다. 자원이 모자란 러너에서 생기는 타임아웃은 테스트 코드의 플래키로 오진된다. 병렬 수를 올린 다음 주에 플래키율이 올랐다면, 테스트를 의심하기 전에 러너의 CPU·메모리 사용률을 본다.

셀프호스티드와 클라우드를 고르는 기준

도구별 요금과 무료 할당량은 자주 바뀌므로 숫자로 외우지 않는다. 대신 바뀌지 않는 판단 축 으로 고른다.

판단 축셀프호스티드가 유리클라우드·관리형이 유리
수요 패턴하루 종일 꾸준히 높다간헐적·돌발적으로 몰린다
대상 접근사내망·VPN 안에만 있다공개망에서 접근 가능하다
설비 다양성소수 조합만 쓴다브라우저·OS·단말 조합이 넓다
운영 인력설비를 볼 사람이 있다없다 — 그 시간을 테스트에 쓰고 싶다
보안·데이터테스트 데이터에 민감정보가 섞인다합성 데이터만 쓴다
재현 요구"같은 환경에서 다시"가 중요하다넓은 커버리지가 더 중요하다

실무 결론은 보통 혼합이다. 상시 수요는 셀프호스티드로 받고, 돌발 수요와 넓은 조합은 클라우드로 받는다. 이때 중요한 것은 같은 테스트가 어느 설비에서 돌았는지를 결과에 기록하는 것 이다. 기록이 없으면 "클라우드에서만 깨지는 테스트" 같은 패턴을 영원히 발견하지 못한다. 레슨 6의 상관 식별자에 설비 종류를 넣는 이유가 여기 있다.

실행이 밀릴 때 — 감축 계획을 미리 쓴다

용량이 부족한 순간에 무엇을 줄일지 정하는 것은 급할 때 할 결정이 아니다. 평상시에 순서를 정해 문서로 두고, 밀릴 때 그 순서대로 집행한다. 아래가 기본 순서이고, 위쪽이 먼저다 — 정보 손실이 적은 것부터 줄인다.

감축 순서 (실행 지연이 목표 완료 시간을 넘길 때)
 
1. 아티팩트 수집 축소
   통과한 테스트의 비디오·트레이스를 끈다. 실패 건만 남긴다.
   (정보 손실 거의 없음 — 통과 아티팩트는 대개 보지 않는다)
 
2. 중복 설비 조합 축소
   브라우저·단말 조합을 핵심 1~2개로 줄인다. 나머지는 야간·주간으로 미룬다.
 
3. 실행 빈도 하향
   PR 마다 돌던 전체 묶음을 머지 후로, 머지마다 돌던 것을 시간당으로 내린다.
 
4. 범위 축소 — 변경 영향 기반
   변경된 모듈과 연관된 테스트만 돌린다. 나머지는 야간 전체 실행이 받는다.
 
5. 우선순위 하위 테스트 보류
   비즈니스 위험이 낮은 테스트를 명시적으로 '보류' 표시하고 목록을 남긴다.
   (여기서부터 정보 손실이 실재한다 — 보류 목록은 매주 리뷰한다)
 
6. 설비 증설 요청
   1~5를 적용한 뒤에도 못 맞추면 용량 산정 근거와 함께 증설을 요청한다.

순서가 거꾸로 가는 조직이 많다. 밀리면 먼저 "테스트를 지우자"는 말이 나오는데, 그건 5번이다. 14를 집행하지 않은 상태에서 5번으로 가면 커버리지만 잃고 원인은 그대로 남는다. 반대로 15를 다 하고도 못 맞춘다면 그때의 증설 요청은 설득력이 다르다 — "줄일 건 다 줄였다"는 근거가 붙기 때문이다.

감축 계획에 반드시 들어가야 하는 한 줄이 있다. 감축은 기본값이 아니라 한시 조치이고, 해제 조건을 함께 쓴다. 해제 조건이 없는 감축은 조용히 영구화되고, 반년 뒤에 아무도 비디오 수집이 꺼져 있는 것을 모르게 된다.

실무에서 왜 필요한가

실행이 밀리는 상태는 품질 활동 전체를 서서히 무력화한다. 완료가 늦으면 개발자는 결과를 기다리지 않고 다음 작업으로 넘어가고, 넘어간 뒤에 온 실패는 맥락이 사라져 조사 비용이 몇 배로 뛴다. 그래서 완료 시간은 단순한 편의 지표가 아니라 피드백이 행동으로 이어지는지를 결정하는 변수 다.

용량 산정이 문서로 있으면 대화의 성격이 바뀐다. "테스트 좀 빨리 되게 해 주세요"는 요청이 아니라 불만이고, 받는 쪽에서 할 수 있는 일이 없다. 반면 "현재 600개 × 25초를 20분에 맞추려면 동시 15가 필요하고 지금은 8이다. 1~4번 감축을 적용하면 24분, 증설 없이는 목표 미달"은 결정 가능한 선택지다. 인프라 예산 요청이 통과하는 자료는 거의 항상 이 형태를 갖는다.

실습 과제

과제 1 — 우리 묶음의 동시 실행 수 산정 (30분)

최근 야간 전체 실행 로그에서 네 숫자를 뽑는다 — 테스트 개수 N, 테스트 실행 시간의 평균과 p90, 고정 준비 시간 O, 그리고 현재 실제 완료 시간.

  1. 목표 완료 시간 D 를 정하고 본문 식으로 필요 동시 실행 수 C 를 계산한다. 평균으로 한 번, p90 으로 한 번 계산해 두 값을 비교한다.
  2. 활용률 70% 기준으로 여유를 얹은 확보 목표를 적는다.
  3. 네 가지 상한 제약(대상 처리량·데이터 충돌·좌석·러너 자원)을 각각 확인해 실제로 올릴 수 있는 상한을 적는다.
  4. 계산값과 상한 중 작은 쪽이 결론이다. 결론이 목표를 못 맞추면 과제 3으로 넘긴다.

과제 2 — 병목 구간 찾기 (25분)

한 번의 전체 실행에 대해 시간을 네 구간으로 쪼갠다 — 대기(큐), 준비(체크아웃·설치), 실행, 수집·업로드. 각 구간이 전체의 몇 %인지 계산한다.

  • 대기가 가장 크면 설비 부족이다 → 과제 1의 산정으로 간다
  • 준비가 가장 크면 캐시·이미지 설계 문제다 → 어떤 단계가 매번 다시 하는지 찾는다
  • 수집·업로드가 10%를 넘으면 아티팩트 정책이 과하다 → 감축 1번의 후보다
  • 실행이 대부분이면 테스트 설계 문제다 → m13·m55 의 영역으로 넘긴다

과제 3 — 감축 계획 문서 쓰기 (20분)

본문의 6단계 감축 순서를 우리 상황으로 구체화한다. 각 단계마다 세 가지를 적는다 — 구체적 조치(어느 설정을 어떻게), 예상 절감 시간, 그리고 해제 조건.

마지막에 발동 기준을 한 문장으로 쓴다. 예: "야간 전체 실행이 3일 연속 목표 완료 시간을 20% 초과하면 1·2번을 자동 적용하고 당번이 공지한다."

자가 체크리스트

  • 테스트 "성능" 문제와 "용량" 문제를 구분해 각각 어느 모듈의 일인지 말할 수 있다
  • 러너·그리드·디바이스 팜이 직렬로 쌓인다는 것을 이해하고 병목 구간을 찾는 절차를 안다
  • 셀프호스티드 러너의 세 가지 전형적 문제(상태 오염·디스크 고갈·버전 표류)를 점검 항목으로 갖고 있다
  • 실행 이미지 태그가 결과에 기록되고 있어 "어느 환경에서 돌았는가"에 답할 수 있다
  • 그리드에서 봐야 할 세 숫자(좌석 수·대기열 길이·세션 평균 수명)를 안다
  • 세션 누수를 설비 쪽에서 방어하는 장치(유휴 제한)가 있는지 확인했다
  • 단말 재고 장부가 있고 마지막 정상 실행 시각이 기록된다
  • 필요 동시 실행 수를 계산해 봤고, 활용률 여유를 얹었다
  • 동시 실행 수의 네 가지 상한 제약을 각각 확인했다
  • 실행이 밀릴 때의 감축 순서가 문서로 있고 각 단계에 해제 조건이 붙어 있다

흔한 실수

대기 시간을 재지 않는다. 실행 시간만 보고 "느리다"를 판정하면 설비 부족을 영원히 발견하지 못한다. 대기는 테스트 로그에 안 찍히고, 파이프라인 전체 소요에만 나타난다. 구간을 쪼개 재지 않으면 보이지 않는 구간이다.

병렬 수를 올려 문제를 해결하려 한다. 데이터 충돌과 대상 처리량 상한을 확인하지 않고 병렬을 올리면, 완료 시간은 조금 줄고 플래키율은 크게 오른다. 순이익이 음수가 되는 전형적인 조치다.

러너 자원 부족을 테스트 플래키로 오진한다. 메모리가 모자란 호스트에서 브라우저는 느려지고, 느려진 브라우저는 타임아웃을 만든다. 로그에는 테스트 실패로 남는다. 병렬 변경 직후의 플래키 증가는 거의 항상 이쪽이다.

클라우드와 셀프호스티드를 섞어 쓰면서 어디서 돌았는지 기록하지 않는다. 설비별 실패율 차이를 비교할 수 없게 되고, "환경 탓"이라는 말만 반복된다.

감축을 임시로 켜고 해제를 잊는다. 특히 아티팩트 수집 축소가 그렇다. 반년 뒤 중요한 실패가 났을 때 트레이스가 없어 재현에 며칠이 든다. 해제 조건을 쓰고, 분기마다 켜진 감축 목록을 확인한다.

참고 자료

  • Selenium 공식 문서 — Grid 의 구성 형태(standalone·hub and node·분산)와 구성 요소, 세션 대기열 옵션. 구성 요소 이름과 기동 옵션은 버전마다 바뀌므로 원문 확인
  • Appium 공식 문서 — 드라이버별 단말 요구사항과 세션 관리. 원문 확인
  • Playwright 공식 문서 — workers 설정과 샤딩(shard) 옵션의 의미. 원문 확인
  • ISTQB CTAL-TAE v2.0 실러버스 — 테스트 자동화 인프라와 배포 장. 장 번호는 원문 확인
  • Jez Humble, David Farley, Continuous Delivery — 배포 파이프라인의 단계 분할과 병렬화
  • 이 커리큘럼 안의 관련 레슨: 모듈 14 레슨 3(Docker 재현성), 모듈 13 레슨 7·8(Appium·조합 전략), 이 모듈 레슨 3(데이터 격리)·레슨 6(상관 식별자)

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

OS — 운영체제
기기를 돌리는 바탕 프로그램 — 윈도우, 맥, 안드로이드 같은 것.
컨테이너 — 컨테이너
이 커리큘럼에서 두 가지로 쓰인다. ① 프로그램과 그것을 돌리는 데 필요한 것들을 한 상자에 담아, 어느 컴퓨터에서나 똑같이 돌아가게 만든 것 ② 화면에서 여러 요소를 하나로 묶는 바깥 틀. 서버·배포 이야기면 ①, 화면·접근성 이야기면 ②다.
CPU — 중앙처리장치
계산을 담당하는 부품. 사람으로 치면 머리다.
VPN — 가상 사설망
공용 인터넷을 지나면서도 사내망에 직접 연결된 것처럼 쓰게 해 주는 장치.
ISTQB — 국제 소프트웨어 테스팅 자격 위원회
테스터 자격 시험을 만들고 용어를 정리하는 국제 단체.
CTAL-TAE — 상급 자격 · 테스트 자동화
상급 테스터 자격 중 자동화 설계를 다루는 과목.

용어집 전체 보기