프로그램이 실행되는 동안 실시간 업데이트를 수행하는 것이 어떻게 가능합니까?

프로그램이 실행되는 동안 실시간 업데이트를 수행하는 것이 어떻게 가능합니까?

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

"텍스트 파일"이란 실행 가능한 코드가 포함된 파일을 의미합니다.모호한 역사적 이유로. 다른 많은 유닉스 변종과 마찬가지로 Linux는 실행 중인 프로그램의 코드를 덮어쓰는 것을 거부합니다. 몇몇 유닉스 변형에서는 이를 허용하므로 새 코드가 이전 코드를 철저하게 수정하지 않는 한 충돌이 발생합니다.

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파일(inode)은 해당 파일을 가리키는 링크가 없고 어떤 프로그램에서도 사용되지 않는 경우에만 제거됩니다. 패키지 관리자가 업그레이드되는 경우. /usr/bin/firefox, 먼저 링크를 해제한 다음(하드 링크 제거 ) 다른 inode(새 버전이 포함된 inode) 에 대한 하드링크인 /usr/bin/firefox새 파일을 생성합니다 . 이전 inode는 이제 사용 가능으로 표시되어 새 데이터를 저장하는 데 재사용할 수 있지만 디스크에 남아 있습니다(inode는 파일 시스템을 구축할 때만 생성되며 삭제되지 않습니다). 다음에 를 시작할 때 새 항목이 사용됩니다./usr/bin/firefoxfirefoxfirefox

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

답변3

Thunderbird나 Firefox와 같은 킬러 애플리케이션이 실행 중인 동안 시스템 패키지 관리자를 통해 어떻게 업데이트할 수 있는지 궁금합니다. 글쎄요, 이것이 실제로는 잘 작동하지 않는다고 말씀드릴 수 있습니다... 패키지 업데이트가 실행되는 동안 Firefox를 열어 두면 끔찍할 정도로 Firefox가 중단되는 일이 있었습니다. 가끔 억지로 죽였다가 다시 시작해야 했어요. 너무 깨져서 제대로 닫지도 못하거든요.

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

실행되는 동안 스스로 업데이트되는 프로그램 a.out을 작성하려면 어떻게 해야 합니까? 귀하의 질문에 대한 답변은 이미 많이 있습니다. 이것 좀 봐: https://stackoverflow.com/questions/232347/how-should-i-implement-an-auto-updater 그런데 프로그래밍에 관한 질문은 StackOverflow에서 하는 것이 더 좋습니다.

관련 정보