우분투 실전 명령어 | flock으로 중복 실행 잠금
서버에서 같은 스크립트가 겹쳐 실행되면 로그가 꼬이거나 데이터가 중복 저장되는 문제가 자주 납니다. 이럴 때 flock으로 잠금을 걸어 두면 중복 실행을 깔끔하게 막을 수 있습니다.
언제 쓰는가
- 크론이 1분마다 도는데, 이전 실행이 아직 안 끝날 수 있을 때
- 배치 스크립트가 API 호출이나 파일 쓰기를 해서 중복 실행이 치명적일 때
- 장애 대응 스크립트를 수동으로 다시 실행할 때 기존 프로세스와 충돌을 피하고 싶을 때
바로 쓰는 명령어
# 한 줄 잠금 실행: 이미 실행 중이면 즉시 종료
flock -n /var/lock/sync-job.lock /usr/local/bin/sync-job.sh
# Bash 스크립트 내부에서 FD 9 잠금 사용
exec 9>/var/lock/report.lock
flock -n 9 || { echo "이미 실행 중"; exit 1; }
./generate-report.sh
# 잠금 대기 후 실행(최대 30초)
flock -w 30 /var/lock/backup.lock /usr/local/bin/backup.sh
# systemd-run으로 테스트 실행
systemd-run --unit flock-test --wait /usr/bin/flock -n /var/lock/demo.lock /bin/sleep 20
핵심 옵션/패턴
- -n: 잠금을 못 잡으면 기다리지 않고 바로 실패
- -w 초: 지정한 시간만큼 잠금을 기다림
- 파일 잠금 경로는 보통 /var/lock 또는 /tmp를 사용
- 스크립트 내부 FD 잠금 패턴은 명령 묶음 전체를 보호하기 좋음
# 권장 패턴: 잠금 + 종료 시 자동 해제
(
flock -n 200 || exit 1
/usr/local/bin/task-a
/usr/local/bin/task-b
) 200>/var/lock/pipeline.lock
명령 출력 예시
$ flock -n /var/lock/sync-job.lock /usr/local/bin/sync-job.sh
$ echo $?
0
# 다른 터미널에서 같은 명령 재실행
$ flock -n /var/lock/sync-job.lock /usr/local/bin/sync-job.sh
$ echo $?
1
$ flock -w 3 /var/lock/backup.lock /usr/local/bin/backup.sh
flock: failed to get lock
$ echo $?
1
자주 하는 실수
- 잠금 파일만 만들면 잠금이 걸린다고 오해하는 경우
- flock 명령으로 실제 락을 획득해야 의미가 있습니다.
- -n을 쓰고 실패 처리 없이 다음 단계로 넘어가는 경우
- 잠금 실패 시 exit 1 같은 명시적 종료를 넣어야 안전합니다.
- 잠금 범위를 너무 좁게 잡는 경우
- 핵심 쓰기 구간만 잠그고 전후 로직은 열어 두면 여전히 경합이 생길 수 있습니다.
검증 방법
# 테스트용 스크립트
cat > /tmp/lock-demo.sh <<'EOF'
#!/usr/bin/env bash
exec 9>/tmp/lock-demo.lock
flock -n 9 || { echo "busy"; exit 1; }
echo "start $(date +%T)"
sleep 15
echo "end $(date +%T)"
EOF
chmod +x /tmp/lock-demo.sh
# 터미널 A
/tmp/lock-demo.sh
# 터미널 B (A 실행 중에)
/tmp/lock-demo.sh
- 터미널 B에서 busy가 출력되면 중복 실행 차단이 정상입니다.
- 크론 작업이라면 syslog 또는 journald에서 실행 간격과 실패 코드를 같이 확인합니다.
운영 팁
- 크론에서는 flock 실패를 오류가 아닌 정상 스킵으로 볼지 먼저 정책을 정하세요.
- 락 경로는 서비스별로 분리해서 이름을 고정하면 운영 중 추적이 쉽습니다.
- 장시간 작업은 -w를 짧게 두고 다음 스케줄로 넘기는 편이 전체 안정성에 유리합니다.
출처
- util-linux man pages
- Ubuntu Server Guide
- systemd man pages