Cron 중복 실행 해결

리눅스 서버에서 매시간, 매일 자동으로 실행되는 스케쥴 작업은 Cron 데몬을 사용하게 됩니다.  특히 매일 새벽에 자동 백업을 걸어놓는 경우에 많이 사용하는데, 간혹 백업이 2회씩 중복 실행되는 문제를 겪는 경우가 있습니다.  따라서 이러한 장애 발생의 원인과 해결 방법을 찾아보겠습니다.
– cron 로그를 통한 중복 실행 위치 찾기
– cron 중복 실행의 원인 파악
– anacron 은 왜 도입되었을까?

1. cron 로그를 통한 중복 실행 위치 찾기

– 먼저 모든 문제 해결의 시작은 해당 데몬의 로그를 확인해야 합니다.

grep daily /var/log/cron|tail -n100|more
Jul 14 03:01:01 localhost anacron[5092]: Will run job `cron.daily' in 10 min.
Jul 14 03:01:01 localhost anacron[5094]: Job `cron.daily' locked by another anacron - skipping
Jul 14 03:11:01 localhost anacron[5092]: Job `cron.daily' started
...
Jul 14 03:16:35 localhost run-parts(/etc/cron.daily)[5142]: starting backup.sh
Jul 14 03:35:11 localhost run-parts(/etc/cron.daily)[5212]: finished backup.sh
...
Jul 14 03:35:22 localhost anacron[5092]: Job `cron.daily' terminated (mailing output)
Jul 14 04:02:01 localhost CROND[5542]: (root) CMD (run-parts /etc/cron.daily)
...
Jul 14 04:08:08 localhost run-parts(/etc/cron.daily)[5542]: starting backup.sh
Jul 14 04:53:51 localhost run-parts(/etc/cron.daily)[5640]: finished backup.sh

– 로그 내용이 많아 분석이 어렵다면, Cron에 속한 프로세스의 시작/종료 로그를 제외하고 다시 확인합니다.

grep daily /var/log/cron|grep -vP 'starting|finished'|tail
Jul 14 03:11:01 localhost anacron[5092]: Job `cron.daily' started
...
Jul 14 04:02:01 localhost CROND[5542]: (root) CMD (run-parts /etc/cron.daily)

로그를 통해 매일 새벽에 자동 실행되는 ‘cron.daily’항목이 anacron[5092] , CROND[5542] 2개 프로세스에서 중복 실행되고 있는 것을 확인하실 수 있습니다.

2. cron 중복 실행의 원인 파악

– ps 명령으로 crond와 anacron 프로세스가 실행중인지 확인합니다.

ps -ef|grep cron
root      1599     1  0 Jul10 ?        00:00:00 crond

crond 는 실행중인데 anacron 은 보이지 않습니다.  그렇다면 anacron 은 다른 프로세스를 통해 실행되고 있다는 사실을 추정할 수 있습니다.

– 먼저 /etc/crontab  설정을 확인합니다.

# CentOS 6 기준, 정상적인 예제
cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

위 설정에서는 아무런 스케쥴 작업이 등록되지 않았습니다.

– 다음 제가 발견한 문제의 서버에서는 다음처럼 “02 4 * * * root run-parts /etc/cron.daily”항목이 선언되어 있었습니다.

# CentOS 6 기준, 잘못된 예제
cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

해당 설정은 모서버호스팅업체의 설치시 기본값인데, 아마 오래전부터 리눅스를 다뤘던 분들이 /etc/crontab 에 “02 4 * * * root run-parts /etc/cron.daily”항목을 수동으로 추가해두신 것 같습니다.  그러나 이렇게 하면 중복 실행이 되는 문제가 발생합니다.  그 이유를 알아보겠습니다.

– 먼저 cron 데몬에서 기본으로 로드하는 설정 파일 디렉토리인 cron.d 의 파일들을 확인합니다.

ls -l /etc/cron.d
-rw-r--r-- 1 root root 113 2013-11-23 21:43 0hourly
-rw-r--r-- 1 root root 235 2013-11-23 06:53 sysstat

– 가장 먼저 실행되는 0hourly 파일을 열어보면, 매시간 1분마다 “/etc/cron.hourly” 항목이 자동 실행되도록 설정되어 있습니다.

cat /etc/cron.d/0hourly
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
01 * * * * root run-parts /etc/cron.hourly

– /etc/cron.hourly 디렉토리를 확인합니다.

ls -l /etc/cron.hourly/
-rwxr-xr-x 1 root root 409 Nov 23  2013 0anacron

– 가장 먼저 실행되는 0anacron 파일을 열어보면,  오늘 날짜로 실행된 기록이 없을 경우 anacron 프로세스를 실행하여, 하루에 1회만 실행되도록 설정되어 있습니다.

cat /etc/cron.hourly/0anacron
...
if [ `date +%Y%m%d` = "$day" ]; then
 exit 0;
fi
...
/usr/sbin/anacron -s

– 마지막으로 anacron 프로세스 실행시 사용되는 /etc/anacrontab 파일을 확인해보면, “/etc/cron.daily”항목이 자동 실행되도록 설정된 것을 확인할 수 있습니다.

cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly

결론) CentOS 6의 경우 /etc/anacrontab 에 “cron.daily”항목이 이미 등록되어 있기 때문에, /etc/crontab 에 “cron.daily”항목을 수동으로 추가할 경우, 중복 실행되는 문제를 겪게 됩니다.

해결책) /etc/crontab 에 수동으로 추가된 아래 내용을 주석(#) 처리하고 문제가 해결되었습니다.  단, CentOS 6 이 아닐 경우 본 내용과 동일하지 않을 수 있으니 주의하셔야 합니다.

vi /etc/crontab
#01 * * * * root run-parts /etc/cron.hourly
#02 4 * * * root run-parts /etc/cron.daily
#22 4 * * 0 root run-parts /etc/cron.weekly
#42 4 1 * * root run-parts /etc/cron.monthly

참고) crontab 파일을 수정하면 cron 데몬에서 자동으로 로드됩니다.  따라서 cron 데몬을 따로 재시작하지 않아도 됩니다.

3. anacron 은 왜 도입되었을까?

뭔가 복잡해진 것 같은 anacron이 왜 시스템에 기본으로 내장되었을까요?  바로 다음처럼 크게 2가지 장점이 있기 때문입니다.

장점1)  작업이 시작되는 시간을 매번 0분~45분 지연시켜, 다른 서버들과 동일한 시간에 스케쥴 작업이 실행되는 부담을 줄입니다.

기존  cron 에서는 /etc/cron.daily 를 매일 새벽 4시 2분에 실행하는 것이 기본 값입니다.  만약 이 상황에서 rdate 로 시간 동기화를 time.bora.net 으로 걸어두었다면, time.bora.net 으로 새벽 4시 2분에 수많은 서버에서 동시 요청을 하기 때문에 거의 DDOS에 해당하게 되어 제대로 접속이 어려울 수 있습니다.  시간 동기화외에도 VM이나 공유 스토리지를 사용하는 경우에도 모든 장비가 동시간에 부하가 발생하는 작업을 처리하는 것은 매우 비효율적일 것 입니다.  이러한 문제를 해결하는데 도움이 됩니다.

0분~45분 지연 시간은 /etc/anacrontab  설정의 RANDOM_DELAY=45 항목을 통해 변경할 수 있습니다.

장점2) 서버의 정지/장애 등으로 인한 매일/매주/매월 자동 실행 작업의 누락 가능성을 줄여 줍니다.

이 부분은 자동 스케쥴러가 다소 복잡한 환경에서 유리하며, 보다 자세한 내용을 알고 싶으신 분들은 다음 블로그 글을 참고하시면 됩니다.

WEBDIR – [LINUX] anacron

 

마지막으로 anacrontab  파일 수정에 관한 내용은 아래 레드햇 기술문서를 참고하시면 됩니다.

https://access.redhat.com/documentation/ko-KR/Red_Hat_Enterprise_Linux/6/html/Migration_Planning_Guide/ch04s14.html