Должны ли записи на жестком диске с выравниванием по секторам быть медленнее записи с выравниванием по секторам?

Справочная информация: я планирую использовать ZFS, и мне нужно найти правильный ashift параметр для моего жесткого диска, который должен быть log2(sector_size)например, 9 для 512-байтовых секторов.

Мой жесткий диск сообщает физический и логический размер сектора 512 байт. Я читал, что некоторые жесткие диски сообщают неверную информацию, чтобы предотвратить проблемы совместимости с операционными системами, которые используют 512-байтовые сектора. Я не уверен, так ли это с моим жестким диском.

Поэтому я написал небольшую программу, которая поможет мне определить истинный размер физического сектора. Программа открывает пустой раздел на моем жестком диске и записывает блоки по 4096 байт в 1000 случайно выбранных местоположений в пределах 1 ГиБ. Случайные местоположения сначала выравниваются до 4096 байтов, затем добавляется смещение. Программа выполняет эти 1000 случайных записей с использованием разных смещений и измеряет, сколько времени записи заняло каждое смещение. Первое смещение равно нулю, затем оно увеличивается с шагом 256 байтов.

При открытии раздела для записи я использую O_WRONLY | O_SYNC | O_DIRECT Флаги, чтобы получить как можно ближе к оборудованию, то есть обойти как можно больше кешей. Я также удостоверяюсь, что мой буфер правильно выровнен в памяти.

Вот что я ожидал:

  • Для ненулевых смещений адреса, по которым я пишу, не выровнены по физическим секторам жесткого диска (независимо от того, имеет ли он 512 или 4096 байтовых физических секторов). Существует по крайней мере один сектор, который должен быть изменен только частично, поэтому жесткий диск должен прочитать этот сектор, обновить его части и затем записать обратно. Это должно быть более медленным случаем, потому что происходит чтение (чтение-изменение-запись).
  • Для нулевого смещения, независимо от того, имеет ли жесткий диск физические сектора 512 или 4096 байт, операции записи не должны требовать чтения каких-либо секторов. Все сектора, затронутые записью, должны быть просто перезаписаны. Это должно быть быстрее.

Но на самом деле я не могу заметить никакой разницы. 1000 записей всегда занимает около 8,5 секунд. Смещение, кажется, не имеет никакого влияния:

Offset  Time (ms) for 1000 random writes
------  --------------------------------
0       8459.11
256     8450.69
512     8633.82
768     8533.94
1024    8467.36
1280    8450.63
1536    8525.72
1792    8533.96
2048    8450.64
2304    8450.79
2560    8442.37
2816    8442.38
3072    8442.28
3328    8450.82
3584    8442.27
3840    8450.81

Дополнительные замечания / замечания:

  • Запись единиц в 512 байт приводит к схожим числам (т.е. нет заметного влияния смещения).
  • Просто для случая, когда сам мой раздел не выровнен по границе физического сектора, я также попытался увеличить смещение с шагом в 1 байт. Таким образом, "идеальное" смещение будет найдено в конце концов - но все же я не смог определить разницу.

Кто-нибудь может объяснить это?

Для завершения, вот моя программа (на случай, если кто-нибудь захочет ее запустить, вставьте путь к пустому блочному устройству в open вызов):

#include <chrono>
#include <fcntl.h>
#include <iostream>
#include <random>
#include <unistd.h>

int main()
{
        const int bufferSize = 4096;
        char buffer[bufferSize] __attribute__((aligned(4096)));
        for (int offset = -256; offset < 4096; offset += 256)
        {
                std::mt19937 generator;
                std::uniform_int_distribution<int> distribution(0, 1024 * 1024 * 1024 / 4096);
                if (offset >= 0) std::cout << offset << "\t";
                else std::cout << "Warming up ..." << std::endl;
                int f = open("PATH_TO_EMPTY_BLOCK_DEVICE", O_WRONLY | O_SYNC | O_DIRECT);
                auto t0 = std::chrono::high_resolution_clock::now();
                for (int i = 0; i < 1000; ++i)
                {
                        lseek(f, SEEK_SET, 4096 * distribution(generator) + offset);
                        if (write(f, buffer, bufferSize) != bufferSize) exit(1);
                }
                auto t1 = std::chrono::high_resolution_clock::now();
                close(f);
                if (offset >= 0) std::cout << (1000 * std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0).count()) << std::endl;
        }

        return 0;
}

2 ответа

Для ненулевых смещений адреса, по которым я пишу, не выровнены по физическим секторам жесткого диска (независимо от того, имеет ли он 512 или 4096 байтовых физических секторов).

[...]

Просто для случая, когда сам мой раздел не выровнен по границе физического сектора, я также попытался увеличить смещение с шагом в 1 байт.

Какую ОС вы используете? Если это Linux, как вы смогли сделать запись с начальным смещением, которое не было кратно 512 байтам, когда вы использовали O_DIRECT против базового блочного устройства?

Должны ли записи на жестком диске с выравниванием по секторам быть медленнее записи с выравниванием по секторам?

Выравнивание по "истинному" размеру сектора должно быть не таким уж большим ударом, но насколько лучше сильно зависит от устройства, данных и шаблонов ( Toshiba утверждает, что снижение производительности из-за смещения может достигать 20%). Твердотельные накопители (о которых вы не спрашиваете, но, возможно, придется выполнить большое удаление, прежде чем размещать данные), являются отличным примером, поскольку плохое выравнивание записи может привести к ненужному усилению записи. Сказав это, мне сказали, что современные устройства имеют секторы намного больше, чем 4 Кбайт, но почти никогда не выставляют это более высоким уровням.

Кто-нибудь может объяснить это [результаты, которые я вижу]?

Что ж, вы, скорее всего, увидите влияние чтения-изменения-записи (RMW), когда попадете в самую быструю из возможных ситуаций, которая его поражает (так как разница будет наибольшей). Поскольку вы делаете случайные записи, которые заставляют ОС ждать истинного завершения, скорее всего, вы находитесь в более медленной ситуации, и удар по производительности просто теряется в шуме. Как уже говорили другие, вы также должны победить любой кеш, который может маскировать проблемы - если вы каким-то образом заполнили кеш секторами, которые будут использоваться процессом RMW, то снова попадание может быть полностью замаскировано. Это может быть ваш пример программы имеет недостатки. Вы рассматривали возможность использования fio?

Мой жесткий диск сообщает о физическом и логическом размере сектора 512 байт

Если диск хочет лгать до такой степени (не указывая лучший физический размер), попытка угадать его поведение после выравнивания разделов по 4 КБ будет сложной задачей. OpenZFS содержит список дисков, чей размер поддельного блока он будет пытаться компенсировать.

Основная причина, по которой я читал для людей, использующих Ashift не по умолчанию с ZFS, заключается в возможности добавления дисков, которые имеют собственный размер блока 4 Кбайт, в смесь на более позднем этапе.

4096 байт x 1000 раз = 4 МБ данных. Скорее всего, ваш жесткий диск имеет 64 МБ кэш-памяти, если не больше, 256 МБ не редкость на современных дисках.

Ваша методология будет работать лучше, если вы значительно увеличите размер записи, возможно, в 64 раза, чтобы реально увидеть характеристики физических дисков.

Другие вопросы по тегам