내 워드프레스 서버가 자꾸 느려지거나 이유 없이 과부하가 걸린다면? 단순히 플러그인을 삭제했다고 해서 끝난 게 아닐 수 있습니다. 많은 플러그인들이 삭제된 후에도 예약 스케줄러인 ‘크론(Cron)’ 작업을 서버에 고스란히 남겨두기 때문입니다.
플러그인 본체는 없는데 백단에서 혼자 주기적으로 돌며 서버 자원을 낭비하고 결국 시스템 과부하까지 유발하는 이 ‘유령 크론’의 정체는 무엇일까요? 이번 글에서는 유령 크론을 확실하게 찾아내고 안전하게 청소하는 방법을 정리해 드립니다.
플러그인은 지웠는데 크론(Cron)은 왜 남아있을까?
쉽게 말해 크론은 워드프레스가 알아서 일을 하도록 돕는 ‘예약 알람시계’입니다. “매일 자정에 통계 데이터 정산하기”, “매주 월요일에 임시 저장 글 삭제하기”처럼 특정 시간에 특정 플러그인 프로그램을 실행하라고 미리 장부에 적어두는 스케줄러죠.
문제는 플러그인을 정식으로 삭제해도, 이 ‘예약 알람’ 장부까지 깨끗하게 지워지지 않는 경우가 허다하다는 점입니다. 바로 아래 그림처럼 말이죠.

위 이미지처럼 플러그인 본체는 이미 깨지고 사라졌는데(DELETED), 서버의 예약 장부에 홀로 남겨진 크론은 눈치 없이 혼자 시계를 차고 서서 “저는 준비됐으니 언제든 일만 시켜주세요!”라며 대기하고 있습니다.
이처럼 할 일은 없는데 정해진 시간마다 할 일을 찾으며 갈 길을 잃고 낙동강 오리알이 된 녀석들을 우리는 ‘고아 크론(Orphan Cron)’ 또는 유령 크론이라고 부릅니다.
공식 개발 문서나 영어권에서는 이처럼 본체(플러그인)가 사라져서 공중에 붕 떠버린 예약 작업을 ‘오픈 크론(Orphaned Cron Tasks, 미삭제 크론)’이라는 정식 명칭으로 부릅니다. ‘미삭제 크론’이나 ‘존재하지 않는 훅(Hook)’, ‘유령 크론’이라고 칭하기도 합니다.
운영체제(OS)에서 부모 프로세스가 먼저 죽어버려 붕 떠버린 ‘고아 프로세스(Orphan Process)’와 완벽하게 같은 개념이라고 보시면 됩니다. 방치하면 서버 성능을 갉아먹는 주범이 됩니다.
Advanced Database Cleaner로 유령 크론 지우기
우선 서버 자원을 낭비하고 있는 유령 크론들을 당장 성불시켜 봅시다. Advanced Database Cleaner 플러그인을 이용하면 아주 안전하게 청소할 수 있습니다.

워드프레스 관리자 메뉴에서 [WP DB Cleaner] ➡️ [크론 작업] 탭으로 이동합니다.
무료 버전은 검색 기능이 제한되지만, [훅(Hook)] 컬럼을 누르면 이름순으로 정렬되어 찾기 쉽습니다.

이미 삭제하고 없는 플러그인의 흔적(예: wp_statistics_...)들을 리스트에서 모두 찾아 선택해 줍니다. 고아 크론이 5개나 있었습니다.
[일괄 동작] ➡️ [삭제] ➡️ [선택된 항목에 적용]을 눌러 깔끔하게 제거합니다.
[팁] ‘동작 없는 크론 작업’ 필터로 안전하게 지우기
크론 작업 목록 하단을 보면 “--개의 동작 없는 크론 작업[필터]“라는 항목이 보입니다.
이를 클릭하면 현재 사이트에서 삭제되었거나 비활성화된 플러그인의 크론 내역만 필터링해 보여줍니다. 이 목록 중에서 완전히 삭제한 플러그인의 흔적만 골라 지우면 훨씬 안전하게 청소할 수 있습니다. (🚨단, 잠시 비활성화해 둔 플러그인의 크론도 포함되어 있으니 나중에 다시 쓸 플러그인이라면 지우지 마세요!)
❓문득 드는 의문: “어차피 없는 작업인데 왜 서버 성능이 저하될까?”
여기서 궁금증이 하나 생깁니다. “어차피 코드가 없어서 실행되려다 바로 실패하고 끝날 작업 아닌가? 등록만 되어 있다고 해서 그게 그렇게 많은 자원을 낭비하나?”
이해를 돕기 위해 아주 쉬운 비유를 들어보겠습니다.
카페 알바생 퇴사 비유
- 내 생각: 카페 알바생이 퇴사했다. 출근부에 이름이 남아있긴 하지만, 어차피 안 올 사람이니 아침에 이름 한 번 슥 보고 넘어가는 게 무슨 큰 문제가 되겠나?
- 현실: 매일 아침 사장님이 출근부를 보며 “어? 이 알바생 왜 안 왔지? 어디 있지?” 하고 가게 안을 뒤지며 찾다가, 결국 전화까지 걸어 확인한다. 전화를 당연히 안 받으니 “좀 있다가 다시 걸어봐야지” 하고 이걸 매일, 매 순간 반복하며 정작 중요한 손님맞이에 집중하지 못하는 상황.
실제로 워드프레스 서버 내부에서는 이 ‘전화 걸어 확인하기’ 행위 때문에 크게 3가지 영역에서 심각한 자원 낭비가 발생하고 있습니다.
① 첫 번째 자원 낭비: 방문할 때마다 일어나는 DB 조회 (체크 오버헤드)
워드프레스 크론(WP-Cron)은 리눅스 서버 자체의 크론과 달라서 스스로 작동하지 못합니다. “방문자가 내 사이트에 접속할 때만” 작동하는 ‘가짜 알람시계’ 구조입니다.
방문자가 내 블로그 글을 읽으려고 들어오는 그 순간, 워드프레스 시스템(코어)이 등 뒤에서 몰래 알람 장부를 펼쳐봅니다. 이 과정에서 메인 글을 보여주기 전에 DB의 wp_options 테이블로 달려가 크론 장부를 통째로 불러옵니다. 유령 크론이 있으면 장부의 덩치가 커지고, 워드프레스는 이 유령 크론이 “지금 실행할 시간인가?”를 계산하기 위해 매 요청마다 쓸데없는 DB 조회와 CPU 연산을 무한 반복하게 됩니다.
② 두 번째 자원 낭비: “유령”이라서 일하지 못하고 무한 반복되는 대기 상태
정상적인 크론은 자기 시간이 되어 실행을 완료하면 장부에 ‘완료’ 신호(True)를 보내고 다음 스케줄로 넘어갑니다. 그래서 그날은 방문자가 아무리 많이 들어와도 더 이상 실행되지 않고 평화롭습니다.
하지만 유령 크론은 코드가 없기 때문에 성공 신호를 리턴하지 못합니다. 결국 장부에는 ‘대기/실패(Pending)’ 상태로 계속 묶여있게 됩니다. 이렇게 되면 바로 1초 뒤에 두 번째, 세 번째 방문자나 검색 로봇(봇)이 들어올 때마다 서버는 “아까 이거 성공 안 됐네? 다시 실행해!”라며 매 접속마다 유령을 끊임없이 호출하는 늪에 빠집니다.
③ 세 번째 자원 낭비: 쓸데없는 네트워크 요청과 에러 로그 폭탄 (Loopback Request)
워드프레스는 방문자가 글을 읽는 속도에 방해를 주지 않으려고, 크론을 처리할 때 서버가 자기 자신에게 비밀 요청(Loopback Request, 주로 wp-cron.php?doing_wp_cron=... 형태)을 따로 보냅니다.
코드가 없는 유령이라 성공 처리가 안 되기 때문에 매 방문자마다 루프백 요청을 서버에 무한 연타로 날리게 되어 PHP 프로세스가 마비됩니다.
정상적인 크론이라면 이 요청을 한 번 던지고 끝나겠지만, 코드가 없는 유령 크론은 완료 처리가 되지 않기 때문에 방문자가 올 때마다 새로운 웹 요청과 PHP 프로세스를 무한히 새로 생성해 냅니다. 이 행위 자체가 서버의 메모리를 계속해서 낭비하게 만듭니다.
게다가 함수를 찾는 데 실패할 때마다 서버 내부에 에러 로그(Fatal error 또는 Warning)를 계속 적어대는데, 이 로그 파일 크기가 수십~수백 MB까지 커지며 디스크 용량과 입출력(I/O) 자원까지 갉아먹습니다.
🧠조금 더 깊이 알아보는 가상 시나리오
만약 하루에 한 번 작동하는 통계 플러그인의 크론이 ‘오늘 밤 자정(00:00)’으로 예약되어 있다면 어떤 일이 벌어질까요?

- 시나리오 A (방문자가 드문 조용한 블로그): 밤 12시가 되어도 사이트가 잠들어 있어 크론은 실행되지 않습니다. 그러다 새벽 3시 반에 첫 방문자가 접속하는 순간 워드프레스가 깨어나 장부를 확인하고, “어? 자정에 실행했어야 하는 통계 작업이 밀렸네?”라고 인지하여 그제야 크론을 실행합니다. (이름은 ‘하루 한 번’이지만 방문자가 올 때까지 계속 밀립니다.)
- 시나리오 B (방문자가 끊이지 않는 대형 블로그): 자정 직후 첫 방문자가 들어오자마자 정확히 크론이 작동합니다.
여기서 유령 크론의 진짜 무서운 점이 등장합니다. 정상적인 플러그인이라면 위 시나리오처럼 한 번 실행되고 나면 장부에 다음 예약 시간을 갱신하므로 그날은 방문자가 아무리 많이 들어와도 조용합니다.
하지만 우리가 앞에서 이야기한 ‘삭제된 통계 플러그인의 유령 크론’은 상황이 다릅니다.
하지만 삭제된 플러그인의 유령 크론은 코드가 없으니 성공 신호(True)를 주지 못하고 실패/대기(Pending) 상태로 남습니다. 장부에는 여전히 “오늘 숙제 안 끝남” 상태로 고여있게 되죠. 이렇게 되면 그 뒤로 들어오는 수백, 수천 번째 방문자가 접속할 때마다 워드프레스는 매 접속마다 유령을 계속 호출하며 서버를 지치게 만듭니다.
❓ “그럼 방문자가 전혀 없다가 1년 후에 첫 방문자가 오면, 밀린 365번이 폭탄처럼 터지나요?”
아니요, 크론 알람시계 자체는 딱 ‘1번’만 실행됩니다. 장부에는 오직 “다음 실행 시간” 딱 하나만 기록되어 ‘과거인가 아닌가’만 판단하기 때문에, 1년 치 밀린 숙제를 누적해서 365번 연속으로 하지는 않습니다.

진짜 문제는 ‘지휘자(크론)’가 아니라 깨어난 ‘연주자(플러그인)’에게 있습니다.
- 케이스 1 (환율 수집 플러그인): 매일 정오에 외부 은행 API에서 환율을 가져오는 플러그인이 있다고 해봅시다. 1년 만에 방문자가 접속해 크론 알람이 딱 1번 울립니다. 이때 만약 플러그인이 ‘밀린 날짜만큼 반복 처리’하도록 허술하게 설계되어 있다면, 깨어난 플러그인이 스스로 판단합니다. “어? 나 1년 동안 환율 수집 안 했네? 지금 지난 365일 치 데이터를 한꺼번에 다 요청해서 DB에 집어넣자!” 크론은 1번 실행되었지만, 플러그인이 내부적으로 365일 치 외부 데이터를 한 번에 긁어오고 DB에 쓰고 저장하는 무거운 연산(Task)을 몰아서 처리하느라 서버가 엄청난 부하를 받게 됩니다.
- 케이스 2 (생일 쿠폰 발송 플러그인): 매일 자정에 생일인 회원에게 쿠폰을 보내는 플러그인입니다. 1년 만에 알람이 1번 울렸을 때, 허술하게 짜인 플러그인이라면 다급해집니다. “지난 1년 동안 생일이었던 회원들 명단 수천 명을 한꺼번에 추출해서, 이메일 수천 통을 지금 이 순간 동시에 발송하자!” 결과적으로 크론 알람은 단 1번 울렸을 뿐인데, 나비효과로 인해 서버가 순식간에 수천 통의 이메일을 발송하느라 CPU가 100%를 찍고 뻗어버리는 현상이 발생합니다.
마무리
사실 위의 1년 방치 예시는 크론의 중첩 메커니즘을 이해하기 위해 극단적으로 든 가상 시나리오입니다. 어차피 365일 동안 방문자가 하나도 없는 홈페이지는 없을 것입니다. 일반 방문자가 없더라도 크롤링 봇이라도 몇 개는 들어오기 때문이죠. 크론은 밀려있어도 알람 자체는 1번만 실행된다는 것, 그리고 Task가 쌓여도 실행 안 된 크론이 중첩되는 게 아니라는 점을 이해하기 위함이었습니다.

또한, 내 사이트에 유령 크론이 몇 개 남아있다고 해서 평상시에 당장 눈에 띄는 심각한 부하를 가져다주진 않습니다.
진짜 문제는 스노우볼입니다. 홈페이지가 오래 운영될수록 플러그인을 설치했다 지우는 일이 자연스레 늘어날 것이고, 그러다 보면 필연적으로 이런 유령 크론 찌꺼기들이 늘어나 부하가 점점 서서히 누적됩니다. 블로그가 성장할수록 방문자 트래픽도 늘어날 텐데, 방문자가 많은 사이트라면 이 사소한 체크 오버헤드가 거대한 부하로 돌변할 수밖에 없습니다.
특히 가장 중요한 것은 사이트가 오래 운영될수록 외부로부터의 공격 시도가 늘어난다는 점입니다. 무차별적인 ‘로그인 시도 공격’이나 ‘악성 봇 크롤링’이 들어올 때마다, 이 고아 크론들 때문에 워드프레스는 계속 “어? 실행 예정일이 과거네? 일단 프로세스 켜서 실행해!”*라며 매 트래픽 요청마다 백단에서 쓸데없는 무한 삽질을 반복하게 됩니다.
소중한 서버 자원이 엉뚱한 유령들에게 낭비되는 것을 막고 쾌적한 블로그 상태를 유지하기 위해, 정기적으로 데이터베이스와 크론 장부를 깔끔하게 청소해 주시는 것을 강력히 권장합니다.

