5.2 KiB
5.2 KiB
51124 먹통: 48시간 코드 차분 기반 원인 확정 리서치
작성일: 2026-03-04
범위: rb8001, robeing-gateway, robeing-monitor, skill-email, skill-embedding, skill-rag-file 최근 48시간 커밋/디프
목표: 51124 CPU 폭주/먹통의 원인을 코드 근거로 확정하고, 재발 방지 해법을 운영 관점으로 고정
1. 결론(확정)
- 24 서버 먹통의 직접 경로는
INTENT_ENGINE=graph+INTENT_USE_LANGGRAPH=true활성 시 의도 분류 워크플로우 내부 재진입 구조다. - 재진입 지점은
IntentGraph.detect_with_workflow()→ LangGraphclassify_intent_node()→IntentGraph.detect()재호출로 확인된다. - 23 서버가 같은 증상을 재현하지 않은 이유는 임시복구 시
.env에서INTENT_ENGINE=v1,INTENT_USE_LANGGRAPH=false로 강제 다운그레이드했기 때문이다.
2. 근거(코드/문서)
2.1 48시간 주요 변경
rb80013532600:docker-compose.yml기본값이INTENT_ENGINE=v1->graph로 변경됨.rb80011f39d08:/api/message응답 후 자기개선 아티팩트 DB 기록 경로 추가(부하 증가 요인).robeing-gateway5b97bea: 프록시가 method/body/content-type 전달하도록 변경(이전보다 실제 경로 실행률 상승).robeing-monitor1221596:/health호환 엔드포인트 추가(먹통 직접 원인으로 보기 어려움).
2.2 재진입(재귀) 경로
rb8001/app/services/brain/intent_graph.py:39-41INTENT_USE_LANGGRAPH=true면detect()가detect_with_workflow()를 호출.
rb8001/app/services/brain/intent_graph.py:65detect_with_workflow()가 LangGraph workflowainvoke실행.
rb8001/app/services/brain/intent_langgraph_workflow.py:49-60classify_intent_node()내부에서 새IntentGraph생성 후intent_graph.detect(message, context)재호출.
- 위 3개가 결합되어, 워크플로우 내부 분류 노드가 다시 워크플로우 진입 경로를 호출하는 구조가 성립한다.
2.3 23/24 차이의 확정 근거
DOCS/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md:43-49- 51123 임시복구에서
INTENT_ENGINE=v1,INTENT_USE_LANGGRAPH=false적용 기록이 명시됨.
- 51123 임시복구에서
rb8001/.env:185-188- 동일 임시복구 성능 오버라이드가 실제 파일에도 존재.
- 따라서 같은 코드 베이스라도 23은 재진입 경로를 비활성화했고, 24는 기본
graph경로를 타서 증상이 확대될 수 있다.
2.4 외부 근거(공식 문서)
- LangGraph는 종료 조건 없이 그래프를 순환 실행하면
GRAPH_RECURSION_LIMIT오류가 발생할 수 있음을 명시한다. - Python은 재귀 깊이에 한계가 있고, 한계를 넘으면
RecursionError가 발생한다(재귀 경로가 안전하지 않다는 일반 규칙). - Docker
restart정책(always/unless-stopped)은 프로세스가 비정상 종료될 때 컨테이너를 반복 재기동한다.
3. 원인/비원인 구분
| 구분 | 항목 | 판정 | 이유 |
|---|---|---|---|
| 원인 | 의도 분류 워크플로우 재진입 구조 | 확정 | 코드 호출 체인이 직접 닫힌 루프를 형성 |
| 증폭 | /api/message 자기개선 DB 기록 추가 |
확정 | 요청당 DB 작업/연결 증가 |
| 증폭 | gateway 프록시 body/header 전달 확대 | 확정 | 기존 차단/오류 경로가 실제 실행으로 전환 |
| 비원인 | robeing-monitor /health 추가 |
제외 | 라우트 1개 추가로 CPU 폭주 구조가 생기지 않음 |
| 비원인 | RAM 부족 | 제외 | 기존 관측값 기준 swap/OOM 근거 없음 |
4. 해결책(정확/우선순위)
P0 즉시(운영 보호)
- 24 서버 배포 전 기본값을 재진입 없는 안전값으로 고정:
INTENT_ENGINE=v1INTENT_USE_LANGGRAPH=false
- 적용 후 30분 관찰 기준:
- 컨테이너
Restarting0회 python main.pyCPU 지속 고점 급등 재발 없음
- 컨테이너
P1 구조 수정(근본)
IntentGraph.detect()에 워크플로우 내부 호출 구분 플래그를 추가해 재진입 차단.- 또는
classify_intent_node()가IntentGraph.detect()가 아닌 전통 분류 함수만 직접 호출하도록 분리. - 회귀 테스트 추가:
- "workflow classify node가 detect_with_workflow를 다시 호출하지 않는다" 단언 테스트.
P2 검증 고정(재발 방지)
- 배포 파이프라인에 스모크 테스트 추가:
INTENT_ENGINE=graph상태에서 단일 메시지 처리 시 호출 깊이/시간 상한 검증.
- 런타임 가드:
- 의도 분류 단계 실행 횟수 카운터를 요청 단위로 기록, 임계 초과 시 즉시 오류/중단.
5. 운영 판정 기준
- 완료 판정은 "응답 속도"가 아니라 "먹통 재발 차단"이다.
- 아래를 동시에 만족해야 완료:
- restart loop 0회
- 운영자가 전체 컨테이너 강제중지 없이 장애 제어 가능
- 09:00~10:00 주요 스케줄 구간에서 CPU 급등/응답 중단 없음