프로그램이 실행되는 동안 어떻게 실시간 업데이트를 할 수 있나요?

프로그램이 실행되는 동안 어떻게 실시간 업데이트를 할 수 있나요?

Thunderbird나 Firefox와 같은 킬러 앱이 시스템 패키지 관리자를 통해 런타임에 어떻게 업데이트될 수 있는지 알고 싶습니다. 이전 코드가 업데이트되면 어떻게 되나요? 런타임에 스스로 업데이트되는 프로그램 a.out을 작성하려면 어떻게 해야 합니까?

답변1

일반 대체 파일

첫째, 파일 교체를 위한 몇 가지 전략이 있습니다.

  1. 열려 있는기존 쓰기 파일은 0 길이로 잘리고 새 콘텐츠가 기록됩니다. (덜 일반적인 변형은 기존 파일을 열고, 이전 내용을 새 내용으로 덮어쓰고, 파일이 더 짧은 경우 새 길이로 자르는 것입니다.) 쉘 용어로:

    echo 'new content' >somefile
    
  2. 제거하다이전 파일을 삭제하고 같은 이름의 새 파일을 만듭니다. 쉘 용어로:

    rm somefile
    echo 'new content' >somefile
    
  3. 임시 이름으로 새 파일을 작성한 다음이동하다새 파일을 기존 이름으로 변경합니다. 이동하면 오래된 파일이 삭제됩니다. 쉘 용어로:

    echo 'new content' >somefile.new
    mv somefile.new somefile
    

나는 이러한 전략들 사이의 모든 차이점을 나열하지는 않을 것이며 단지 몇 가지 중요한 것들만 언급할 것입니다. 정책 1을 사용하면 프로세스가 현재 파일을 사용하고 있는 경우 해당 프로세스는 업데이트될 때 새 콘텐츠를 보게 됩니다. 프로세스에서 파일 내용이 변경되지 않을 것으로 예상하는 경우 이로 인해 약간의 혼란이 발생할 수 있습니다. 이는 파일(예: lsof또는 에 표시되는 파일)을 여는 프로세스에만 관련됩니다. 문서를 여는 대화형 응용 프로그램(예: 편집기에서 파일 열기)은 일반적으로 파일을 열어두지 않고 "문서 열기" 작업 중에 수행합니다. "문서 저장" 작업 중 파일 바꾸기(위 전략 중 하나 사용)./proc/PID/fd/

정책 2와 3을 사용하면 프로세스에 파일이 열려 있는 경우 somefile콘텐츠 업그레이드 중에 이전 파일이 열린 상태로 유지됩니다. 전략 2를 사용하면 파일 삭제 단계에서 실제로는 디렉터리에 있는 파일 항목만 삭제됩니다. 파일 자체는 해당 파일을 가리키는 디렉토리 항목이 없는 경우에만 삭제됩니다(일반적인 Unix 파일 시스템에서는동일한 파일에 대한 여러 디렉토리 항목)그리고열려 있는 프로세스가 없습니다. 이를 관찰하는 방법은 다음과 같습니다. sleep프로세스가 종료될 때만 파일이 삭제됩니다 ( rm해당 디렉토리 항목만 삭제됨) .

echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .

전략 3의 경우 새 파일을 기존 이름으로 이동하는 단계에서는 기존 콘텐츠로 연결되는 디렉터리 항목을 삭제하고 새 콘텐츠로 연결되는 디렉터리 항목을 생성합니다. 이는 하나의 원자 작업으로 수행되므로 이 전략에는 한 가지 주요 이점이 있습니다. 프로세스가 언제든지 파일을 열면 이전 콘텐츠나 새 콘텐츠가 표시됩니다. 혼합된 콘텐츠를 얻거나 파일이 존재하지 않을 위험이 없습니다. 기존의.

실행 파일 교체

실행 중인 실행 파일을 사용하여 Linux에서 전략 1을 시도하면 오류가 발생합니다.

cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy

"텍스트 파일"이란 실행 가능한 코드가 포함된 파일을 의미합니다.알 수 없는 역사적 이유 때문에. 다른 많은 Unix 변종과 마찬가지로 Linux는 실행 중인 프로그램의 코드 덮어쓰기를 거부합니다. 일부 UNIX 변종에서는 이를 허용하므로 새 코드가 이전 코드를 근본적으로 수정하지 않는 한 충돌이 발생합니다.

Linux에서는 라이브러리를 동적으로 로드하는 코드를 재정의할 수 있습니다. 이를 사용하는 프로그램이 충돌할 수 있습니다. ( sleep시작 시 필요한 모든 라이브러리 코드를 로드하기 때문에 이를 관찰할 수 없을 것입니다 . 예를 들어 잠자기 후에 유용한 작업을 수행하는 보다 복잡한 프로그램을 사용해 보십시오 perl -e 'sleep 9; print lc $ARGV[0]'.)

인터프리터가 스크립트를 실행 중인 경우 인터프리터는 스크립트 파일을 정상적으로 열므로 스크립트를 덮어쓰는 것을 방지할 수 있는 방법은 없습니다. 일부 통역사는 첫 번째 줄 실행을 시작하기 전에 전체 스크립트를 읽고 구문 분석하고, 다른 통역사는 필요에 따라 스크립트를 읽습니다. 바라보다실행 중에 스크립트를 편집하면 어떻게 되나요?그리고Linux는 쉘 스크립트를 어떻게 처리합니까?자세한 내용은.

전략 2와 3은 실행 파일에도 안전합니다. 실행 중인 실행 파일(및 동적으로 로드된 라이브러리)은 파일 설명자가 있다는 점에서 열린 파일은 아니지만 매우 유사한 방식으로 동작합니다. 프로그램이 코드를 실행하는 동안에는 디렉토리 항목이 없더라도 파일은 디스크에 남아 있습니다.

업그레이드 신청

대부분의 패키지 관리자는 위에서 언급한 주요 이점이 있는 파일 교체 전략 3을 사용합니다. 즉, 어느 시점에서든 열려 있는 파일의 유효한 버전을 얻을 수 있다는 것입니다.

응용 프로그램 업그레이드 시 문제가 발생할 수 있습니다. 하나의 파일을 업그레이드하는 것은 원자성이지만 응용 프로그램이 여러 파일(프로그램, 라이브러리, 데이터 등)로 구성된 경우 전체 응용 프로그램을 업그레이드하는 것은 원자성이 아닙니다. 다음과 같은 일련의 이벤트를 고려해보세요.

  1. 애플리케이션 인스턴스가 시작되었습니다.
  2. 애플리케이션이 업그레이드되었습니다.
  3. 실행 중인 인스턴스 애플리케이션은 데이터 파일 중 하나를 엽니다.

3단계에서는 실행 중인 이전 버전의 애플리케이션 인스턴스가 새 버전의 데이터 파일을 엽니다. 이것이 작동하는지 여부는 응용 프로그램, 파일 유형, 파일 수정 정도에 따라 다릅니다.

업그레이드 후에도 기존 프로그램이 계속 실행되고 있음을 알 수 있습니다. 새 버전을 실행하려면 이전 프로그램을 종료하고 새 버전을 실행해야 합니다. 패키지 관리자는 일반적으로 업그레이드 시 데몬을 종료하고 다시 시작하지만 최종 사용자 애플리케이션은 영향을 받지 않습니다.

일부 데몬에는 데몬을 종료하고 새 인스턴스가 다시 시작될 때까지 기다리지 않고도(서비스가 중단될 수 있음) 업그레이드를 처리하는 특별한 절차가 있습니다. 이는 다음과 같은 상황에서 필요합니다.내부에, 종료될 수 없습니다. 초기화 시스템은 실행 중인 인스턴스 호출을 요청하는 방법을 제공합니다.execve새 버전으로 교체됩니다.

답변2

업그레이드는 프로그램이 실행되는 동안 실행될 수 있지만, 프로그램을 실행하는 동안 표시되는 내용은 실제로는 이전 버전입니다. 이전 바이너리는 프로그램을 닫을 때까지 디스크에 남아 있습니다.

설명하다:Linux 시스템에서 파일은 단지 inode일 뿐이며 여러 링크를 가질 수 있습니다. 예를 들어. 당신이 보는 것은 /bin/bash내 시스템의 링크뿐입니다. 링크에 대해 명령을 실행하여 inode 3932163링크가 연결된 inode를 확인할 수 있습니다. ls --inode /path파일(인덱스 노드)은 해당 파일을 가리키는 링크가 없고 어떤 프로그램에서도 사용되지 않는 경우에만 삭제됩니다. 예를 들어 패키지 관리자가 업그레이드되는 경우. /usr/bin/firefox, 먼저 링크를 해제(하드 링크 제거 )한 다음 다른 inode(inode의 새 버전 포함)에 대한 하드 링크 인 /usr/bin/firefox해당 파일이라는 새 파일을 생성합니다 . 이전 inode는 이제 사용 가능으로 표시되어 새 데이터를 저장하는 데 재사용할 수 있지만 디스크에 남아 있습니다(inode는 파일 시스템을 구축할 때만 생성되며 삭제되지 않습니다). 다음에 시작할 때 새 것이 사용됩니다 ./usr/bin/firefoxfirefoxfirefox

런타임에 자체적으로 "업그레이드"되는 프로그램을 작성하려는 경우 제가 생각할 수 있는 유일한 해결책은 자체 바이너리의 타임스탬프를 주기적으로 확인하고 프로그램 시작 시간보다 새로운 경우 자체를 다시 로드하는 것입니다.

답변3

Thunderbird나 Firefox와 같은 킬러 앱을 시스템 패키지 관리자를 통해 런타임에 어떻게 업데이트할 수 있는지 궁금합니다. 글쎄요, 이것은 잘 작동하지 않습니다...패키지 업데이트가 실행되는 동안 Firefox를 열어두면 매우 심각한 결함이 발생합니다. 때로는 강제로 종료하고 다시 시작해야 할 때도 있습니다. 너무 손상되어 제대로 종료할 수도 없기 때문입니다.

이전 코드가 업데이트되면 어떻게 되나요? 일반적으로 Linux에서는 프로그램이 메모리에 로드되므로 프로그램이 실행되는 동안 디스크의 실행 파일이 필요하거나 사용되지 않습니다. 실제로 실행 파일을 삭제할 수도 있지만 프로그램은 신경 쓰지 않아도 됩니다... 그러나 일부 프로그램에서는 실행 파일이 필요할 수 있으며 일부 운영 체제(예: Windows)는 실행 파일을 잠가서 삭제 또는 이름 변경을 방지합니다. / 프로그램이 실행되는 동안 이동합니다. Firefox는 실제로 매우 복잡하고 많은 데이터 파일을 사용하여 GUI(사용자 인터페이스) 구축 방법을 알려주기 때문에 충돌이 발생합니다. 패키지 업데이트 중에 이러한 파일은 덮어쓰기(업데이트)되므로 이전 Firefox 실행 파일(메모리 내)이 새 GUI 파일을 사용하려고 하면 이상한 일이 발생할 수 있습니다.

런타임에 스스로 업데이트되는 프로그램 a.out을 작성하려면 어떻게 해야 합니까? 귀하의 질문에 대한 답변은 이미 많습니다. 이것을 살펴보십시오: https://stackoverflow.com/questions/232347/how-should-i-implement-an-auto-updater 그건 그렇고, 프로그래밍에 관한 질문은 StackOverflow에서 가장 잘 질문됩니다.

관련 정보