내 IO 요청 크기가 약 512K로 제한되는 이유는 무엇입니까?

내 IO 요청 크기가 약 512K로 제한되는 이유는 무엇입니까?

나는 /dev/sda읽기에 1MiB 블록 크기를 사용합니다. Linux는 IO 요청을 제한하는 것 같습니다.512KiB평균 크기는 512KiB입니다. 여기서 무슨 일이 일어나고 있는 걸까요? 이 동작에 대한 구성 옵션이 있습니까?

$ sudo dd iflag=direct if=/dev/sda bs=1M of=/dev/null status=progress
1545601024 bytes (1.5 GB, 1.4 GiB) copied, 10 s, 155 MB/s
1521+0 records in
1520+0 records out
...

dd명령이 실행 되면 rareq-sz512입니다.

희귀 크기 장치에 대한 읽기 요청의 평균 크기(KB)입니다.

--man iostat

$ iostat -d -x 3
...
Device            r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s  %rrqm  %wrqm r_await w_await aqu-sz rareq-sz wareq-sz  svctm  %util
sda            309.00    0.00 158149.33      0.00     0.00     0.00   0.00   0.00    5.24    0.00   1.42   511.81     0.00   1.11  34.27
dm-0             0.00    0.00      0.00      0.00     0.00     0.00   0.00   0.00    0.00    0.00   0.00     0.00     0.00   0.00   0.00
dm-1             0.00    0.00      0.00      0.00     0.00     0.00   0.00   0.00    0.00    0.00   0.00     0.00     0.00   0.00   0.00
dm-2             0.00    0.00      0.00      0.00     0.00     0.00   0.00   0.00    0.00    0.00   0.00     0.00     0.00   0.00   0.00
dm-3             0.00    0.00      0.00      0.00     0.00     0.00   0.00   0.00    0.00    0.00   0.00     0.00     0.00   0.00   0.00
...

커널 버전은 5.1.15-300.fc30.x86_64.is max_sectors_kb1280입니다.

$ cd /sys/class/block/sda/queue
$ grep -H . max_sectors_kb max_hw_sectors_kb max_segments max_segment_size optimal_io_size logical_block_size chunk_sectors
max_sectors_kb:1280
max_hw_sectors_kb:32767
max_segments:168
max_segment_size:65536
optimal_io_size:0
logical_block_size:512
chunk_sectors:0

기본적으로 BFQ I/O 스케줄러를 사용합니다. 나는 또한 나중에 테스트를 반복해 보았습니다 echo 0 | sudo tee wbt_lat_usec. 그런 다음 나중에 테스트를 반복해 보았습니다 echo mq-deadline|sudo tee scheduler. 결과는 여전히 동일합니다.

WBT 외에도 두 I/O 스케줄러 모두 기본 설정을 사용했습니다. 예를 들어 500 mq-deadlineiosched/read_expire0.5초에 해당합니다.

마지막 테스트(mq-deadline, WBT 비활성화) 중에 다음을 실행했습니다 btrace /dev/sda. 모든 요청이 서로 다른 두 부분으로 분할된 것으로 나타났습니다.

  8,0    0     3090     5.516361551 15201  Q   R 6496256 + 2048 [dd]
  8,0    0     3091     5.516370559 15201  X   R 6496256 / 6497600 [dd]
  8,0    0     3092     5.516374414 15201  G   R 6496256 + 1344 [dd]
  8,0    0     3093     5.516376502 15201  I   R 6496256 + 1344 [dd]
  8,0    0     3094     5.516388293 15201  G   R 6497600 + 704 [dd]
  8,0    0     3095     5.516388891 15201  I   R 6497600 + 704 [dd]
  8,0    0     3096     5.516400193   733  D   R 6496256 + 1344 [kworker/0:1H]
  8,0    0     3097     5.516427886   733  D   R 6497600 + 704 [kworker/0:1H]
  8,0    0     3098     5.521033332     0  C   R 6496256 + 1344 [0]
  8,0    0     3099     5.523001591     0  C   R 6497600 + 704 [0]

X——분할[소프트웨어] raid 또는 장치 매퍼 설정에서 들어오는 I/O는 장치 또는 내부 영역에 걸쳐 있을 수 있으며 서비스를 위해 더 작은 부분으로 분할되어야 합니다. 이는 부적절한 raid/dm 장치 설정으로 인한 성능 문제를 나타낼 수 있지만 정상적인 경계 조건의 일부일 수도 있습니다. dm은 특히 많은 I/O를 복제하는 데 좋지 않습니다.

--man blkparse

무시해야 할 것들iostat

%util번호는 무시하세요. 이번 버전에서는 깨졌습니다. (`dd`가 최고 속도로 실행되고 있지만 디스크 사용률은 20%에 불과합니다. 왜?)

아이디어 aqu-sz또한 영향을 받음%util을 기반으로 하기 때문에. 내 생각에는 이것이 여기 크기의 약 3배(100/34.27)라는 뜻이라고 생각합니다.

svtm번호는 무시하세요. "경고! 이 필드를 더 이상 신뢰하지 마십시오. 이 필드는 향후 sysstat 릴리스에서 제거될 예정입니다."

답변1

내 IO 요청 크기가 약 512K로 제한되는 이유는 무엇입니까?

I/O는 커밋된 방식과 도달한 다양한 제한(이 경우)으로 인해 /sys/block/sda/queue/max_segments"대략" 512KiB로 제한되어 있다고 생각합니다. 질문자는 blktrace우리가 이 미스터리를 추측할 수 있도록 다양한 보조 정보(커널 버전 및 출력 등)를 제공하는 데 시간을 투자했으니, 제가 어떻게 이런 결론에 도달했는지 살펴보겠습니다.

왜 […]는 다음으로 제한됩니다.~에 대한512K?

핵심은 질문자가 제목에 "about"을 주의 깊게 언급했다는 점에 주목하는 것입니다. 출력 결과를 보면 iostat512KiB의 값을 찾아야 한다고 생각하게 됩니다.

Device         [...] aqu-sz rareq-sz wareq-sz  svctm  %util
sda            [...]   1.42   511.81     0.00   1.11  34.27

blktrace(경유)는 blkparse몇 가지 정확한 값을 제공합니다.

  8,0    0     3090     5.516361551 15201  Q   R 6496256 + 2048 [dd]
  8,0    0     3091     5.516370559 15201  X   R 6496256 / 6497600 [dd]
  8,0    0     3092     5.516374414 15201  G   R 6496256 + 1344 [dd]
  8,0    0     3093     5.516376502 15201  I   R 6496256 + 1344 [dd]
  8,0    0     3094     5.516388293 15201  G   R 6497600 + 704 [dd]
  8,0    0     3095     5.516388891 15201  I   R 6497600 + 704 [dd]

(일반적으로 단일 섹터 크기는 512바이트일 것으로 예상합니다.) 따라서 dd크기 2048 섹터(1MiByte)의 섹터 6496256의 읽기 I/O는 두 부분으로 분할됩니다. 하나는 섹터 6496256 1344 섹터에서 시작하고 다른 하나는 1344 섹터를 읽습니다. 섹터 6496256에서 시작하고 섹터 6497600에서 시작하는 704 섹터입니다. 그래서분할 전 요청된 최대 크기는 1024개 섹터(512KiB)보다 약간 큽니다....근데 왜?

질문자가 언급했습니다 5.1.15-300.fc30.x86_64.Google 검색 Linux 분할 블록 I/O 커널나타나다Linux 장치 드라이버, 3판의 "16장. 블록 드라이버"그리고 언급

[...] 여러 장치에 제출하기 위해 bio_split파일을 청크로 분할하는 데 사용할 수 있는 호출bio

bios를 다른 장치로 보내려고 하기 때문에(md나 장치 매퍼가 할 수 있는 방식으로) 분할하지는 않지만 여전히 탐색할 영역을 제공합니다. 수색LXR의 5.1.15 Linux 커널 소스 코드bio_split파일에 대한 링크가 포함되어 있습니다.block/blk-merge.c. 이 파일에는 다음이 포함되어 있습니다.blk_queue_split()함수 호출을 위한 비특수 I/Oblk_bio_segment_split().

(휴식을 갖고 LXR을 탐색하고 싶다면 지금이 좋은 때입니다. 아래에서 계속 조사하고 더 간결하게 노력하겠습니다)

blk_bio_segment_split()변수의 max_sectors정렬에서 반환된 최종 값blk_max_size_offset()보고 q->limits.chunk_sectors0이면 반환합니다 q->limits.max_sectors. 클릭하면 max_sectors그것이 어떻게 max_sectors_kb파생되는지 확인할 수 있습니다.queue_max_sectors_store()이 시간은block/blk-sysfs.c. blk_bio_segment_split()로 돌아가서 max_segs변수는 다음에서 옵니다.queue_max_segments()Return q->limits.max_segments계속해서 blk_bio_segment_split()다음을 볼 수 있습니다.

    bio_for_each_bvec(bv, bio, iter) {

~에 따르면block/biovecs.txt우리는 다중 페이지 bvec을 반복하고 있습니다.

        if (sectors + (bv.bv_len >> 9) > max_sectors) {
            /*
             * Consider this a new segment if we're splitting in
             * the middle of this vector.
             */
            if (nsegs < max_segs &&
                sectors < max_sectors) {
                /* split in the middle of bvec */
                bv.bv_len = (max_sectors - sectors) << 9;
                bvec_split_segs(q, &bv, &nsegs,
                        &seg_size,
                        &front_seg_size,
                        &sectors, max_segs);
            }
            goto split;
        }

따라서 I/O 크기가 (질문자의 경우 1280KiB)보다 크면 max_sectors_kb분할됩니다(사용 가능한 세그먼트 및 섹터 공간이 있는 경우 분할하기 전에 현재 I/O를 최대한 많이 채웁니다). 부분으로 나누고 가능한 한 많이 추가하세요). 그러나 질문자의 경우 I/O는 "단지" 1MiB로 1280KiB 미만이므로 해당 경우에는 해당되지 않습니다. 더 아래에서 볼 수 있습니다.

        if (bvprvp) {
            if (seg_size + bv.bv_len > queue_max_segment_size(q))
                goto new_segment;
        [...]

queue_max_segment_size()반품 q->limits.max_segment_size. 이전에 본 것( if (sectors + (bv.bv_len >> 9) > max_sectors)) bv.bv_len이 바이트 단위라는 점을 고려하면(다른 이유는 무엇입니까? 512로 나누어야 할까요?) 질문자는 /sys/block/sda/queue/max_segment_size그것이 65336이라고 말했습니다. 그 가치가 무엇인지 알면 bv.bv_len...

[...]
new_segment:
        if (nsegs == max_segs)
            goto split;

        bvprv = bv;
        bvprvp = &bvprv;

        if (bv.bv_offset + bv.bv_len <= PAGE_SIZE) {
            nsegs++;
            seg_size = bv.bv_len;
            sectors += bv.bv_len >> 9;
            if (nsegs == 1 && seg_size > front_seg_size)
                front_seg_size = seg_size;
        } else if (bvec_split_segs(q, &bv, &nsegs, &seg_size,
                    &front_seg_size, &sectors, max_segs)) {
            goto split;
        }
    }

    do_split = false;

따라서 각각에 대해 bv단일 페이지인지 다중 페이지 bvec인지 확인합니다(크기가 <=인지 확인하여 PAGE_SIZE). 단일 페이지 bvec인 경우 세그먼트 수를 늘리고 일부 장부를 수행합니다. 다중 페이지 bvec인 경우 더 작은 세그먼트로 분할해야 하는지 확인합니다(코드는bvec_split_segs()비교를 수행합니다 get_max_segment_size(). 이 경우 세그먼트를 /sys/block/sda/queue/max_segment_size64KiB(이전에는 65336에 대해 이야기했음)보다 크지 않지만 168( max_segs)개 세그먼트를 넘지 않는 여러 세그먼트로 분할한다는 의미입니다. bvec_split_segs()세그먼트 제한에 도달했지만 모든 길이가 포함되지 않은 경우 bv로 이동합니다 . 그러나 1024/64 = 16개의 세그먼트만 생성한다고 split가정하면 결국 1MiB 미만의 I/O를 커밋할 필요가 없습니다. goto split질문자가 I/O를 통해 이동한 경로가 아닙니다.

거꾸로 외삽하여 "단일 페이지 크기의 세그먼트만" 가정하면 이는 bv.bv_offset + bv.bv_len<= 4096을 추론할 수 있음을 의미합니다.bv_offsetunsigned int그러면 이는 0 <= bv.bv_len<= 4096을 의미합니다. 따라서 우리는 goto new_segment조건부 선도를 before로 취하지 않는다는 것을 추론할 수도 있습니다 . 그런 다음 원래 Biovec에는 1024/4 = 256개의 세그먼트가 있어야 한다는 결론을 내립니다. 256 > 168 그래서 우리는split다음 으로 건너뛰기new_segment결과적으로 하나의 168세그먼트 I/O와 또 다른 88세그먼트 I/O가 생성됩니다. 168 * 4096 = 688128바이트, 88 * 4096 = 360448바이트 그런데 그래서 어쩌죠? 훌륭한:

688128 / 512 = 1344

360448 / 512 = 704

출력에 표시되는 숫자는 다음과 같습니다 blktrace.

[...]   R 6496256 + 2048 [dd]
[...]   R 6496256 / 6497600 [dd]
[...]   R 6496256 + 1344 [dd]
[...]   R 6496256 + 1344 [dd]
[...]   R 6497600 + 704 [dd]
[...]   R 6497600 + 704 [dd]

따라서 dd제가 사용하도록 제안하는 명령줄은 I/O가 단일 페이지 bvec를 형성하도록 하고 최대 세그먼트 수에 도달했으므로 다음 경계에서 I/O 분할이 발생합니다.672KB모든 I/O에 대해.

다중 페이지 bvec을 생성하기 위해 I/O를 다르게(예: 버퍼링된 I/O를 통해) 제출하면 다른 분할 지점이 표시될 것이라고 생각됩니다.

이 동작에 대한 구성 옵션이 있습니까?

순서 지정 - /sys/block/<block device>/queue/max_sectors_kb블록 계층을 통해 제출된 일반 I/O가 분할되기 전에 도달할 수 있는 최대 크기에 대한 제어이지만 이는 많은 기준 중 하나일 뿐입니다. 다른 제한(예: 최대 세그먼트)에 도달하면 블록 기반 I /O는 더 작은 크기로 분할할 수 있습니다. 또한 원시 SCSI 명령을 사용하는 경우 /sys/block/<block device>/queue/max_hw_sectors_kb최대 크기까지 I/O를 제출할 수 있지만 그렇게 하면 블록 계층을 우회하게 되어 더 큰 I/O가 거부됩니다.

사실 넌 할 수 있어Ilya Dryomov는 이러한 max_segments제한 사항을 설명합니다.2015년 6월 Ceph 사용자 스레드에서 "대형 IO를 작은 IO로 분할하는 krbd" 및나중에 rbd기기 수리(어느자체는 나중에 복원되었습니다).

위 내용에 대한 추가 확인은 "2MB가 512KB가 되면커널 블록 계층 관리자 Jens Axboe가 작성한 "Device Limits" 섹션에는 최대 세그먼트 제한을 더 간결하게 다루는 섹션이 있습니다.

관련 정보