Linux에서 오래된 파일 잠금 처리 및 클러스터의 강력한 사용

Linux에서 오래된 파일 잠금 처리 및 클러스터의 강력한 사용

cron을 통해 주기적으로(몇 분마다) 실행되는 스크립트가 있습니다. 그러나 스크립트는 여러 번 병렬로 실행되지 않으며 때로는 약간 더 오래 걸리므로 일부 잠금을 구현하고 싶습니다. 즉, 이전 인스턴스가 이미 실행 중인 경우 스크립트가 일찍 종료되는지 확인하십시오.

다양한 제안을 바탕으로 다음과 같은 자물쇠가 생겼습니다.

lock="/run/$(basename "$0").lock"
exec {fd}<>"$lock"
flock -n $fd || exit 1

스크립트의 다른 인스턴스가 아직 실행 중이면 종료 1을 호출해야 합니다.

이제 문제는 스크립트가 종료된 후에도 오래된 잠금이 남아 있는 경우가 있다는 것입니다. 이는 사실상 cron이 다시는 실행되지 않음을 의미합니다(다음 재부팅 때까지 또는 잠긴 파일이 삭제될 때까지). 이는 확실히 제가 원하는 것이 아닙니다.

lslocks 명령이 기존 파일 잠금을 나열할 수 있음을 발견했습니다. 이는 다음을 보여줍니다.

(unknown)        2732 FLOCK        WRITE 0     0   0 /run...                                                                 

프로세스(이 경우 2732)는 더 이상 존재하지 않습니다(예: ps aux). 전체 파일 이름(예: /run...)이 표시되지 않는 이유도 확실하지 않습니다. lslocks에는 --notrucate 인수가 있는데, 이는 파일 이름이 잘리는 것을 피할 수 있는 것처럼 들리지만 출력은 변경되지 않고 여전히 /run...입니다.

그래서 여러 가지 질문이 있습니다.

  • 이러한 잠금이 있는 이유는 무엇이며 클러스터의 잠금이 프로세스 수명 주기 외부에 존재하게 만드는 상황은 무엇입니까?
  • lslocks가 전체 경로/파일 이름을 표시하지 않는 이유는 무엇입니까?
  • 이를 방지하고 스크립트 잠금을 더욱 강력하게 만들 수 있는 좋은 방법이 있습니까?
  • 다시 시작하지 않고 오래된 잠금을 정리할 수 있는 방법이 있습니까?

답변1

잠금은 flock파일 설명 개체와 연결되어 있으며 파일 설명을 참조하는 모든 파일 설명자가 닫히면 사라집니다.foll.2 맨페이지).

파일이 여전히 잠겨 있으면 파일 설명자는 원래 프로세스나 하위 프로세스에서 여전히 참조되는 것이 거의 확실합니다(원본 프로세스 계층 외부에 참조를 전파하기 위해 전달하는 파일 설명자와 같은 것을 사용하지 않는다고 가정).

나는 그것을 확인하는 것이 좋습니다 sudo fuser $lock_path.

이 문제를 해결하기 위해 저는 두 가지 방법을 알고 있습니다. 즉, 쉘이 하위 프로세스가 파일 설명자를 상속하지 못하도록 막거나, 여전히 파일 설명자를 참조하는 모든 프로세스를 종료하는 것입니다 fuser -k ....

표시되는 경로는 정보를 수집 lslocks하는 데 사용되므로 불완전합니다 /proc/locks. 파일에는 마운트 지점의 식별자와 잠금을 획득한 프로세스에 대한 정보가 포함되어 있지만 잠금 파일에 대한 경로는 포함되어 있지 않습니다. 프로세스를 확인할 때 잠금을 유지하는 파일 설명자를 찾을 수 없으면 lslocks마운트 지점을 인쇄하는 것으로 돌아갑니다.

답변2

내 무리에게도 같은 문제가 있었습니다. fusion 사용에 대한 thejh의 제안이 문제를 찾는 데 도움이 되었습니다. 클러스터와 함께 실행한 명령이 백그라운드에 남아 있는 하위 프로세스를 시작한 것으로 나타났습니다. 따라서 원래 명령이 완료되더라도 하위 프로세스가 잠금을 보유하고 있으므로 Flock은 파일을 잠금 해제하지 않습니다.

해결책: 무리 --닫기

"manflock"은 --close가 "명령을 실행하기 전에 잠금을 유지하는 파일 설명자를 닫습니다. 이는 명령이 잠금을 유지해서는 안 되는 하위 프로세스를 생성하는 경우 유용합니다."라고 말합니다.

이것은 내 문제를 완전히 해결했습니다.

답변3

이제 스크립트가 한 번만 실행되도록 하는 완전히 다른 방법을 사용하여 이 문제를 해결했습니다. 이것은 내 원래 질문에 대한 답변은 아니지만 다른 사람에게 도움이 될 수 있도록 여기에서 공유하겠습니다.

이제 pgrep을 사용하여 동일한 이름으로 실행 중인 프로세스 수를 확인하고 있습니다. 이 가능성은 트위터에서 나에게 지적되었습니다. 내 생각에 이 접근 방식의 유일한 단점은 동일한 이름을 가진 여러 스크립트가 있으면 방해가 될 수 있다는 것입니다. 그러나 이는 충분히 구체적인 스크립트 이름을 사용하면 피할 수 있습니다.

이것은 내가 사용하는 코드입니다:

PNAME="$(basename "$0")"
if [[ "$(pgrep -c -u $USER $PNAME )" -ne 1 ]]; then
    exit 1
fi

관련 정보