← 목록
기타 2026-07-31 6KB 읽기 5분

주문콘솔 문자열 핸들 누수 수리 (exit43 크래시 대응)

개요

주문콘솔.한선(포트 9869, 3창 병렬 발사 오케스트레이터)이 2초 폴링(/상태·/로그·/분석)으로 매 요청 로그 파일 전체를 읽기()+분리() 하면서 crownyc VM의 문자열 핸들 풀(상한 480,000)을 고갈시켜 exit 43으로 크래시하던 문제를 수리했다.

원인

  • OC_로그조회(N)/로그 요청마다 타이밍로그 파일 전체를 읽기()분리(본문,"\n").
  • OC_분석()/분석 요청마다 같은 파일을 재파싱(분리() × 줄수 × 필드).
  • 2초 폴링 UI가 두 라우트를 계속 호출 → 요청당 수백~수천 개 문자열 핸들 신규 생성,
메모리복원/맵힙복원류로도 문자열 풀은 회수되지 않아(가드레일 §장수서버 exit43 함정) 8,000여 요청 만에 90% 경고([STR] 조기경고) 후 곧 상한 초과로 크래시.

수리 내용

파일: /Users/ef/CrownyDoc/projects/kps-trading-tool/주문콘솔.한선

  1. 인메모리 로그 링버퍼 (OC_로그버퍼, 상한 200) 추가.
- OC_로그버퍼추가(줄): 200 초과 시 앞부분을 잘라 재구축(회전). - OC_로그()가 파일 append와 동시에 링버퍼에도 반영. - /로그 라우트(OC_로그조회)는 이제 이 링버퍼만 조립 — 읽기()·분리() 호출 0회.

  1. 인메모리 분석 카운터 8종(`OC_편차합/편차수/편차최대/지연합/지연수/지연최소/지연최대/
발사완료수/발사요청수) 추가. OC_로그()` 안에서 이벤트 종류(발사요청/발사완료/발사편차)에 따라 즉시 갱신. - /분석(OC_분석)은 이제 이 카운터만으로 평균/최대/체결률/판정을 계산 — 파일 재파싱 0회.

  1. 부팅 1회 한정 복원 OC_카운터부팅복원()주문콘솔시작()에서 딱 1번 호출, 기존
로그 파일 꼬리를 읽어 링버퍼/카운터 시드. 실패해도 0에서 시작(크래시 안 함). - ★1차 구현 버그(실측으로 발견·즉시 수정): 파일 전체를 분리()하면 재기동을 거치며 수천 줄로 자란 append-only 로그에서 배열힙 O(n) 폭증 함정(가드레일 §루프내배열반환함수 힙고갈)에 걸려 TCP대기 도달 전 무한 스핀(bind 자체를 못 함, 100% CPU busy-loop)이 재현됨. 수정: 파일 전체가 아니라 꼬리 8000자만 부분()으로 잘라 그 구간만 분리·파싱.

  1. OC_GC주기(문자열GC 호출 간격) 200 → 최종 20으로 강화(1차 50 시도 시 3000요청
부하시험에서 90% 경고 1회 재발 확인 → 20으로 재강화 후 재검증에서 경고 0건).

  1. 파일 append는 그대로 유지(덧쓰기(OC_타이밍로그, ...), 감사추적 정본) — 읽기만 제거.
  1. /상태 라우트는 이미 OC_JSON필드추출(인덱스 탐색 기반)만 쓰고 있어 분리() 남발이
없었음 — 추가 수정 불필요.

검증 결과

  • 컴파일: ./hanseonc_high 주문콘솔.한선 > /tmp/주문콘솔.toau — 경고 0, 20,912 큐브 생성.
  • 재기동: 기존 stale 프로세스(포트 9869 점유) 확인 후 종료 → `LIVE=0 CROWNY_TCP_LOOPBACK=1
nohup ./crownyc run /tmp/주문콘솔.toau &로 드라이런 기동. [주문콘솔] 기동 — 포트 9869 (LOOPBACK=1) 발사대상=3창` 로그로 정상 바인딩 확인.
  • 부하시험(최종본, /상태·/로그·/분석·/진입 각 750회씩 순환, 총 3000요청):
  • 실패 0건(이전 1차 시도에서는 부팅복원 무한스핀 버그로 전체 rc=7 실패 — 위 4)에서 수정)
  • [STR] 조기경고 0건, 핸들 상한 0건
  • 프로세스 생존 확인(pgrep/ps로 시험 전후 동일 PID 유지)
  • 응답시간: 합계 285,288ms / 3000건 = 평균 약 95ms, 최대 885ms
  • (참고: 시험 중간에 한 차례 시스템 전역에서 무관한 다수 crownyc 프로세스가 SIGKILL (Code Signature Invalid)로 동시에 죽는 외부 이벤트가 있었음 — 다른 세션이 공유 crownyc 바이너리를 재빌드하며 이미 로드된 프로세스들의 코드서명이 무효화된 것으로 추정. 우리 서버(9869)도 그 파도에 함께 죽었으나 이는 이번 수리 대상 결함과 무관한 인프라 이벤트 — 재기동 후 재시험에서는 이 현상 없이 정상 완주)
    • /분석 정합성: {"발사요청수":2295,"발사완료수":2296,...} — 카운터가 1:1에 근접
    (부팅 시 8000자 꼬리 복원 시 경계선 한 줄이 발사완료 이벤트로 중복 카운트될 여지가 있는 구조적 여유값, 치명적 오차 아님). 판정 로직(편차평균 ≤100→티 등)도 파일 기반 구현과 동일 임계값 유지.

    관련 파일

    • /Users/ef/CrownyDoc/projects/kps-trading-tool/주문콘솔.한선 (수정)
    • /tmp/주문콘솔.toau (최신 컴파일 산출물)
    • /tmp/kps/주문타이밍.psv (append-only 로그, 삭제하지 않음)
    • 참고 관용구(읽기만): 모의트라도서버.한선, 브라우저어댑터.한선, 관제기.한선

    잔여 이슈

    1. /분석 발사요청수/발사완료수 ±1 오차: 부팅 복원 시 8000자 꼬리를 자르는 경계에서
    한 줄이 걸치면 이벤트가 중복/누락될 수 있음. 실사용에 지장 없는 수준(오차 1건)이지만 완전 정밀화하려면 꼬리 절단 지점을 줄 경계(\n 위치)로 스냅하는 로직 추가 여지 있음.
    1. 링버퍼 200줄 상한: /로그가 파일 전체가 아니라 최근 200줄만 반환(요구사항 부합,
    UI가 최근 로그만 필요하다는 전제). 감사용 전체 이력 조회가 필요하면 파일을 직접 열람.
    1. 외부 이벤트 관찰: 부하시험 중 공유 crownyc 바이너리 재빌드로 추정되는 시스템
    전역 SIGKILL(Code Signature Invalid) 동시다발 크래시를 목격(우리 서비스 결함 아님). 여러 세션이 동시에 같은 바이너리 경로를 재컴파일하는 관행이 계속되면 다른 장수 서버도 같은 이유로 무작위 시각에 죽을 수 있음 — 인프라 차원의 별도 이슈로 공유 필요(이번 작업 범위 밖, gateway.yaml 등 공유 인프라는 무접촉 원칙에 따라 이번 세션에서 손대지 않음).
    1. LIVE=1 실주문 경로는 이번 작업에서 손대지도 검증하지도 않음(요구사항대로 드라이런만).