Linux는 블록 장치를 어떻게 처리합니까?

Linux는 블록 장치를 어떻게 처리합니까?

오늘 저는 FreeBSD가 블록 장치에 대한 지원을 완전히 제거했다는 것을 알게 되었습니다. 이 결정에 대한 근거를 읽으면서 나는 다음과 같은 사실을 발견했습니다.

블록 장치는 커널이 캐시를 제공하는 디스크 장치입니다. 이러한 캐싱은 블록 장치를 거의 사용할 수 없게 만들거나 적어도 위험할 정도로 신뢰할 수 없게 만듭니다. 캐시는 쓰기 작업 순서를 다시 지정하여 애플리케이션이 어떤 순간에도 정확한 디스크 내용을 알 수 없도록 합니다. 이로 인해 디스크 데이터 구조(파일 시스템, 데이터베이스 등)의 예측 가능하고 안정적인 충돌 복구가 불가능해졌습니다. 쓰기가 지연될 수 있기 때문에 커널은 어떤 특정 쓰기 작업에서 쓰기 오류가 발생했는지 애플리케이션에 보고할 수 없으며 이로 인해 일관성 문제가 더욱 악화됩니다.

(에서https://www.freebsd.org/doc/en_US.ISO8859-1/books/arch-handbook/driverbasics-block.html)

그러나 나는 Linux가 거의 독점적으로 블록 장치를 사용한다는 것을 알고 있습니다(원시 장치를 요청할 수는 있지만).

그렇다면 Linux는 이 인용문에서 언급된 문제를 어떻게 피할 수 있습니까? 아니면 대부분의 드라이버가 원시 장치만 요청합니까?

답변1

BSD 사람들은 정말 하드코어하고 종종 놀라운 일을 합니다. :-) 제 생각에는 블록 장치 계층을 제거하는 것은 문제가 되지 않습니다(예를 들어 nfs에는 기본 블록 장치도 없습니다). 그러나 이 추론은 블록 장치에 대한 것이 아닙니다. 쓰기 캐싱에 반대합니다. 제 생각에는 쓰기 캐시를 제거하는 것은 매우 나쁜 일입니다. 프로세스가 디스크에 무언가를 쓰는 경우 성공할 때까지 제어권을 되찾지 않습니까?

하지만 나는 그들이 무엇을 하고 있는지 몰랐다고 생각합니다. 누군가가 다른 답변으로 이유를 설명할 수 있기를 바랍니다.

이를 명확하게 설명하려면 파일 시스템이 어떻게 작동하는지 설명해야 합니다. 파일 시스템 드라이버는 본질적으로 파일 시스템 작업(디렉터리 열기, 파일 생성, 읽기, 쓰기, 삭제 등)과 블록 작업(예: "페이지 0xfce2ea31을 디스크 블록 0xc0deebed에 쓰기") 사이의 변환 계층입니다.

하지만 차단 작업은 그 자리에서 하드 드라이브에 도달하지 않습니다. 먼저 블록 캐시로 이동합니다. 이는 파일 시스템이 디스크에 메모리 페이지를 쓰려는 경우 먼저 예약된 메모리 영역에 쓴다는 것을 의미합니다. 커널의 메모리 관리에서 최적이라고 판단하는 경우 이 데이터는 하드 디스크에 기록됩니다. 이를 통해 다양한 속도 향상이 가능합니다. 예를 들어 디스크의 시작과 끝에서 많은 쓰기가 발생하는 경우 커널은 디스크 헤드가 가능한 한 적게 자체적으로 재배치되는 방식으로 이를 결합할 수 있습니다.

또 다른 개선 사항이 있습니다. 프로그램이 파일에 쓰면 마치 램디스크인 것처럼 매우 빠른 속도로 작업이 수행됩니다. 물론 이는 시스템 RAM이 가득 차지 않은 경우에만 가능하며, 그 후에는 쓰기 캐시가 지워질 때까지 기다려야 합니다. 그러나 이는 동시 쓰기가 많은 경우에만 발생합니다(예: 대용량 파일을 복사하는 경우).

파일 시스템의 경우 디스크에서 실행되는 파일 시스템(예: 블록 장치)과 그렇지 않은 파일 시스템(fe nfs) 사이에는 큰 차이가 있습니다. 두 번째 경우에는 블록이 없기 때문에 블록 캐싱이 불가능합니다. 이들의 경우 소위 "버퍼 캐시"가 있습니다. 이는 기본적으로 여전히 캐싱(읽기 및 쓰기)이 있지만 메모리 블록을 중심으로 구성되지 않고 모든 크기의 I/O 조각을 중심으로 구성됨을 의미합니다.

예, Linux에는 블록 캐싱 메커니즘 없이 디스크 장치를 사용할 수 있는 "원시" 블록 장치가 있습니다. 그러나 이 문제는 그들에 의해 해결되지 않았습니다.

대신에 "저널링 파일 시스템"이라는 것이 있습니다. 저널 파일 시스템을 사용하면 파일 시스템은 다른 페이지보다 먼저 작성해야 하는 페이지를 커널에 지시할 수 있습니다. 파일 시스템에 저널링 메커니즘이 없으면 블록을 디스크에 기록하고(보다 정확하게는 블록 캐시에 기록), 커널은 최적이라고 생각하는 경우 실제 쓰기 작업을 실제로 수행합니다.

저널 파일 시스템은 각 쓰기 작업이 두 번 발생하는 것으로 생각할 수 있습니다. 먼저 "로그"(디스크의 예약된 영역)에 대해, 그리고 실제 위치에 대해서만 발생합니다. 시스템 충돌이나 디스크 오류가 발생하는 경우 디스크의 손상되지 않은 마지막 상태 내용을 로그에서 매우 빠르고 쉽게 재구성할 수 있습니다.

그러나 이렇게 하면 각 쓰기가 두 번 완료되어야 하므로 쓰기 성능이 크게 저하됩니다. 이것이 실제로 저널링 파일 시스템이 더 정교한 방식으로 작동하는 이유입니다. 다양한 복잡한 데이터 구조 작업을 사용하여 이러한 오버헤드를 거의 눈에 띄지 않는 수준으로 줄입니다. 하지만 어렵습니다. 예를 들어 ext2에 비해 ext3의 주요 개선 사항은 로깅 기능이 포함되어 있어 코드 크기가 기하급수적으로 증가한다는 것입니다.

Linux에서 블록 계층 API에는 "장벽" 메커니즘이 있습니다. 파일 시스템은 쓰기 작업 사이에 "장벽"을 둘 수 있습니다. 장벽은 데이터를 의미합니다.뒤쪽에배리어는 디스크에만 씁니다.뒤쪽에각 데이터앞으로장애물이 기록되었습니다. 저널링 파일 시스템은 장벽 메커니즘을 사용하여 실제 쓰기 작업에 필요한 순서에 대해 블록 계층에 지시합니다. 내가 아는 한 그들은 원시 장치 매핑을 사용하지 않습니다.

FreeBSD가 이에 대해 어떻게 반응할지 모르겠습니다. 어쩌면 블록 장치를 제거하면 모든 것이 블록 캐시 대신 버퍼 캐시로 작동한다는 의미일 수도 있습니다. 아니면 여기에 기록되지 않은 내용이 있습니다. 내부적으로 *BSD와 Linux 파일 시스템 세계 사이에는 큰 차이가 있습니다.

관련 정보