운영 작업

용량 계획·변경

복원 여유를 계산하고 지원되는 자원 크기를 바꾼다

무엇을 하게 되나

동시 세션 수와 worker 메모리·노드 수를 계획하고 지원되는 값을 변경한다. transcript와 성과물의 고정 상한은 저장소 계약이 정본이다.

준비물

실제 노드 allocatable·다른 Pod requests·slot limit·workspace 사용량을 확인한다. transcript 크기와 compaction 여부에 따라 복원 peak가 다르므로 평균 사용량만으로 크기를 줄이지 않는다.

단계

1. 복원 비용과 안전 여유

기준: compaction이 없는 transcript를 resume할 때의 최악 peak이 worker 메모리 한도의 절반 이하여야 한다. 나머지 절반은 첫 turn의 작업, 측정하지 않은 transcript 모양, 엔진 버전 차이에 쓰는 여유다.

개발용 .env.example은 WORKER_MEMORY_MB=2048을 둔다. 그대로 쓰면 위의 절반 기준이 지켜지지 않는다. 큰 transcript를 resume하는 시험에서는 그 줄을 지우거나 WORKER_MEMORY_MB=4608로 바꾼다. 실제 배포 입력에서 적용되는 값도 함께 확인한다.

측정 방법

비교 조건은 fake model·cgroup v2 Compose 환경이다. source worker가 합성 transcript를 mirror에 넣고 checkpoint한 뒤 pause한다. 이어서 새 worker가 그 checkpoint를 복원하고 첫 resume turn을 돈다. 그동안 0.5초마다 worker 컨테이너의 cgroup(memory.peak, anon, file, shmem, swap, oom_kill)과 프로세스별 VmHWM을 기록했다. memory.peak에는 회수 가능한 page cache(file)도 들어간다. 그래도 기준에는 포함했다. worker 이미지는 claude-agent-sdk 0.3.270, Claude Code CLI 2.1.270이다.

4608MiB 한도 (현재 기본값)

transcriptcompaction첫 resume turnmemory.peak MiB (한도 대비)anonfileswapOOMworker(bun) VmHWMCLI VmHWM
511MiB없음성공1970 (43%)1054710005461129
511MiB있음성공1338 (29%)53371600588237
64MiB없음성공726 (16%)5587500504329

6144MiB 한도 (비교 측정)

transcriptcompaction첫 resume turnmemory.peak MiB (한도 대비)anonfileswapworker(bun) VmHWMCLI VmHWM
600.0MiB없음성공2178 (35%)130174506261308
600.1MiB있음성공1029 (17%)4536090497236
799.4MiB없음성공2785 (45%)166985205971727
799.1MiB있음성공1392 (23%)6719960716234
64.9MiB없음성공839 (14%)5082790437326
150.2MiB없음성공828 (13%)5011510487492

읽는 법

  • worker(bun)는 transcript 크기와 상관없이 440–720MiB를 쓴다. restore가 part 단위로 스트리밍하기 때문이다.
  • 크기에 비례하는 몫은 엔진(CLI)이다. compaction이 없으면 엔진은 대략 210 + 1.85 × T MiB를 쓴다(T는 transcript MiB). 511MiB에서 공식은 1155MiB이고, 실측은 1129MiB였다. compaction이 있으면 엔진 몫은 크기와 상관없이 약 235MiB다.
  • 전체 peak는 page cache를 더해 150–800MiB 구간에서 transcript 1MiB당 약 3MiB씩 는다(150.2MiB에서 828MiB, 600MiB에서 2178MiB, 800MiB에서 2785MiB). 아래 표의 256·400MiB 값은 이 직선으로 보간한 추정이다.

2. transcript 상한과 메모리 선택

후보 상한마다 필요한 메모리와 노드당 세션 수를 비교했다. 메모리는 2 × peak를 512MiB 단위로 올린 값이다. 세션 수는 allocatable 30GiB(30720MiB) 노드 기준이다. 표본이 작아 이 표만으로 운영 환경의 상한을 결정하지 않는다.

상한compaction 없는 peak절반 기준 메모리노드당 세션분포 중 상한 안80% 경고
256MiB1146MiB (추정)2560MiB1210/12204.8MiB
400MiB1578MiB (추정)3584MiB810/12320MiB
512MiB1970MiB (실측)4096MiB → 4608MiB611/12409.6MiB
600MiB2178MiB (실측)4608MiB612/12480MiB
800MiB2785MiB (실측)5632MiB512/12640MiB
  • 512MiB는 관측한 12개 중 11개를 담는다. 둘째로 큰 400.1MiB 세션도 경고에 걸리지 않는다. 넘는 것은 591.8MiB 하나다. 이런 세션은 409.6MiB에서 경고를 받고 새 세션으로 옮긴다.
  • 400MiB면 400.1MiB 세션의 checkpoint가 바로 거절된다. 256MiB면 217MiB 세션도 경고 구간에 들어간다.
  • 메모리는 4096MiB가 아니라 4608MiB다. 512MiB의 실측 peak 1970MiB는 4096MiB의 절반(2048)에 78MiB밖에 남지 않는다. 4608MiB면 여유가 334MiB다.

3. 노드당 동시 세션 수

sessions per node = floor((node allocatable memory - sum of other Pod requests on the node) / worker.memoryMb)

worker 전용 노드 그룹(worker.nodeSelector, worker.tolerations)을 쓰면 다른 Pod 몫은 DaemonSet 정도다. 30GiB allocatable 노드에서 DaemonSet 몫을 0으로 보면 다음과 같다.

worker.memoryMb노드당 세션
204815
4608 (현재)6
61445

CPU도 같은 식으로 센다(worker.cpus, 기본 1). 보통은 메모리가 먼저 찬다. 세션마다 workspace PVC(worker.workspace.quotaMb, 기본 4096MiB)도 하나씩 붙는다. 복원된 transcript(최대 512MiB)는 작업 트리, git objects, restore spool과 함께 이 안에 든다.

local Docker 실행 기반에서는 한 머신의 메모리를 EXECUTION_SLOT_LIMIT(기본 10)개 worker가 나눠 쓴다. 한도는 cgroup 상한이지 예약이 아니라서 동시에 다 차지 않으면 넘쳐도 돈다. 그래도 slot 수 × 4608MiB가 머신 메모리를 크게 넘으면 OOM이 난다.

지원되는 변경 선택

방법하는 일얻는 것대가
① worker.memoryMb 낮추기values 값 하나만 바꾼다(WORKER_MEMORY_MB, 다음 launch부터 적용)노드당 세션이 는다. 예를 들어 3584MiB면 30GiB 노드에 8개다compaction 없는 큰 transcript를 resume할 여유가 같이 준다. 절반 기준을 지키려면 상한도 같이 내려야 한다(3584MiB면 상한 약 400MiB, 추정). 상한은 코드 상수라 빌드가 필요하다
② (현재 미지원) requests를 limits보다 작게 하는 오버커밋chart의 worker Pod requests를 limits보다 작게 둔다작은 세션이 많을 때 노드당 세션이 크게 는다. 실측에서 64–150MiB transcript의 resume peak는 726–839MiB였다지금 chart와 scheduler는 requests = limits로만 Pod를 만든다. 바꾸려면 코드 변경이 필요하다. QoS가 Burstable로 내려가, 큰 세션 몇 개가 동시에 resume하면 노드 메모리 압박으로 OOM kill이나 eviction이 난다
③ 노드 그룹 키우기worker 노드 수나 노드 크기를 늘린다세션당 보장은 그대로 두고 총 세션 수를 늘린다비용이 는다. 코드 변경은 없다
④ (현재 미지원) 세션 크기별 Pod 크기복원할 transcript 크기를 보고 scheduler가 Pod 메모리를 고른다작은 세션은 작게, 큰 세션만 크게 띄운다코드 변경이 필요하다. scheduler가 launch 전에 checkpoint 크기를 알아야 하고, 실행 중에 같은 Pod 안에서 transcript가 커지는 경우를 따로 다뤄야 한다

상한(MAX_TRANSCRIPT_BYTES)만 올리고 메모리를 그대로 두는 것은 권하지 않는다. compaction 없는 큰 transcript의 resume이 한도에 닿으면 worker가 재기동을 반복하다 세션이 recovery_required가 된다. 상한을 바꿀 때는 이 문서의 방법으로 다시 잰다.

메모리 값은 다음 launch부터 적용되고 실행 중 worker는 교체되지 않는다. 상한을 바꾸는 직접 빌드는 API와 worker의 같은 릴리스가 필요하므로 업그레이드 게이트를 따른다.

API만 더 작은 transcript 상한을 쓰면 worker에서 상한 안인 checkpoint도 finalize가 거절하고 transcript_too_large를 기록해 새 turn을 막을 수 있다. API와 worker의 상한을 함께 맞춘다. 새 transcript reason을 모르는 옛 API는 보고를 400으로 거절하므로 migration → API 모든 인스턴스 → worker 순서를 지키고, 그 reason을 아는 빌드까지만 rollback한다.

4. provider 비용과 상한 대조

사용량과 비용 계측의 추정·fallback 단가·재인가 경계를 보고 실제 provider 청구와 비교한다. 설치 상한을 바꾸고 적용할 때는 모델 연결과 backend별 업그레이드 절차를 따른다.

확인

변경 전후 동일한 checkpoint를 새 worker에서 복원해 turn 완료·memory.peak·OOM·디스크·inode·queue wait를 비교한다. 표의 숫자는 기재한 SDK·CLI·합성 transcript 조건에서만 관측됐으며 운영 환경·새 runtime의 실측을 대신하지 않는다.

자주 막히는 곳

transcript 상한만 올리고 메모리를 유지하면 재기동 후 recovery_required가 될 수 있다. requests를 limits보다 작게 하는 오버커밋과 세션 크기별 Pod 크기는 현재 지원하지 않는다.

되돌리기

새 launch에 적용할 메모리·slot·노드 수를 이전 값으로 되돌린다. 이미 만들어진 workspace의 byte quota를 임의로 바꾸거나 volume을 지우지 않는다. quota 계약 변경은 workspace 이전을 따른다.

다음에 읽을 곳

저장소와 상한, 지표 수집, 격리 설명.

이 페이지