한선씨 게이트웨이 안정화 분석 — 크래시 규명 + 수정/재설계 판단
개요
라이브 :8080/:8443 한선씨 게이트웨이(crownyc run /tmp/게이트웨이통합.toau)가 수분마다 silent 크래시(로그 무에러, ~30초 자가복구)하는 문제를 코드 감사 + 그림자 포트(:8099) 실측으로 규명했다. 결론부터: crownyc VM은 정상(mind/auth/bank 7일+ 생존), 게이트웨이 고유의 두 버그가 원인이며, 재설계가 아니라 간단수정 3~4건으로 충분히 완성도 높게 안정화 가능하다.
1. 크래시 트리거 — 두 개의 독립 근본원인 (둘 다 실측 확인)
원인 A — SIGPIPE (즉발형, exit 141)
TCP쓰기(opcode 494 = raw write())/소켓보내기(opcode 375 = send(fd,...,0))가 쓰면서 커널이 SIGPIPE → 기본동작=프로세스 종료.crownyc.c opcode 494 write((int)va, str_ptr, str_len) — MSG_NOSIGNAL 없음.send(fd, s, slen, 0) — flag 0, MSG_NOSIGNAL 없음.signal() 호출은 오직 opcode 766(시그널)을 한선씨가 명시 호출할 때만(crownyc.c:12094~12099). 게이트웨이/프록시/통합 어디에도 시그널(13,1) 호출 없음.원인 B — 배열 힙 단조 누수 (지속형, exit 1)
줄분리/배열 리터럴이 1024큐브 블록을 영구 할당하는데 이 배열 힙은 GC가 전혀 회수하지 않음.crownyc.c:5259 case 405(ARRAY): int base = mem_count; mem_count += 1024; — 해제 경로 없음.str_gc(crownyc.c:1675)는 문자열 풀/힙 핸들만 compact. 배열 mem_count 블록은 GC 대상 아님.동안(참))엔 리셋 없음.줄분리 1 + _upstream분해 리터럴 1 + 도메인헤더목록 리터럴 1 ≈ 요청당 5~7 블록. (12,000,000-10,000)/~5120 ≈ 2,300~2,400 요청 → OOM. 초당 수건이면 수분 = 관측된 크래시 주기와 일치.꺼내(INDEX)가 보호영역 침범 → OOB 누적. crownyc.c:5289 OOB 누적 100회 → exit(1) "VM 즉시 중단"(stderr → nohup 로그 미포착, silent).왜 mind/auth/bank는 7일+ 생존 (모든 모순 해소)
단순 요청-응답형: (1) 응답 쓰기 도중 클라 RST를 거의 안 받음 → SIGPIPE 안 맞음. (2) 요청당줄분리/배열 리터럴 미사용 → mem_count 평탄. 게이트웨이만 스트리밍 프록시/정적 대용량 전송 중 브라우저 abort(reload/이탈/모바일 단절/stunnel 전달 reset)에 상시 노출 + 요청당 5~7 배열 누수. "단순 GET 폭격(:8099) 안 죽음"·"mind 7일 생존"이 정확히 설명됨 — 차이는 graceful FIN(생존) vs mid-write RST(SIGPIPE) + 배열 누적.2. 레거시 JS 게이트웨이 강건성 대조 — 한선씨가 빠뜨린 것
| # | 레거시 패턴 (lib/) | 한선씨 현황 | 크래시 직결 |
|---|---|---|---|
| a | proxy.js:157/206/379 .on('error') + Node SIGPIPE 자동무시 + gateway.js uncaughtException | write 반환값 미확인, SIGPIPE 가드 없음 | ★★★ (원인 A) |
| b | proxyRes.pipe(res) 백프레셔 자동 | 청크 직통 OK, 백프레셔 재시도 없음, 16KB concat 캡 | 부차 |
| - | (배열 힙 누수는 레거시엔 없는 VM 메모리 모델 문제) | str_gc가 배열 미회수 | ★★★ (원인 B) |
| c | cluster.fork × min(cpus,27) + 워커 재생성 | 단일 프로세스 → 1크래시=전체다운(워치독 의존) | 영향확대 |
| d | upstream http.Agent keepAlive | Connection:close 강제, 매 요청 신규 소켓 | 부차 |
| e | 'upgrade'→proxyWebSocket 양방향 pipe+timeout | 교대폴링(블로킹) | 부차 |
| f | Content-Length>maxBody 사전 413 | 본문 크기 상한 없음(회수 가드만) | 부차 |
| g | RETRYABLE×GET/HEAD×3회 | 재시도 없음, 즉시 502/503 | 품질 |
| h | path traversal baseDir 검증 | \x00BAD 마커로 일부 처리 | 보안 |
| i | trident 3진 헬스 게이트 | 헬스 상태머신 없음 | 품질 |
3. 핵심 판단 — 간단수정으로 충분한가?
결론: 재설계 불필요. 간단수정으로 충분히 완성도 높은 안정화 가능.
근거:
- crownyc VM은 장기구동 안정이 실증됨(mind 7일+, auth, bank). 게이트웨이가 죽는 건 VM 한계가 아니라 게이트웨이가 트리거하는 두 개의 특정 버그다.
- 두 버그 모두 국소적·근본적으로 막을 수 있다 — SIGPIPE는 1줄, 배열 누수는 요청 핸들러 전후 mem_count 스냅샷/복원 또는 줄분리 호출 최소화로 차단.
- 레거시의 cluster/H2/재시도/trident는 가용성·성능 향상이지 크래시 제거에 필수가 아니다. 안정화 후 점진 이식하면 된다.
두 프로그램 장단
- 레거시 JS: 강건(uncaughtException·error 이벤트·cluster·재시도·백프레셔로 구조적 면역). 단 nginx 대체 목표와 "한선씨=주언어" 헌법에 역행. 참조·이식 원천으로 가치.
- 한선씨 게이트웨이: 헌법 정합·자립. 단 VM 메모리 모델(배열 GC 부재)과 SIGPIPE 미가드라는 두 함정에 노출. 두 곳만 막으면 레거시 수준 안정성 도달 가능.
4. 우선순위 수정 계획
즉시 적용 가능한 간단수정 (크래시 박멸 — 이것만으로 충분)
S1 (★최우선, 근본·즉효) — SIGPIPE 면역
- 옵션 1(VM, 1줄, 전 서비스 면역):
crownyc.cmain 진입부(mem_init 직후, 13772 부근)에signal(SIGPIPE, SIG_IGN);. crownyc 재빌드만으로 게이트웨이 무수정 즉시 해결. - 옵션 2(VM, 더 정확): opcode 494/375/499의
write/send를MSG_NOSIGNAL+ 반환 -1·errno==EPIPE를 연결종료로 정상처리. - 옵션 3(한선씨 측, VM 미수정 시):
게이트웨이통합.한선엔트리 최상단에시그널(13, 1)(SIGPIPE,SIG_IGN) 호출 추가. → 재컴파일만으로 가능, 라이브 crownyc 무변경.
- 옵션 1(한선씨 측, 즉시):
게이트웨이통합.한선_요청처리에서 요청 문자열을 한 번만줄분리해줄들배열을 _호스트추출/_경로추출/_컨텐츠길이에 인자로 전달(현재 함수마다 재분리). 요청당 누수 5~7 → 2~3 블록으로 절반↓ (속도 지연, 근본 아님). - 옵션 2(VM, 근본): crownyc가 핸들러 콜프레임 종료 시 배열 힙을 자동 회수, 또는
mem_count 마커 저장/복원빌트인 opcode 노출. 게이트웨이 통합서버 루프가 _요청처리 전후로 mem_count 스냅샷·복원 → OOM 영구 차단. 권장(최소수정·근본).
- 한선씨
_프록시스트리밍/응답 송신부에서TCP쓰기/소켓보내기반환 -1 시 연결중단 분기(루프 탈출). SIGPIPE를 SIG_IGN으로 막은 뒤 EPIPE를 깨끗이 처리.
후속 강건성 격상 (선택 이식, 크래시 무관·가용성 향상)
- P1: 본문 크기 상한(레거시 f) — _요청누적읽기에 Content-Length>maxBody 413.
- P2: GET/HEAD 재시도 3회(레거시 g).
- P3: trident 3진 헬스 게이트(레거시 i) — Ta 서비스 503 차단·복구탐색.
- P4: 멀티워커(레거시 c) — 단일프로세스 → SO_REUSEPORT 다중 accept(VM 멀티프로세스 모델 검토 후).
5. 라이브 생존 재확인 (2026-06-10)
lsof 확인: :8080(crownyc 55453) :8443(stunnel 55452) :9100(crownyc 55455) 모두 LISTEN. 백엔드 mind(7750, crownyc 22396, "2 6월26" 다일 uptime) :9400(bank) :9401(auth) ALIVE. 재현은 전부 그림자 :8099 / /tmp/*.한선에서만 수행, 잔류 프로세스 0. 라이브 무접촉 유지.관련 파일
- 한선씨:
/Users/ef/crowny-gateway/한선게이트웨이/게이트웨이통합.한선,프록시.한선 - 컴파일본:
/tmp/게이트웨이통합.toau - VM 소스(수정 대상):
/Users/ef/CrownyOS/crownyc/crownyc.c— 494/375/499(write/send), 5259(ARRAY), 5289(OOB exit), 1675(str_gc), 12094(시그널 opcode), main 13772 - 레거시 참조:
/Users/ef/crowny-gateway/lib/{gateway.js,proxy.js,trident.js,middleware.js,shield.js}
잔여 이슈
- crownyc.c SIGPIPE SIG_IGN + 배열 힙 GC/콜프레임 회수 패치는 VM 재빌드 수반 → VM 담당 트랙에서 라이브 무중단 절차로 적용 권장(이 분석은 비파괴 전용).
- S1(옵션3)+S2(옵션1) 한선씨측 즉시수정은 게이트웨이 세션이 바로 적용 가능.