0 이 문서의 목적 (중요)
이 문서는 메모가 아니다.
이번 “유령 데몬 사건”의 전 과정, 판단, 실체 규명, 최종 설계 결론을 다음에도 다시 헷갈리지 않기 위해 남기는 운영 메뉴얼이다.
- 감정/추측/기억에 의존하지 않는다
- 증거 기반 판단만 기록한다
- 다음에 같은 일이 발생하면 이 문서 그대로 따라 하면 끝나게 한다
1. 사건 요약
데몬이 죽지 않는 문제가 아니라,
유저 세션(pmaadmin)이 지속적으로 데몬을 재생성하고 있었다.
2. 처음 나타난 현상
3. 잘못된 가설들 (뻘짓 정리)
가설 1: DB 이벤트(event_scheduler)가 범인
event_scheduler는 ON이었지만 실제 EVENTS는 비어 있었음
→ 범인 아님
가설 2: 데몬 프로세스가 혼자 살아 있음
데몬을 kill 해도 다시 생김. 파일을 수정해도 영향 없음
→ 데몬은 원인이 아니라 결과물
가설 3: 파일에 exit 넣으면 데몬이 멈춘다
파일 정지는 미래 실행 차단일 뿐, 이미 떠 있는 데몬에는 영향 없음
→ 개념 혼동
4. 결정적 전환점
핵심 질문: "누가 실제로 DB에 INSERT를 치고 있는가?"
SHOW FULL PROCESSLIST;
1~2초 간격, 최소 10~20회 연속 실행 후 포착된 증거:
- User: pmaadmin
- Host: localhost
- Command: Query
- Info: INSERT INTO...
👉 진범 확정
5. 최종 실체 규명
진범
유저 세션 (웹 계층)
DB 계정: pmaadmin
php / phpMyAdmin / 웹 요청을 통해 매우 짧게 INSERT → COMMIT → 종료
데몬의 정체
데몬은 유령이다.
스스로 존재하지 않으며, 명령자가 살려내는 결과물일 뿐이다.
💡 왜 계속 안 잡혔으며, 왜 죽여도 안 됐는가?
스텔스성
INSERT가 찰나의 순간에 실행되고 사라짐. SHOW PROCESSLIST 한두 번으로는 "없는 것처럼" 보임.
무한 재생성
데몬을 죽이면 명령자(유저 세션)가 이를 감지하거나 재실행하여 새로운 PID로 다시 태어남.
"데몬을 못 죽인 게 아니라, 죽여도 계속 다시 만들어졌던 것"
8. 정답 구조 (원칙)
데몬은 관리 대상 X
쫓아다닐 필요 없음. 결과물일 뿐.
명령자가 핵심 통제 대상
실행, 중지, 재생성의 주체는 명령자다.
파일 레벨 제어
파일이 곧 실행 여부이자 신분증이다.
9. 파일 중지 가드 (Future Block)
<?php // DAEMON EXECUTION BLOCKED exit;
미래의 실행을 100% 차단하지만, 이미 떠 있는 데몬은 별도 사살 필요.
11. 고유 ID 전략
$DAEMON_ID = pathinfo(__FILE__, PATHINFO_FILENAME);
파일명이 곧 고유 ID다.
10. 대응 프로세스 & 13. 최종 원칙
🚀 사살과 재발 방지 순서
- 파일 무력화 (중지 가드 삽입 or 파일명 변경)
- 이미 떠 있는 데몬 1회 사살
- 이후 감시 (끝)
⚖️ 불변의 운영 원칙
- 데몬은 태어나지 못하게 한다.
- 이미 태어난 건 한 번만 죽인다.
- 모든 제어는 PHP 파일로 한다.
- 유저 세션은 실행만 하고 판단하지 않는다.
- 파일명이 곧 고유 ID다.
14. 이 문서의 의미
추측의 기록 ❌
감정의 기록 ❌
실체 규명과 정답 설계의 기록 ⭕
"다음에 같은 증상이 오면, 이 문서 1번부터 그대로 따라 하면 끝"