때로는 쉘 스크립트의 인스턴스가 한 번에 하나만 실행되는지 확인해야 합니다.
예를 들어, crond를 통해 실행되는 cron 작업은 기본적으로 잠금(예: 기본 Solaris crond)을 제공하지 않습니다.
잠금을 구현하는 일반적인 패턴은 다음과 같은 코드입니다.
#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then # 'test' -> race begin
echo Job is already running\!
exit 6
fi
touch $LOCK # 'set' -> race end
# do some work
rm $LOCK
물론 이러한 코드에는 경쟁 조건이 있습니다. 한 인스턴스가 파일에 액세스할 수 있기 전에 두 인스턴스의 실행이 3행 이후로 진행될 수 있는 시간 창이 있습니다 $LOCK
.
크론 작업의 경우 호출 사이에 몇 분의 간격이 있기 때문에 이는 일반적으로 문제가 되지 않습니다.
그러나 잠금 파일이 NFS 서버에 있는 경우와 같이 상황이 잘못되어 중단될 수 있습니다. 이 경우 여러 크론 작업이 차단되어 라인 3에 대기할 수 있습니다. NFS 서버가 다시 활성화되면놀라운 무리작업은 병렬로 실행됩니다.
온라인 검색에서 이 도구를 찾았습니다.잠긴 작동이것은 이 문제에 대한 좋은 해결책인 것 같습니다. 이를 사용하면 다음과 같이 잠금이 필요한 스크립트를 실행할 수 있습니다.
$ lockrun --lockfile=/var/tmp/mylock myscript.sh
래퍼에 넣거나 crontab에서 사용할 수 있습니다.
사용 가능한 경우 (POSIX)를 사용 하고 (BSD) lockf()
로 대체됩니다 . flock()
그리고 lockf()
NFS에 대한 지원은 비교적 광범위해야 합니다.
어떤 대안이 있습니까 lockrun
?
다른 cron 데몬은 어떻습니까? 합리적인 방식으로 잠금을 수행하기 위한 일반적인 크론드 지원이 있습니까? Vixie Crond(Debian/Ubuntu 시스템의 기본값)의 매뉴얼 페이지를 잠깐 살펴보면 잠금에 대한 정보가 전혀 나와 있지 않습니다.
lockrun
유사한 도구를 포함하는 것이 좋은 생각일까요?핵심 도구?
내가 보기엔 그것이 구현하는 테마가 다음과 매우 유사한 것 같습니다.timeout
, nice
그리고 친구들.
답변1
이는 두 작업이 모두 라인 3을 통과할 수 있는 위에서 설명한 경쟁 조건을 방지하는 쉘 스크립트를 잠그는 또 다른 방법입니다. 이 noclobber
옵션은 ksh 및 bash에서 작동합니다. set noclobber
csh/tcsh에 스크립트를 작성해서는 안 되므로 사용하지 마십시오 . ;)
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
YMMV는 NFS를 잠그지만(NFS 서버에 액세스할 수 없는 경우) 전반적으로 이전보다 더 강력해졌습니다. (10년 전)
동시에 동일한 작업을 수행하는 여러 서버의 크론 작업이 있지만 실제로 실행하려면 인스턴스가 하나만 필요한 경우 이와 유사한 작업이 적합할 수 있습니다.
저는 lockrun에 대한 경험이 없지만 스크립트가 실제로 실행되기 전에 잠금 환경을 미리 설정하는 것이 도움이 될 수 있습니다. 아니면 아닐 수도 있습니다. 래퍼의 스크립트 외부에서 잠긴 파일에 대한 테스트를 설정할 수 있으며 이론적으로 두 작업 모두에서 lockrun이 정확히 동시에 호출되면 스크립트의 "내부"와 동일한 경쟁 조건이 발생하게 됩니까? ? 해결책?
그럼에도 불구하고 파일 잠금은 시스템 동작을 거의 존중하며 실행 전에 잠긴 파일이 존재하는지 확인하지 않는 스크립트는 수행하려는 모든 작업을 수행합니다. 잠금 파일 테스트와 올바른 동작만으로 잠재적인 문제의 99%(100%는 아니더라도)를 해결할 수 있습니다.
잠금 파일 경쟁 조건이 자주 발생하는 경우 작업 타이밍이 올바르지 않은 등 더 큰 문제가 있음을 나타낼 수도 있고 간격이 작업 완료만큼 중요하지 않은 경우 작업이 데몬에 더 적합할 수도 있습니다.
다음과 같이 편집됨 - 2016-05-06 (KSH88을 사용하는 경우)
아래 @Clint Pachl의 의견에 따라 ksh88을 사용하는 경우 mkdir
대신 사용하십시오 noclobber
. 이는 잠재적인 경쟁 조건을 주로 완화하지만 완전히 제한하지는 않습니다(위험은 적음). 더 많은 정보를 원하시면 읽어주세요아래 Clint가 게시한 링크.
lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid
if ( mkdir ${lockdir} ) 2> /dev/null; then
echo $$ > $pidfile
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -rf "$lockdir"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi
그리고 추가 보너스로 스크립트에서 tmp 파일을 생성해야 하는 경우 lockdir
스크립트가 종료되면 해당 파일이 지워진다는 것을 알고 해당 디렉토리를 사용할 수 있습니다.
보다 현대적인 bash를 위해서는 상단의 noclobber 방법이 적합합니다.
답변2
나는 하드 링크를 사용하는 것을 선호합니다.
lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
echo locked
else
echo locked by $(<$lockfile)
rm $tmpfile
exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to
하드 링크는 NFS에서 원자적입니다.그리고 대부분의 경우,mkdir도 마찬가지. 실제 수준에서는 작동하거나 mkdir(2)
거의 link(2)
동일합니다. 더 많은 NFS 구현이 원자적 하드 링크보다는 원자적 하드 링크를 허용하기 때문에 저는 하드 링크를 사용하는 것을 선호합니다 mkdir
. 최신 버전의 NFS를 사용하면 둘 중 하나를 사용하는 것에 대해 걱정할 필요가 없습니다.
답변3
나는 이것이 mkdir
원자적이라는 것을 알고 있으므로 아마도 다음과 같습니다.
lockdir=/var/tmp/myapp
if mkdir $lockdir; then
# this is a new instance, store the pid
echo $$ > $lockdir/PID
else
echo Job is already running, pid $(<$lockdir/PID) >&2
exit 6
fi
# then set traps to cleanup upon script termination
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15
답변4
간단한 방법은 다음과 같습니다.lockfile
일반적으로 procmail
패키지와 함께 제공됩니다.
LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0
# here the actual job
rm -f "$LOCKFILE"