Linux에서 쓰기 손실을 일으키는 I/O 오류에 대처하기 위한 프로그램 쓰기
TL;DR: Linux 커널에서 버퍼링된 I/O 쓰기가 손실된 경우 응용 프로그램에서 확인할 수 있는 방법이 있습니까?
파일(및 그 부모 디렉토리)은 내구성을 위해 필요합니다.문제는 I/O 오류로 인해 커널에서 쓰기 보류 중인 더티 버퍼가 손실된 경우 응용 프로그램에서 이를 어떻게 감지하고 복구 또는 중단시킬 수 있는가 하는 것입니다.
쓰기 순서와 쓰기 내구성이 중요한 데이터베이스 애플리케이션 등을 생각할 수 있습니다.
글씨를 잃어버렸다고?
Linux 커널의 블록 계층에 따라 정상적으로 전송된 버퍼링된 I/O 요청이 손실될 수 있습니다.write()
,pwrite()
하다
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(및 을 참조).
새로운 커널에서는 대신 다음과 같은 "lost async page write"가 오류에 포함됩니다.
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
이 ★★★★★★★★★★★★★★★★★★★★★★★★★★★write()
에러 없이 이미 반환되어 버립니다.어플리케이션에 에러를 보고할 방법은 없는 것 같습니다.
탐지하는 거요?
커널 소스에 대해서는 잘 모르지만, 제 생각엔 이 소스는AS_EIO
버퍼가 비동기 쓰기를 실행하는 경우 기입에 실패한 버퍼:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
이 이 되면 알 수 합니다.fsync()
파일이 디스크에 저장되어 있는지 확인합니다.
가 차례로 호출하는 것은 힘 있는 것처럼 보입니다.다시 돌아오다-EIO
1은 1은 1은 1은 1은 1은 1은 1은 1은 1은 1입니다.
이게대로 만, 내, 면, 면, 면으로 퍼진다면fsync()
,에서 I했을 경우 패닉 상태가 되어 경우, I/O 에러가 발생했을 경우는, I/O 에러가 발생합니다.fsync()
재기동시에 작업을 재실행하는 방법을 알고 있는 경우, 이것으로 충분한 안전성이 확보됩니까?
파일 내의 어떤 바이트 오프셋이 손실된 페이지에 해당하는지 알 수 있는 방법은 없을 것입니다.그러나 앱이 마지막 성공 이후 보류 중인 모든 작업을 반복할 경우 다시 쓸 수 있습니다.fsync()
된 쓰기에 커널 를 다시 되어, 의 I/O가 됩니다.fsync()
료해야합합합?????
그 밖에 무해한 ?fsync()
도 모른다-EIO
구제금융을 받고 일을 다시 하는 게 너무 심한가요?
왜요?
물론 이러한 오류는 발생하지 않아야 합니다., 개, 개, 개 2 개의 했습니다.dm-multipath
SAN이 씬 프로비저닝된 스토리지 할당 실패를 보고하기 위해 사용하는 감지 코드와 드라이버 기본값입니다.그러나 이러한 문제가 발생할 수 있는 유일한 상황은 아닙니다. libvirt, Docker 등에서 사용되는 씬 프로비저닝된 LVM의 보고서도 있습니다.데이터베이스와 같은 중요한 애플리케이션은 이러한 오류에 대처하기 위해 노력해야 하며, 맹목적으로 모든 것이 정상인 것처럼 행동해서는 안 됩니다.
커널이 커널 패닉으로 인해 사망하지 않고 쓰기 손실이 발생해도 괜찮다고 생각하는 경우, 애플리케이션은 이에 대처할 방법을 찾아야 합니다.
실제로 SAN의 멀티패스 문제로 인해 쓰기가 손실되어 DBMS가 쓰기에 실패한 것을 몰랐기 때문에 데이터베이스 손상을 일으킨 사례를 발견했습니다.재미없어.
fsync()
-EIO
에
(주의: 초기 부품은 오래된 커널을 참조합니다.다음은 최신 커널을 반영하여 갱신되었습니다.)
이는 실패한 파일의 더티 버퍼 페이지에 플래그가 설정된 비동기 버퍼 쓰기처럼 보입니다.
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
후, 「」, 「」에 의해서 됩니다.wait_on_page_writeback_range(...)
by called do_sync_mapping_range(...)
by called sys_sync_file_range(...)
by called sys_sync_file_range2(...)
하기 위해 C를 호출합니다.fsync()
.
하지만 딱 한 번!
는 ★★★★★★★★★★★★★★★★★★ sys_sync_file_range
168 * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
169 * I/O errors or ENOSPC conditions and will return those to the caller, after
170 * clearing the EIO and ENOSPC flags in the address_space.
는, 「 」가 되었을 때에,fsync()
-EIO
되어 있음) (manpage)-ENOSPC
에러 상태가 클리어 되기 때문에, 그 후의 에러 상태가 클리어 됩니다.fsync()
페이지가 작성되지 않았더라도 성공했다고 보고합니다.
다를까wait_on_page_writeback_range(...)
에러 비트를 테스트하면, 다음과 같이 에러 비트를 클리어 합니다.
301 /* Check for outstanding write errors */
302 if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
303 ret = -ENOSPC;
304 if (test_and_clear_bit(AS_EIO, &mapping->flags))
305 ret = -EIO;
할 수 있을 것으로 fsync()
데이터가 디스크에 저장되어 있다고 믿을 때까지, 그것은 매우 잘못된 것입니다.
DBMS에서 .DBMS는 를 재시도합니다. 시시시시시시다다fsync()
성공하면 다 잘 될 거라고 생각해요.
이거 허용되나요?
의 POSIX/SuS 문서에서는, 어느쪽이든, 실제로는 이것을 지정하고 있지 않습니다.
fsync() 함수가 실패하면 미결 I/O 조작이 완료되었다고 보증되지 않습니다.
Linux의 man-page에는 장애 발생 시 어떤 일이 일어나는지 나와 있지 않습니다.
이 말의 되어 있는 것 요.fsync()
에러는, 「당신의 기입에 무슨 일이 일어났는지 모릅니다.작동했을 수도 있고, 실패했을 수도 있습니다.확인을 위해 다시 시도하는 것이 좋습니다.입니니다
새로운 커널
4.9 세트로-EIO
「」를 해, 「」를 해 주세요.mapping_set_error
.
buffer_io_error(bh, ", lost async page write");
mapping_set_error(page->mapping, -EIO);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
동기 측면에서는 비슷하다고 생각합니다만, 현재는 구조가 매우 복잡해지고 있습니다. filemap_check_errors
mm/filemap.c
다음 작업을 수행합니다.
if (test_bit(AS_EIO, &mapping->flags) &&
test_and_clear_bit(AS_EIO, &mapping->flags))
ret = -EIO;
거의 같은 효과가 있습니다.에러 체크는 모두 테스트 및 클리어 되는 것 같습니다.
if (test_bit(AS_EIO, &mapping->flags) &&
test_and_clear_bit(AS_EIO, &mapping->flags))
ret = -EIO;
return ret;
하고 btrfs
때, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」ext4
(루프백)에 의한 )/mnt/tmp
합니다.
sudo dd if=/dev/zero of=/tmp/ext bs=1M count=100
sudo mke2fs -j -T ext4 /tmp/ext
sudo mount -o loop /tmp/ext /mnt/tmp
sudo perf probe filemap_check_errors
sudo perf record -g -e probe:end_buffer_async_write -e probe:filemap_check_errors dd if=/dev/zero of=/mnt/tmp/test bs=4k count=1 conv=fsync
콜은 '보다'에서 수 있습니다.perf report -T
:
---__GI___libc_fsync
entry_SYSCALL_64_fastpath
sys_fsync
do_fsync
vfs_fsync_range
ext4_sync_file
filemap_write_and_wait_range
filemap_check_errors
읽어본 결과, 현대의 알맹이들도 똑같이 행동한다는 것을 알 수 있습니다.
은 만약에 '이렇게 하면 된다'는인 것 같아요.fsync()
(아마도)write()
★★★★★★★★★★★★★★★★★」close()
는 반환됩니다.-EIO
은, 에 「의 상태」가 되었을 에, 의 상태로 fsync()
또는 d "d "d"close()
및그 d'd't's 。write()
10 인치 †
시험
저는 이 동작을 증명하기 위해 테스트 케이스를 구현했습니다.
시사점
DBMS는 크래시 리커버리를 입력하여 이 문제에 대처할 수 있습니다.일반 사용자 애플리케이션은 도대체 어떻게 이 문제에 대처할 수 있을까요?fsync()
man page는 "fsync-if-you-feel-like-it"을 의미한다는 경고를 주지 않으며, 많은 앱이 이 동작에 잘 대처하지 못할 것으로 예상됩니다.
버그 리포트
- https://bugzilla.kernel.org/show_bug.cgi?id=194755
- https://bugzilla.kernel.org/show_bug.cgi?id=194757
추가 정보
lwn.net은 이에 대해 "개선된 블록 계층 오류 처리"라는 기사에서 언급했습니다.
postgresql.org 메일링 리스트 스레드.
응용 프로그램의 write()는 이미 오류 없이 반환되므로 응용 프로그램에 오류를 다시 보고할 방법은 없는 것 같습니다.
나는 동의하지 않는다. write
는 단순히 큐잉되어 할 수 즉, 다음 은 디스크상의 기입이 필요합니다.즉, 다음 조작에서는 에러가 보고됩니다.다음 작업에서는 디스크에 실제 쓰기가 필요합니다.즉, 다음 작업에서는 에러가 보고됩니다.fsync
시스템이 캐시를 플러시하기로 결정했을 경우, 그리고 적어도 마지막으로 파일을 닫았을 때 다음과 같은 쓰기를 수행할 수 있습니다.
따라서 응용 프로그램에서 가능한 쓰기 오류를 감지하기 위해 의 반환값을 테스트하는 것이 필수적입니다.
정말로 현명한 에러 처리를 실시할 필요가 있는 경우는, 전회의 성공 이후에 작성된 모든 것이,fsync
실패했을 수도 있고 그 모든 점에서 적어도 뭔가 실패했을 수도 있어요
write
(2)는 기대 이상의 성능을 제공합니다. man 가 열려 .write()
삭제:
에서의 정상적인
write()
는 데이터가 디스크에 커밋되었음을 보증하지 않습니다.실제로 일부 버그가 있는 구현에서는 데이터를 위한 공간이 성공적으로 예약되어 있는지조차 보장되지 않습니다.할 수 은 전화하는 입니다.fsync
(2) (2) 데이터 기입이 완료됩니다
을 알 수 .write()
단순히 데이터가 커널의 버퍼링 퍼실리티에 도달했음을 나타냅니다.버퍼 유지에 실패하면 이후 파일 기술자에 액세스할 때 오류 코드가 반환됩니다.으로서 「」이 될 이 있다.close()
[ man ]의 [close
2) 문장이 포함됩니다.(2).
높습니다.
write
(2)은, , (2) 동작에 보고한다.close
). ( ).
쓰기를 할 필요가 는, 「」를 사용할 가 있습니다.fsync
/fsyncdata
★★★★★★★★★★★★★★★★★★:
fsync()
파일 기술자 fd가 참조하는 파일의 수정된 코어 내 데이터(즉, 변경된 버퍼 캐시 페이지)를 모두 디스크 디바이스(또는 다른 영구 스토리지 디바이스)로 전송하여 변경된 모든 정보를 시스템이 크래시되거나 재부팅된 후에도 가져올 수 있도록 합니다.여기에는 디스크 캐시가 있는 경우 디스크 캐시를 쓰거나 플러싱됩니다.콜은, 디바이스가 전송이 완료했다고 보고할 때까지 블록 됩니다.
파일을 열 때 O_SYNC 플래그를 사용합니다.그러면 데이터가 디스크에 기록되게 됩니다.
이게 널 만족시키지 못한다면 아무것도 없을 거야.
close의 반환값을 확인합니다.버퍼링된 쓰기가 성공하는 것처럼 보이는 동안 닫기가 실패할 수 있습니다.
언급URL : https://stackoverflow.com/questions/42434872/writing-programs-to-cope-with-i-o-errors-causing-lost-writes-on-linux
'programing' 카테고리의 다른 글
IE11에서 VueJ가 렌더링되지 않음 (0) | 2022.07.11 |
---|---|
날짜에 하루를 추가하려면 어떻게 해야 합니다. (0) | 2022.07.11 |
v-select 외부에서 클릭하면 v-model이 null로 재설정되는 이유는 무엇입니까?Vuetify (0) | 2022.07.11 |
컴포넌트의 다른 모듈에서 커스텀 디렉티브를 테스트하는 방법 (0) | 2022.07.11 |
사용자가 C에 입력한 문자열을 읽으려면 어떻게 해야 하나요? (0) | 2022.07.11 |