실패한 파일 전송을 재개 할 수있는 프로그램은 데이터 추가를 시작할 위치를 어떻게 알 수 있습니까?


23

같은 일부 파일 복사 프로그램 rsynccurl실패 전송 / 복사를 재개 할 수있는 능력을 가지고있다.

이러한 실패의 원인은 여러 가지가있을 수 있으며, 경우에 따라 프로그램이 수행 할 수없는 경우도 프로그램이 "정리"할 수 있습니다.

이러한 프로그램이 재개되면 성공적으로 전송 된 파일 / 데이터의 크기를 계산하고 소스에서 다음 바이트를 읽고 파일 조각에 추가하기 시작합니다.

예를 들어, 대상에 "만들어진"파일 조각의 크기는 1378 바이트이므로 원본의 1379 바이트부터 읽고 조각에 추가하기 시작합니다.

내 질문은 바이트가 비트로 구성되어 있으며 모든 파일이 깨끗한 바이트 크기의 청크로 분할 된 데이터를 가지고 있지 않다는 것을 알고 있습니다.이 프로그램은 데이터 추가를 시작하기로 선택한 지점이 올바른지 어떻게 알 수 있습니까?

대상 파일을 작성할 때 프로그램, 커널 또는 파일 시스템 수준에서 발생하는 SQL 데이터베이스와 유사한 일종의 버퍼링 또는 "트랜잭션"은 깔끔하고 잘 구성된 바이트 만 기본 블록 장치로 만들 수 있습니까?
또는 프로그램은 최신 바이트가 잠재적으로 불완전하다고 가정하므로 불량으로 가정하여 삭제하고 바이트를 다시 복사 한 다음 추가를 시작합니까?

모든 데이터가 바이트로 표현되는 것은 아니라는 것을 알기 때문에 이러한 추측은 틀린 것 같습니다.

이러한 프로그램이 "다시 시작"되면 올바른 위치에서 시작한다는 것을 어떻게 알 수 있습니까?


21
"모든 파일이 깨끗한 바이트 크기의 덩어리로 분할 된 데이터를 가지고있는 것은 아닙니다"? 바이트보다 작은 것을 파일에 어떻게 쓰나요?
muru

17
나는 바이트보다 작은 것을 쓸 수있는 시스템 호출이 없다는 것을 알고 있으며, 디스크 자체는 오늘날 512 바이트 블록 (또는 4096 바이트 블록)보다 적은 디스크를 쓰지 않는다고 생각합니다.
muru

8
아니요, 최소값은 바이트입니다. Sane 응용 프로그램은 4KB 또는 8KB 청크를 사용합니다. head -c 20480 /dev/zero | strace -e write tee foo >/dev/null그러면 OS 가이 를 버퍼링하여 더 큰 청크로 디스크로 보냅니다.
muru

9
@the_velour_fog : 어떻게 1 비트 만 쓰 fwrite()나요?
psmears

9
모든 실용적인 목적을 위해 데이터 바이트로 구성되며 모든 것이 가장 작은 단위로 작동합니다. 일부 시스템 (주로 압축과 관련된 gzip, h264)은 바이트에서 개별 비트의 압축을 풀지 만 운영 체제 및 메모리 작동은 바이트 수준입니다.
pjc50

답변:


40

명확성을 기하기 위해 실제 메커니즘은 더 복잡한 보안을 제공하기 위해 더 복잡합니다. 디스크에 기록 작업을 다음과 같이 상상할 수 있습니다.

  • 응용 프로그램이 바이트를 씁니다 (1)
  • 커널 (및 / 또는 파일 시스템 IOSS)이 그것들을 버퍼링
  • 버퍼가 가득 차면 파일 시스템으로 플러시 됩니다.
    • 블록이 할당됩니다 (2)
    • 블록이 작성되었습니다 (3)
    • 파일 및 블록 정보가 업데이트됩니다 (4)

프로세스가 (1)에서 중단되면 디스크에 아무 것도 얻지 않으면 파일이 손상되지 않고 이전 블록에서 잘립니다. 5000 바이트를 전송했으며 디스크에 4096 만 있으면 오프셋 4096에서 전송을 다시 시작합니다.

(2)에 있으면 메모리를 제외하고 아무 일도 일어나지 않습니다. (1)과 같습니다. at (3)이면 데이터가 기록 되지만 아무도 기억하지 않습니다 . 당신은 9000 바이트, 4096은 서면있어 4096이 기록되었다 전송 손실을 , 나머지는 잃었어요. 오프셋 4096에서 전송이 재개됩니다.

(4)이면 데이터가 디스크에 커밋 된 것입니다. 스트림의 다음 바이트가 손실 될 수 있습니다. 9000 바이트를 보냈고 8192가 기록되고 나머지는 손실되며 전송은 오프셋 8192에서 재개됩니다.

이것은 단순화 된 것입니다. 예를 들어, 3-4 단계의 각 "논리적"쓰기는 "원자"가 아니라 다른 시퀀스 (번호 5 번으로 표시)를 발생시켜 대상 장치 (예 : 하드 디스크)에 적합한 하위 블록으로 블록을 세분화합니다. )는 장치의 호스트 컨트롤러로 전송되며 캐싱 메커니즘 이 있으며 마지막으로 자기 플래터에 저장됩니다. 이 서브 시퀀스가 ​​항상 시스템 제어하에있는 것은 아니므로 데이터를 하드 디스크로 보냈다고해서 실제로 쓰여졌으며 다시 읽을 수있는 것은 아닙니다.

몇몇 파일 시스템은 저널링을 구현 하여 가장 취약한 지점 (4)이 실제로 메타 데이터를 작성함으로써 실제로 취약 하지 않은지 확인합니다 (4 단계에서 발생하는 모든 일에 일관되게 작동하는 트랜잭션 ).

트랜잭션 도중에 시스템이 재설정되면 가장 가까운 그대로 체크 포인트로 다시 돌아갈 수 있습니다. 기록 된 데이터는 사례 (1)과 마찬가지로 여전히 손실되지만 재개는이를 처리합니다. 실제로 정보 가 손실 되지 않습니다 .


1
좋은 설명입니다. 모든 것이 의미가 있습니다. 따라서 프로세스가 (4) 파일 블록 정보를 업데이트 할 때까지 모든 바이트가 양호하다는 것을 알고 있습니다. 이전 단계에 있던 모든 바이트는 디스크로 만들지 않았거나 디스크에 저장되지 않았을 경우 "기억되지 않은"것입니다 (참조 없음)
the_velour_fog

4
@the_velour_fog 그리고 두 번째 단락을 보완하기 위해 저널링을 구현 하지 않는 파일 시스템을 사용하는 경우 실제로 "파손 된"데이터를 얻을 수 있으므로 오류가 발생 하지 않고 이력서가 실패하고 깨진 파일이 생성 됩니다. 이것은 과거에 항상 발생 했었습니다. 특히 플로피와 같이 지연 시간이 긴 장치 용으로 설계된 파일 시스템에서 특히 그렇습니다. 파일 시스템이 이런 식으로 신뢰할 수없는 경우에도이를 피하기위한 몇 가지 트릭이 있었지만, 보상하기 위해 더 똑똑한 응용 프로그램과 일부 시스템에서 잘못되었을 수있는 일부 가정이 필요했습니다.
Luaan

이 답변은 파일 시스템에서 저널링의 유용성을 과장합니다. 모든 것이 (공통을 통해 fsync) 사용자 공간 응용 프로그램 및 하드 드라이브 컨트롤러 (종종 "엔터프라이즈"드라이브 에서조차도 망가짐)를 포함하여 트랜잭션 의미 체계를 구현 하지 않는 한 안정적으로 작동하지 않습니다 . fsync많은 파일 작업이 없으면 POSIX 에서는 직관적으로 정렬되고 원 자성이 보장되지 않습니다 . 열린 파일은 등 이 없는 파일과 O_APPEND다르게 작동 할 수 있습니다. 실제로 파일 일관성을 유지하는 가장 중요한 열쇠는 커널 VFS 시스템 및 디스크 캐시입니다. 다른 모든 것은 대부분 보풀입니다.
user1643723

11

참고 : 나는 rsync다른 파일 전송 유틸리티 의 소스를 보지 않았습니다.

파일의 끝을 뛰어 넘고 그 위치의 위치를 ​​바이트 단위로 얻는 C 프로그램을 작성하는 것은 쉽지 않습니다.

두 작업 모두 표준 C 라이브러리 함수를 한 번 호출하여 수행됩니다 lseek()( lseek(fd, 0, SEEK_END)파일 설명자를 위해 열린 파일 길이를 리턴 함).fd 바이트 단위로 측정 된 ).

대상 파일에 대한 작업이 완료되면 lseek() 소스 파일에서 위치로 이동하여 적절한 위치로 이동할 수 있습니다 lseek(fd, pos, SEEK_SET). 그런 다음 소스 파일의 이전 부분이 변경되지 않은 것으로 식별되었다고 가정하면 전송은 해당 시점에서 계속 될 수 있습니다 (다른 유틸리티가 다른 방식으로이를 수행 할 수 있음).

파일이 조각 날 수 있습니다 디스크에서 있지만 파일 시스템은 응용 프로그램이 파일을 순차적 인 바이트 시퀀스로 인식하도록합니다.


비트 및 바이트에 대한 주석의 설명과 관련하여 : 디스크에 기록 될 수있는 가장 작은 데이터 단위는 byte 입니다. 단일 바이트에는 하나 이상의 블록이 필요합니다 디스크에 데이터 을 할당해야합니다. 블록의 크기는 파일 시스템의 유형 및 파일 시스템을 초기화 할 때 관리자가 사용하는 매개 변수에 따라 다르지만 대개 512 바이트에서 4KiB 사이입니다. 쓰기 작업은 커널, 기본 C 라이브러리 또는 응용 프로그램 자체에 의해 버퍼링 될 수 있으며 실제 디스크 쓰기는 최적화로 적절한 블록 크기의 배수로 발생할 수 있습니다.

파일에 단일 비트를 쓸 수 없으며 쓰기 작업이 실패하면 파일에 "반각 바이트"가 남지 않습니다.


감사합니다. 그래서 쓰기 작업이 실패하면 반 바이트를 남기지 않는 것은 무엇입니까? 커널 버퍼링 muru가 설명하고 있습니까? 즉, 8KB 청크를 커널로 전송하는 도중 프로세스가 중단되고 예기치 않게 종료 된 경우-8KB 청크는 결코 커널에 도달하지 않습니다. 그러나 커널과 파일 시스템에 도달 한 이전의 프로세스는 양호하다고 가정 할 수 있습니까?
the_velour_fog

6
@the_velour_fog 는 I / O 시스템 호출 도중 프로세스가 중단 될 수 없기 때문에 예기치 않은 종료가 발생할 수 없습니다 (따라서 NFS 파일에 대한 파일 시스템 액세스 호출에서 처리 불가능한 프로세스가 중단 되는 것을 보는 것은 드문 일이 아닙니다). 또한보십시오 : unix.stackexchange.com/q/62697/70524
muru

2
정확한 시간에 시스템 전원이 꺼지면 문제가 발생할 수 있습니다. 때때로 파일의 마지막 쓰기 지점에서 가비지가 발생할 수 있습니다. 데이터베이스 디자인에서 매우 까다로운 문제입니다. 그러나 여전히 "유효한"또는 "유효하지 않은"가장 작은 단위는 디스크 블록입니다.
pjc50

1
당신이 "얻을 수없는 것처럼 너무 아니다 @the_velour_fog 반 쓴 바이트를 "(또는, 더 정확하게, 반 작성 블록 바이트) 반 작성 블록으로는되지 않을 것이다 기록 전체를 (기록 된 것으로 ) -LSerni의 답변의 단계 (3) 및 (4)를 참조하십시오 .
TripeHound

5

curl 및 rsync와 같은 프로그램은 매우 다르기 때문에 이것은 기본적으로 두 가지 질문입니다.

curl과 같은 HTTP 클라이언트의 경우 현재 파일의 크기를 확인한 다음 Content-Range요청과 함께 헤더 를 보냅니다 . 서버 206200(성공 ) 대신 상태 코드 (부분 내용)를 사용하여 파일 범위 전송을 재개하고 다운로드가 재개되거나 헤더를 무시하고 처음부터 시작하며 HTTP 클라이언트는 모든 것을 다시 다운로드하는 것 외에 다른 선택을 할 수 없습니다 다시.

또한 서버는 Content-Length헤더를 보내거나 보내지 않을 수 있습니다 . 일부 다운로드에 백분율 및 파일 크기가 표시되지 않는 것을 알 수 있습니다. 이것은 서버가 클라이언트에게 길이를 알려주지 않는 다운로드이므로 클라이언트는 다운로드 한 양만 알지만 바이트 수는 알 수 없습니다.

Content-Range시작 중지 위치에 헤더를 사용하면 일부 다운로드 관리자가 한 번에 다른 소스에서 파일을 다운로드하여 각 미러 자체가 네트워크 연결보다 느리면 전송 속도가 빨라집니다.

반면에 rsync는 증분 파일 전송을위한 고급 프로토콜입니다. 서버 및 클라이언트 측에서 파일의 일부에 대한 체크섬을 생성하여 동일한 바이트를 감지합니다. 그런 다음 차이점 만 보냅니다. 즉, 다운로드를 재개 할 수 없으며 파일을 다시 다운로드하지 않고 매우 큰 파일 중간에 몇 바이트를 변경 한 경우 변경된 바이트를 다운로드 할 수도 있습니다.

전송을 재개하기위한 또 다른 프로토콜은 비트 토렌트이며, .torrent파일에는 파일의 블록에 대한 체크섬 목록이 포함되어 있으므로 블록을 임의의 순서로 다른 소스에서 병렬로 다운로드하여 확인할 수 있습니다.

rsync 및 bittorent는 디스크의 부분 데이터를 확인하지만 HTTP 다운로드를 다시 시작해도 그렇지는 않습니다. 따라서 부분 데이터가 손상되었다고 의심되면 무결성을 검사해야합니다 (예 : 최종 파일의 체크섬 사용). 그러나 다운로드 도중 중단되거나 네트워크 연결이 끊어지면 일반적으로 전송 중에 정전이 발생하더라도 부분 파일이 손상되지 않습니다.


4

TL; DR : 사용하는 프로토콜이 허용하지 않는 한 불가능합니다.

프로그램이 항상 임의의 위치에서 다시 시작할 수는 없습니다. 예를 들어, 서버가 지원 하고 클라이언트가이를 구현 한 경우에만 HTTP 요청을 다시 시작할 수 있습니다 . 이는 보편적이지 않으므로 프로그램 설명서를 확인하십시오. 서버가이를 지원하는 경우 프로그램은 프로토콜의 일부로 간단히 요청하여 전송을 재개 할 수 있습니다. 일반적으로 다운로드 디렉토리에 부분 전송이 표시됩니다 (일반적으로 ".partial"확장자 또는 이와 유사한 것으로 표시됨).

파일 다운로드가 일시 중지되었거나 중지 된 경우 클라이언트는 파일을 디스크에 쓸 수 있고 재개 할 위치를 명확하게 알 수 있습니다. 반면에 클라이언트가 충돌하거나 파일에 쓰는 중 오류가 발생하면 클라이언트는 파일이 손상되었다고 가정하고 다시 시작해야합니다. BitTorrent 는 파일을 "청크"로 나누고 어떤 파일이 성공적으로 다운로드되었는지 추적하여이 문제를 다소 완화합니다. 다시 실행해야 할 가장 큰 부분은 몇 덩어리입니다. Rsync 는 비슷한 것을 수행합니다.

프로그램은 내용이 동일하다는 것을 어떻게 알 수 있습니까? 한 가지 방법은 클라이언트와 서버간에 일부 식별자가 동일한 지 확인하는 것입니다. 이것의 몇 가지 예는 타임 스탬프와 크기이지만 프로토콜에 고유 한 메커니즘 이 있습니다. 식별자가 일치하면 클라이언트는 재개가 작동한다고 가정 할 수 있습니다.

보다 명확한 확인을 원하면 HTTP와 친구가 첫 번째 선택이되어서는 안됩니다. 전체 파일 및 각 전송 된 청크에 대한 체크섬 또는 해시가있는 프로토콜을 사용하여 다운로드의 체크섬을 서버의 컴퓨터 체크섬과 비교할 수 있습니다. 일치하지 않는 항목은 다시 다운로드됩니다. 다시 한번, BitTorrent는 이런 종류의 프로토콜의 예입니다. rsync는 선택적으로이 작업을 수행 할 수 있습니다.


rsync 예제의 경우 하나의 rsync 프로토콜 만 있기 때문에 간단합니다. http 다운로드의 경우 표준으로 범위 요청이 있습니다. 업로드의 표준 의미가 wpart 및 curl의 multipart / form-data이기 때문에 이력서 업로드에서 curl이 실제로 무엇을하는지 궁금합니다.하지만 업로드 이력서 의미가 보편적으로 동의한다고는 생각하지 않습니다. 예를 들어 YouTube와 Nginx는 다르게 할 수 있습니다.
Rob

1

전송에 사용 된 프로토콜에 따라 다릅니다. curl은 http를 사용하며 파일에 나타나는 순서대로 데이터를 순차적으로 전송합니다. 따라서 부분적으로 완료된 전송의 파일 크기에 따라 curl이 다시 시작될 수 있습니다. 실제로 N 길이의 파일을 만들고 그 파일을 부분적으로 완료된 다운로드로 취급하도록 요청한 다음 (첫 번째 N 바이트를 버림) 첫 N 바이트를 건너 뛰도록 속일 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.