자식 프로세스로 MCP 스타일 도구를 호출하는 모든 OpenClaw 게이트웨이는 결국 EMFILE을 만난다. 운영체제가 악의적인 것이 아니라 병렬성 × 파이프·소켓·로그 파일이 프로세스당 파일 디스크립터 테이블을 예상보다 빨리 소모하기 때문이다. 2026년에는 경계형 워커 세마포어와 솔직한 ulimit -n 여유를 같은 runbook에 적고, 토큰 예산과 도구 스로틀 및 openclaw doctor 게이트웨이 진단과 맞추면 동시성 스파이크가 상류 장애로 위장되지 않는다.
실행 가능한 가이드라인: 8 GiB Mac mini에서 게이트웨이 워커당 기본 자식 병렬 8, HTTP 스택과 메트릭에 256 디스크립터 예약. 프로덕션 테넌트 전에 하루 약 $16.9 수준의 Apple 하드웨어 대여로 리허설하라.
프로세스 모델과 숨은 FD 소비
자식은 표준 스트림 세 벌을 상속하고 PTY를 연결하면 복제가 늘어난다. 모델 공급자 소켓, Prometheus 스크랩, 선택적 WebSocket 팬아웃, 로테이션 로그, SQLite/Redis가 더해진다. 단순 32-way 병렬만으로도 사용자 도구가 파일을 열기 전에 1000개 이상을 쓸 수 있다. 통합 채널마다 장수 연결 수를 설계 표에 적으면 메트릭 스크레이퍼와 큐 클라이언트가 같은 FD 예산을 다투는 상황을 줄인다.
워커 세마포어와 공정 큐
도구 실행기 주변에 계수 세마포어를 중앙집중화하고 exec 전에 획득, 시그널 취소를 포함한 해제 경로에서 반납한다. 테넌트 내에서는 FIFO를 우선하고 인시던트 브리지용 관리 작업에는 가중치를 둔다.
| 프로파일 | 병렬 상한 | 근거 |
|---|---|---|
| 파일 읽기 | 12 | Apple NVMe 큐 깊이 스위트 스팟 |
| 네트워크 크롤러 | 6 | TLS 소켓마다 추가 FD |
| CPU 컴파일 | 성능 코어의 2배 | 열 설계 전력이 먼저 한계 |
macOS 소프트·하드 한도
수정 전후로 launchctl limit maxfiles를 실행한다. 대화형 셸은 종종 소프트 256이고 서비스는 소프트 10240이 필요하다. 둘 다 runbook 첫장에 기록해 프로필만 고치는 실수를 막는다.
LaunchAgent plist SoftResourceLimits
plist의 SoftResourceLimits NumberOfFiles는 세마포어 수학에 20% 버스트 여유를 더한다. ThrottleInterval로 잘못된 설정 시 exec 폭주를 억제한다.
디스크립터 누수 빠른 탐지
소크 테스트 중 60초마다 lsof -p $GATEWAY_PID를 샘플링하고 CLOSE_WAIT 소켓을 비교한다. 열린 디스크립터가 소프트 한도 70%를 5분 넘기면 알람을 걸고 최근 세 배포 태그를 첨부한다.
IO 바운드 vs CPU 바운드
매니페스트에 io_bound와 cpu_bound를 태깅해 스케줄러가 다른 세마포어를 적용하게 한다. 단일 상한이면 셸 유틸이 긴 ffmpeg 작업 뒤에서 굶주린다.
큐 깊이와 백프레셔
gateway_tool_queue_depth 게이지를보내고 p95가 50개 대기를 10분 넘으면 병렬 또는 상류 처리량이 맞지 않다는 신호다. 구조화 로그에 큐 순번을 넣어 SSH 없이도 설명 가능하게 한다.
롤아웃 체크리스트
- 프로덕션 부모 PID에서 현재
ulimit -n스냅샷. - 스테이징에서 먼저 병렬을 낮추고 도구 p95 지연 측정.
- 72시간 누수 회귀가 없음을 증명한 뒤 소프트 한도 상향.
- doctor로 채널 연결 재검증.
공유 Mac mini 멀티테넌트
여러 팀이 한 호스트를 쓸 때 Unix 그룹이나 환경 네임스페이스로 세마포어를 분할해 폭주 테넌트가 전역 풀을 고갈시키지 않게 한다. 대화형 세션용 30% 이상을 예약하고 재무 보드에 인시던트 버퍼로 표기한다.
벤치 하네스 기대치
합성 하네스는 5분마다 병렬을 +4씩 올리며 CPU 패키지 전력과 팬 듀티를 기록한다. GPU 상주 세트와 도구 부하가 충돌하면 Apple Silicon은 더 빨리 서멀 스로틀한다.
스로틀·429 협응
높은 병렬은 상류 속도 제한을 증폭한다. 토큰 스로틀 가이드를 보라. 429가 치솟으면 백오프를 늘리기 전에 잠시 병렬을 낮추면 체감 지연이 양쪽 모두 개선된다.
관측 가능성과 온콜 플레이북
히스토그램에 exemplar를 붙여 동시 도구 수와 FD 사용을 연결하면 인시던트 지휘관이 첫 5분 안에 “도구 과다”와 “소켓 누수”를 구분한다.
샌드박스 상호작용
Seatbelt 프로필이 IPC용 FD를 복제하면 한도에 이중으로 잡힐 수 있다. 스테이징 게이트웨이에서 검증 후 프로덕션에서 캡을 강화한다.
문서 드리프트
도구 패밀리별 기본 세마포어를 단일 Markdown 표로 관리한다. 문서가 낡으면 운영이 누수 수정 대신 ulimit만 올리려 한다.
vnode 압력과 임시 디렉터리
/var/folders 아래에 스크래치 파일을 대량 생성하면 FD는 멀쩡해도 vnode 캐시가 먼저 고갈된다. CI에서 sysctl vfs.numvnodes를 모니터링하고 명시적 대량 추출이 아니면 작업당 10000개 파일 쿼터를 둔다.
kqueue 감시
워크스페이스를 kqueue로 보면 경로마다 디스크립터가 든다. 추적 파일이 5000을 넘으면 재귀 감시를 단일 루트로 접고 사용자 공간에서 필터링한다.
gRPC·HTTP/2 멀티플렉싱
멀티플렉스 스트림도 윈도우 버퍼를 쓴다. 연결당 outbound 스트림은 100 미만을 권장해 SETTINGS 프레임 churn이 효율 코어 CPU를 튀게 하는 일을 막는다.
Redis 연결 풀
중앙 큐는 스레드마다 Redis 연결을 열기 쉽다. 8 GiB 호스트에서는 공유 32 연결 풀로 제한하고 TLS 세션 재개를 확인해 재연결 폭풍 시 핸드셰이크가 FD에 곱슬지 않게 한다.
롤링 업그레이드 창
롤링 배포에서 구·신 바이너리가 겹치면 디스크립터가 잠시 두 배다. 유지보수 창에 소프트 한도 15%를 올리거나 두 스크랩 주기 동안 병렬을 줄인다.
지원 매크로
사용자가 “파일을 너무 많이 열었다”고 볼 때 매크로에 openclaw doctor, 세마포어 상한, plist 키를 넣는다. 성숙 배포에선 중복 티켓이 약 40% 줄었다는 사례가 있다.
용량 표 시작점
최악의 경우를 (workers × tools_parallel × (3 파이프 + 2 로그 + 2 소켓)) + fixed_overhead로 모델링한다. 8 워커에 병렬 8이면 사용자 작업 전에도 1500에 근접한다——plist 상한을 고르기 전 25% 버퍼를 더하고 분기마다 재검토한다.
재무 승인은 누수 수정 티켓과 짝을 이루어야 한다. 하드 한도만 올리는 것은 부채를 감사 시즌으로 미루는 것으로 보인다.
이 수치를 SLO 대시보드 옆에 붙여 대규모 론칭·컴플라이언스 감사·연휴 트래픽 스파이크·글로벌 벤더 유지보수 전에 “병렬 두 배” 요청이 거절되는 이유를 공유한다.
MacHTML의 Apple Silicon Mac mini 대여는 프로덕션에 가까운 launchd 상속, 현실적인 파이프 버퍼링, 조용한 지속 부하로 블랙프라이드 전 시그마 수학을 검증하기 좋다. 하루 약 $16.9로 재무는 용량 실험을 CapEx가 아닌 OpEx로 보며 엔지니어는 여전히 파일 테이블을 root 수준에서 들여다본다.
탄력 임대로 FD 회귀를 디버깅할 때 프로덕션형 게이트웨이를 다른 스쿼드가 의존하는 공유 스테이징을 건드리지 않고 격리 하드웨어에 복제할 수 있다.
실제 macOS에서 OpenClaw 병렬성 리허설
클라우드 Mac mini를 빌려 ulimit 변경, LaunchAgent plist, 세마포어 조정을 프로덕션급 부하로 검증하세요.