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


15

썬더 버드 나 파이어 폭스와 같은 킬러 애플리케이션이 시스템 패키지 관리자를 통해 업데이트되는 동안 어떻게 실행되는지 궁금합니다. 이전 코드는 업데이트되는 동안 어떻게됩니까? 프로그램이 실행되는 동안 자체적으로 업데이트되는 프로그램을 작성하려면 어떻게해야합니까?



@derobert 정확하게는 아닙니다 : 그 스레드는 실행 파일의 특성으로 들어 가지 않습니다. 관련 배경을 제공하지만 중복되지는 않습니다.
Gilles 'SO- 악마 그만해'

@Gilles 글쎄, 당신이 나머지 물건에 남겨두면 너무 넓습니다. 여기에는 적어도 두 가지 질문이 있습니다. 그리고 다른 질문은 꽤 가깝습니다. 유닉스에서 파일을 업데이트하여 교체하는 이유를 묻습니다.
derobert

자신의 코드로이 작업을 수행하려면 "핫"코드 업데이트가 핵심 기능인 프로그래밍 언어 Erlang을 살펴보십시오. learnyousomeerlang.com/relups
mattdm

1
@Gilles BTW : 응답으로 추가 한 에세이를 보았을 때, 나는 가까운 투표를 철회했습니다. 업데이트가 어떻게 작동하는지 알고 싶어하는 사람을 지적하기 위해이 질문을 좋은 곳으로 바꿨습니다.
derobert

답변:


21

일반적으로 파일 교체

먼저 파일을 대체하는 몇 가지 전략이 있습니다.

  1. 쓰기 위해 기존 파일을 열고 0 길이로 자른 다음 새 내용을 씁니다. 덜 일반적인 변형은 기존 파일을 열고 기존 내용을 새 내용으로 덮어 쓰고 파일이 더 짧은 경우 새 길이로 자릅니다.

    echo 'new content' >somefile
    
  2. 이전 파일을 제거 하고 동일한 이름으로 새 파일을 작성하십시오. 쉘 용어로 :

    rm somefile
    echo 'new content' >somefile
    
  3. 임시 이름으로 새 파일에 쓴 다음 새 파일을 기존 이름으로 이동 하십시오. 이동하면 이전 파일이 삭제됩니다. 쉘 용어로 :

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

전략의 차이점을 모두 나열하지는 않겠습니다. 여기서 중요한 몇 가지만 언급하겠습니다. stategy 1을 사용하면 현재 프로세스를 사용하는 프로세스가있는 경우 프로세스는 업데이트중인 새 컨텐츠를 봅니다. 프로세스에서 파일 내용이 동일하게 유지 될 것으로 예상되는 경우 약간의 혼동이 발생할 수 있습니다. 이것은 파일을 열어 둔 프로세스에 관한 것입니다 ( 문서 에서 lsof또는 문서 에서 볼 수있는 대화식 응용 프로그램은 일반적으로 파일을 편집기에서 열어서) 대화 형 응용 프로그램은 일반적으로 파일을 열어 두지 않습니다. "문서 열기"작업을 수행하고 "문서 저장"작업 중에 파일을 위의 전략 중 하나를 사용하여 바꿉니다./proc/PID/fd/

전략 2 및 3을 사용하면 일부 프로세스에서 파일을 somefile연 경우 컨텐츠 업그레이드 중에 이전 파일이 열린 상태로 유지됩니다. 전략 2를 사용하면 실제로 파일을 제거하는 단계는 디렉토리에서 파일 항목 만 제거합니다. 그것으로 이어지는에는 디렉토리 엔트리가 없을 때 파일 자체는 제거 (일반 유닉스 파일 시스템에를,있을 수 하나 개 이상의 디렉토리와 동일한 파일에 대한 항목 ) 어떤 프로세스가 오픈이 없습니다. 이를 관찰하는 방법은 다음과 같습니다. 파일은 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에서는 동적으로로드 된 라이브러리의 코드를 덮어 쓸 수 있습니다. 사용중인 프로그램이 중단 될 수 있습니다. ( sleep시작할 때 필요한 모든 라이브러리 코드를로드하기 때문에이 기능 을 관찰하지 못할 수 있습니다 . 수면 후 유용한 무언가를 수행하는보다 복잡한 프로그램을 시도하십시오 perl -e 'sleep 9; print lc $ARGV[0]'.)

인터프리터가 스크립트를 실행중인 경우 스크립트 파일은 인터프리터에 의해 일반적인 방식으로 열리므로 스크립트 덮어 쓰기를 방지 할 수 없습니다. 일부 인터프리터는 첫 줄을 실행하기 전에 전체 스크립트를 읽고 구문 분석하고 다른 인터프리터는 필요에 따라 스크립트를 읽습니다. 실행 중에 스크립트를 편집하면 어떻게됩니까?를 참조하십시오 . 그리고 어떻게 리눅스 거래 쉘 스크립트? 상세 사항은.

전략 2와 3은 실행 파일에도 안전합니다. 실행 파일 (및 동적으로로드 된 라이브러리)은 파일 디스크립터가 있다는 의미에서 파일을 열지는 않지만 매우 유사한 방식으로 동작합니다. 일부 프로그램이 코드를 실행하는 한 파일은 디렉토리 항목이 없어도 디스크에 남아 있습니다.

응용 프로그램 업그레이드

대부분의 패키지 관리자는 전략 3을 사용하여 위에서 언급 한 주요 이점 때문에 파일을 교체합니다. 언제든지 파일을 열면 유효한 버전이됩니다.

응용 프로그램 업그레이드가 중단 될 수있는 위치는 하나의 파일을 업그레이드하는 것이 원 자성이지만 응용 프로그램이 여러 파일 (프로그램, 라이브러리, 데이터 등)로 구성된 경우 전체를 업그레이드하는 것이 아닙니다. 다음과 같은 일련의 이벤트를 고려하십시오.

  1. 응용 프로그램의 인스턴스가 시작되었습니다.
  2. 응용 프로그램이 업그레이드되었습니다.
  3. 실행중인 인스턴스 응용 프로그램은 해당 데이터 파일 중 하나를 엽니 다.

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

업그레이드 후에도 이전 프로그램이 여전히 실행 중임을 알 수 있습니다. 새 버전을 실행하려면 이전 프로그램을 종료하고 새 버전을 실행해야합니다. 패키지 관리자는 일반적으로 업그레이드시 데몬을 종료하고 다시 시작하지만 최종 사용자 응용 프로그램은 그대로 둡니다.

일부 데몬에는 데몬을 종료하지 않고 업그레이드를 처리하고 새 인스턴스가 다시 시작될 때까지 기다릴 때 서비스가 중단되는 특별한 절차가 있습니다. 이것은 init 의 경우에 필요하며 이는 죽일 수 없습니다. init 시스템은 실행중인 인스턴스 호출 execve이 자신을 새 버전으로 교체 하도록 요청하는 방법을 제공합니다 .


"그런 다음 새 파일을 기존 이름으로 이동하십시오. 이동하면 이전 파일이 삭제됩니다." unlink나중에 다루는 것처럼 실제로는 단지 약간 혼란 스럽 습니다. "기존 이름을 대체"할 수도 있지만 여전히 다소 혼란 스럽습니다.
derobert

@derobert 나는“연결 해제”용어에 무겁게되고 싶지 않았습니다. 디렉토리 항목과 관련하여“삭제”를 사용하고 있습니다.이 미묘한 부분은 나중에 설명합니다. 그 단계에서 혼란 스럽습니까?
Gilles 'SO- 악마 그만해'

아마도 추가 단락을 설명하기에 충분히 혼란스럽지 않을 수도 있습니다. 혼란스럽지 않지만 기술적으로 올바른 표현을 원합니다. "remove"를 다시 사용하면 설명 할 링크가 이미 있습니까?
derobert

3

프로그램이 실행되는 동안 업그레이드를 실행할 수 있지만 실행중인 프로그램은 실제로 이전 버전입니다. 이전 바이너리는 프로그램을 닫을 때까지 디스크에 남아 있습니다.

설명 : Linux 시스템에서 파일은 단지 inode이므로 여러 개의 링크가있을 수 있습니다. 예 : /bin/bash당신이 볼은 그냥 링크입니다 inode 3932163내 시스템에. 링크를 발행하여 어떤 inode가 어떤 링크를 수행하는지 찾을 수 있습니다 ls --inode /path. 파일 (inode)은 해당 파일을 가리키는 링크가없고 프로그램에서 사용하지 않는 경우에만 제거됩니다. 패키지 관리자 업그레이드시 /usr/bin/firefox먼저 링크를 해제 (하드 링크 제거 /usr/bin/firefox) 한 다음 /usr/bin/firefox다른 inode (새 firefox버전 을 포함하는 파일)에 대한 하드 링크 라는 새 파일을 만듭니다 . 이전 inode는 이제 사용 가능으로 표시되며 새 데이터를 저장하기 위해 재사용 할 수 있지만 디스크에 남아 있습니다 (아이 노드는 파일 시스템을 빌드 할 때만 생성되며 절대 삭제되지 않습니다). 다음에 시작할 때firefox새로운 것이 사용됩니다.

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


1
실제로, 파일을 삭제 (링크 해제)하는 방법이 Unix에서 작동하기 때문입니다. unix.stackexchange.com/questions/49299/…를 참조하십시오 . 또한 적어도 Linux에서는 실제로 실행중인 바이너리에 쓸 수 없으며 "텍스트 파일 사용 중"오류가 발생합니다.
derobert

이상해 ... 그렇다면 어떻게합니까? 데비안의 apt업그레이드 작업? Iceweasel( Firefox)을 포함하여 문제없이 실행중인 프로그램을 업그레이드 할 수 있습니다 .
psimon

2
APT (또는 오히려 dpkg)는 파일을 덮어 쓰지 않습니다. 대신 링크를 해제하고 동일한 이름으로 새 것을 넣습니다. 설명을 위해 링크 된 질문과 답변을 참조하십시오.
derobert

2
그것은 여전히 ​​RAM에 있기 때문이 아니라 여전히 디스크에 있습니다. 파일은 프로그램의 마지막 인스턴스가 종료 될 때까지 실제로 삭제되지 않습니다.
derobert

2
이 사이트는 편집을 제안하지 않습니다. 담당자가 충분히 높으면 수정 만하면 더 이상 제안 할 수 없습니다. 따라서 유닉스 시스템의 파일 (inode)은 일반적으로 하나의 이름을 갖습니다. 그러나 ln(하드 링크)로 이름을 추가하면 더 많은 것을 가질 수 있습니다 . rm(링크 해제)로 이름을 제거 할 수 있습니다 . 실제로 파일을 직접 삭제할 수는 없으며 이름 만 제거하십시오. 파일 이름이없고 추가로 열려 있지 않은 경우 커널은 해당 파일을 삭제합니다. 실행중인 프로그램에는 실행중인 파일이 열려 있으므로 모든 이름을 제거한 후에도 파일이 계속 남아 있습니다.
derobert

0

썬더 버드 나 파이어 폭스와 같은 킬러 응용 프로그램이 시스템 패키지 관리자를 통해 어떻게 업데이트되고 있는지 궁금합니다. 글쎄, 나는 이것이 실제로 잘 작동하지 않는다고 말할 수있다 ... 패키지 업데이트가 실행되는 동안 열어두면 Firefox가 나에게 끔찍한 영향을 미쳤다. 때로는 너무 세게 죽이고 다시 시작해야했습니다. 너무 깨져서 제대로 닫을 수도 없었습니다.

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

프로그램이 실행되는 동안 자체적으로 업데이트되는 프로그램을 작성하려면 어떻게해야합니까? 귀하의 질문에 이미 많은 답변이 있습니다. 이 체크 아웃 : /programming/232347/how-should-i-implement-an-auto-updater을 그건 그렇고, 프로그래밍에 대한 질문은 더 나은에 StackOverflow에 꺼져 있습니다.


2
실행 파일은 실제로 요청 페이지 (스왑)됩니다. 그것들은 메모리에 완전히로드되지 않으며, 시스템이 다른 것을 위해 RAM을 원할 때마다 메모리에서 제거 될 수 있습니다. 이전 버전은 실제로 디스크에 남아 있습니다. unix.stackexchange.com/questions/49299/…를 참조하십시오 . 적어도 리눅스에서는 실제로 실행중인 실행 파일에 쓸 수 없으며 "텍스트 파일 사용 중"이라는 오류가 발생합니다. 루트조차도 할 수 없습니다. (하지만 Firefox에 대해서는 꽤 정확합니다).
derobert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.