diff --git a/docs/config/layout-osd.en.md b/docs/config/layout-osd.en.md index 3ab5190a..b0fd7527 100644 --- a/docs/config/layout-osd.en.md +++ b/docs/config/layout-osd.en.md @@ -213,4 +213,5 @@ have enough RAM for the default 4 KB csum_block_size. Option 3 is recommended for SSD+HDD setups (because metadata SSDs will handle extra reads without any performance drop) and also *maybe* for NVMe all-flash setups when you don't have enough RAM (because NVMe drives have plenty -of read iops to spare). +of read iops to spare). [cached_io_meta](osd.en.md#cached_io_meta) may also +help to improve performance in this case for SSD+HDD setups. diff --git a/docs/config/layout-osd.ru.md b/docs/config/layout-osd.ru.md index 8ee7f3f7..49847580 100644 --- a/docs/config/layout-osd.ru.md +++ b/docs/config/layout-osd.ru.md @@ -232,3 +232,5 @@ csum_block_size данных. без снижения производительности. Также вариант 3 *может* рекомендоваться для All-Flash кластеров на основе NVMe-дисков, когда памяти НЕ достаточно, потому что NVMe-диски имеют огромный запас производительности по чтению. +Также улучшить производительность для SSD+HDD кластеров в данном случае +может помочь параметр [cached_io_meta](osd.ru.md#cached_io_meta). diff --git a/docs/config/osd.en.md b/docs/config/osd.en.md index 1ec108d5..6c15a59b 100644 --- a/docs/config/osd.en.md +++ b/docs/config/osd.en.md @@ -31,6 +31,9 @@ them, even without restarting by updating configuration in etcd. - [max_flusher_count](#max_flusher_count) - [inmemory_metadata](#inmemory_metadata) - [inmemory_journal](#inmemory_journal) +- [cached_io_data](#cached_io_data) +- [cached_io_meta](#cached_io_meta) +- [cached_io_journal](#cached_io_journal) - [journal_sector_buffer_count](#journal_sector_buffer_count) - [journal_no_same_sector_overwrites](#journal_no_same_sector_overwrites) - [throttle_small_writes](#throttle_small_writes) @@ -255,6 +258,48 @@ is typically very small because it's sufficient to have 16-32 MB journal for SSD OSDs. However, in theory it's possible that you'll want to turn it off for hybrid (HDD+SSD) OSDs with large journals on quick devices. +## cached_io_data + +- Type: boolean +- Default: false + +Read and write *data* through Linux page cache, i.e. use a file descriptor +opened with O_SYNC, but without O_DIRECT for I/O. May improve read +performance for hot data and slower disks - HDDs and maybe SATA SSDs. +Not recommended for desktop SSDs without capacitors because O_SYNC flushes +disk cache on every write. + +## cached_io_meta + +- Type: boolean +- Default: false + +Read and write *metadata* through Linux page cache. May improve read +performance only if your drives are relatively slow (HDD, SATA SSD), and +only if checksums are enabled and [inmemory_metadata](#inmemory_metadata) +is disabled, because in this case metadata blocks are read from disk +on every read request to verify checksums and caching them may reduce this +extra read load. + +Absolutely pointless to enable with enabled inmemory_metadata because all +metadata is kept in memory anyway, and likely pointless without checksums, +because in that case, metadata blocks are read from disk only during journal +flushing. + +If the same device is used for data and metadata, enabling [cached_io_data](#cached_io_data) +also enables this parameter, given that it isn't turned off explicitly. + +## cached_io_journal + +- Type: boolean +- Default: false + +Read and write *journal* through Linux page cache. May improve read +performance if [inmemory_journal](#inmemory_journal) is turned off. + +If the same device is used for metadata and journal, enabling [cached_io_meta](#cached_io_meta) +also enables this parameter, given that it isn't turned off explicitly. + ## journal_sector_buffer_count - Type: integer diff --git a/docs/config/osd.ru.md b/docs/config/osd.ru.md index 30c68f2c..0a1e962c 100644 --- a/docs/config/osd.ru.md +++ b/docs/config/osd.ru.md @@ -32,6 +32,9 @@ - [max_flusher_count](#max_flusher_count) - [inmemory_metadata](#inmemory_metadata) - [inmemory_journal](#inmemory_journal) +- [cached_io_data](#cached_io_data) +- [cached_io_meta](#cached_io_meta) +- [cached_io_journal](#cached_io_journal) - [journal_sector_buffer_count](#journal_sector_buffer_count) - [journal_no_same_sector_overwrites](#journal_no_same_sector_overwrites) - [throttle_small_writes](#throttle_small_writes) @@ -263,6 +266,52 @@ Flusher - это микро-поток (корутина), которая коп параметра может оказаться полезным для гибридных OSD (HDD+SSD) с большими журналами, расположенными на быстром по сравнению с HDD устройстве. +## cached_io_data + +- Тип: булево (да/нет) +- Значение по умолчанию: false + +Читать и записывать *данные* через системный кэш Linux (page cache), то есть, +использовать для данных файловый дескриптор, открытый без флага O_DIRECT, но +с флагом O_SYNC. Может улучшить скорость чтения для относительно медленных +дисков - HDD и, возможно, SATA SSD. Не рекомендуется для потребительских +SSD без конденсаторов, так как O_SYNC сбрасывает кэш диска при каждой записи. + +## cached_io_meta + +- Тип: булево (да/нет) +- Значение по умолчанию: false + +Читать и записывать *метаданные* через системный кэш Linux. Может улучшить +скорость чтения, если у вас медленные диски, и только если контрольные суммы +включены, а параметр [inmemory_metadata](#inmemory_metadata) отключён, так +как в этом случае блоки метаданных читаются с диска при каждом запросе чтения +для проверки контрольных сумм и их кэширование может снизить дополнительную +нагрузку на диск. + +Абсолютно бессмысленно включать данный параметр, если параметр +inmemory_metadata включён (по умолчанию это так), и также вероятно +бессмысленно включать его, если не включены контрольные суммы, так как в +этом случае блоки метаданных читаются с диска только во время сброса +журнала. + +Если одно и то же устройство используется для данных и метаданных, включение +[cached_io_data](#cached_io_data) также включает данный параметр, при +условии, что он не отключён явным образом. + +## cached_io_journal + +- Тип: булево (да/нет) +- Значение по умолчанию: false + +Читать и записывать *журнал* через системный кэш Linux. Может улучшить +скорость чтения, если параметр [inmemory_journal](#inmemory_journal) +отключён. + +Если одно и то же устройство используется для метаданных и журнала, +включение [cached_io_meta](#cached_io_meta) также включает данный +параметр, при условии, что он не отключён явным образом. + ## journal_sector_buffer_count - Тип: целое число diff --git a/docs/config/src/layout-osd.yml b/docs/config/src/layout-osd.yml index f36f88bd..4b97fd09 100644 --- a/docs/config/src/layout-osd.yml +++ b/docs/config/src/layout-osd.yml @@ -244,7 +244,8 @@ Option 3 is recommended for SSD+HDD setups (because metadata SSDs will handle extra reads without any performance drop) and also *maybe* for NVMe all-flash setups when you don't have enough RAM (because NVMe drives have plenty - of read iops to spare). + of read iops to spare). [cached_io_meta](osd.en.md#cached_io_meta) may also + help to improve performance in this case for SSD+HDD setups. info_ru: | Размер блока расчёта контрольных сумм. @@ -275,3 +276,5 @@ без снижения производительности. Также вариант 3 *может* рекомендоваться для All-Flash кластеров на основе NVMe-дисков, когда памяти НЕ достаточно, потому что NVMe-диски имеют огромный запас производительности по чтению. + Также улучшить производительность для SSD+HDD кластеров в данном случае + может помочь параметр [cached_io_meta](osd.ru.md#cached_io_meta). diff --git a/docs/config/src/osd.yml b/docs/config/src/osd.yml index 6e61fa57..519bbedd 100644 --- a/docs/config/src/osd.yml +++ b/docs/config/src/osd.yml @@ -260,6 +260,73 @@ достаточно 16- или 32-мегабайтного журнала. Однако в теории отключение параметра может оказаться полезным для гибридных OSD (HDD+SSD) с большими журналами, расположенными на быстром по сравнению с HDD устройстве. +- name: cached_io_data + type: bool + default: false + info: | + Read and write *data* through Linux page cache, i.e. use a file descriptor + opened with O_SYNC, but without O_DIRECT for I/O. May improve read + performance for hot data and slower disks - HDDs and maybe SATA SSDs. + Not recommended for desktop SSDs without capacitors because O_SYNC flushes + disk cache on every write. + info_ru: | + Читать и записывать *данные* через системный кэш Linux (page cache), то есть, + использовать для данных файловый дескриптор, открытый без флага O_DIRECT, но + с флагом O_SYNC. Может улучшить скорость чтения для относительно медленных + дисков - HDD и, возможно, SATA SSD. Не рекомендуется для потребительских + SSD без конденсаторов, так как O_SYNC сбрасывает кэш диска при каждой записи. +- name: cached_io_meta + type: bool + default: false + info: | + Read and write *metadata* through Linux page cache. May improve read + performance only if your drives are relatively slow (HDD, SATA SSD), and + only if checksums are enabled and [inmemory_metadata](#inmemory_metadata) + is disabled, because in this case metadata blocks are read from disk + on every read request to verify checksums and caching them may reduce this + extra read load. + + Absolutely pointless to enable with enabled inmemory_metadata because all + metadata is kept in memory anyway, and likely pointless without checksums, + because in that case, metadata blocks are read from disk only during journal + flushing. + + If the same device is used for data and metadata, enabling [cached_io_data](#cached_io_data) + also enables this parameter, given that it isn't turned off explicitly. + info_ru: | + Читать и записывать *метаданные* через системный кэш Linux. Может улучшить + скорость чтения, если у вас медленные диски, и только если контрольные суммы + включены, а параметр [inmemory_metadata](#inmemory_metadata) отключён, так + как в этом случае блоки метаданных читаются с диска при каждом запросе чтения + для проверки контрольных сумм и их кэширование может снизить дополнительную + нагрузку на диск. + + Абсолютно бессмысленно включать данный параметр, если параметр + inmemory_metadata включён (по умолчанию это так), и также вероятно + бессмысленно включать его, если не включены контрольные суммы, так как в + этом случае блоки метаданных читаются с диска только во время сброса + журнала. + + Если одно и то же устройство используется для данных и метаданных, включение + [cached_io_data](#cached_io_data) также включает данный параметр, при + условии, что он не отключён явным образом. +- name: cached_io_journal + type: bool + default: false + info: | + Read and write *journal* through Linux page cache. May improve read + performance if [inmemory_journal](#inmemory_journal) is turned off. + + If the same device is used for metadata and journal, enabling [cached_io_meta](#cached_io_meta) + also enables this parameter, given that it isn't turned off explicitly. + info_ru: | + Читать и записывать *журнал* через системный кэш Linux. Может улучшить + скорость чтения, если параметр [inmemory_journal](#inmemory_journal) + отключён. + + Если одно и то же устройство используется для метаданных и журнала, + включение [cached_io_meta](#cached_io_meta) также включает данный + параметр, при условии, что он не отключён явным образом. - name: journal_sector_buffer_count type: int default: 32 diff --git a/docs/usage/disk.en.md b/docs/usage/disk.en.md index 6ca3fe1b..13680829 100644 --- a/docs/usage/disk.en.md +++ b/docs/usage/disk.en.md @@ -102,8 +102,9 @@ checks the device cache status on start and tries to disable cache for SATA/SAS If it doesn't succeed it issues a warning in the system log. You can also pass other OSD options here as arguments and they'll be persisted -to the superblock: max_write_iodepth, max_write_iodepth, min_flusher_count, -max_flusher_count, inmemory_metadata, inmemory_journal, journal_sector_buffer_count, +in the superblock: cached_io_data, cached_io_meta, cached_io_journal, +inmemory_metadata, inmemory_journal, max_write_iodepth, +min_flusher_count, max_flusher_count, journal_sector_buffer_count, journal_no_same_sector_overwrites, throttle_small_writes, throttle_target_iops, throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us. See [Runtime OSD Parameters](../config/osd.en.md) for details. diff --git a/docs/usage/disk.ru.md b/docs/usage/disk.ru.md index 274d4fef..77972fe4 100644 --- a/docs/usage/disk.ru.md +++ b/docs/usage/disk.ru.md @@ -103,8 +103,9 @@ vitastor-disk - инструмент командной строки для уп это не удаётся, в системный журнал выводится предупреждение. Вы можете передать данной команде и некоторые другие опции OSD в качестве аргументов -и они тоже будут сохранены в суперблок: max_write_iodepth, max_write_iodepth, min_flusher_count, -max_flusher_count, inmemory_metadata, inmemory_journal, journal_sector_buffer_count, +и они тоже будут сохранены в суперблок: cached_io_data, cached_io_meta, +cached_io_journal, inmemory_metadata, inmemory_journal, max_write_iodepth, +min_flusher_count, max_flusher_count, journal_sector_buffer_count, journal_no_same_sector_overwrites, throttle_small_writes, throttle_target_iops, throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us. Читайте об этих параметрах подробнее в разделе [Изменяемые параметры OSD](../config/osd.ru.md). diff --git a/src/blockstore_disk.cpp b/src/blockstore_disk.cpp index 415b167a..6711349e 100644 --- a/src/blockstore_disk.cpp +++ b/src/blockstore_disk.cpp @@ -45,6 +45,13 @@ void blockstore_disk_t::parse_config(std::map & config meta_block_size = parse_size(config["meta_block_size"]); bitmap_granularity = parse_size(config["bitmap_granularity"]); meta_format = stoull_full(config["meta_format"]); + cached_io_data = config["cached_io_data"] == "true" || config["cached_io_data"] == "yes" || config["cached_io_data"] == "1"; + cached_io_meta = cached_io_data && (meta_device == data_device || meta_device == "") && + config.find("cached_io_meta") == config.end() || + config["cached_io_meta"] == "true" || config["cached_io_meta"] == "yes" || config["cached_io_meta"] == "1"; + cached_io_journal = cached_io_meta && (journal_device == meta_device || journal_device == "") && + config.find("cached_io_journal") == config.end() || + config["cached_io_journal"] == "true" || config["cached_io_journal"] == "yes" || config["cached_io_journal"] == "1"; if (config["data_csum_type"] == "crc32c") { data_csum_type = BLOCKSTORE_CSUM_CRC32C; @@ -267,7 +274,7 @@ static void check_size(int fd, uint64_t *size, uint64_t *sectsize, std::string n void blockstore_disk_t::open_data() { - data_fd = open(data_device.c_str(), O_DIRECT|O_RDWR); + data_fd = open(data_device.c_str(), (cached_io_data ? O_SYNC : O_DIRECT) | O_RDWR); if (data_fd == -1) { throw std::runtime_error("Failed to open data device "+data_device+": "+std::string(strerror(errno))); @@ -292,9 +299,9 @@ void blockstore_disk_t::open_data() void blockstore_disk_t::open_meta() { - if (meta_device != data_device) + if (meta_device != data_device || cached_io_meta != cached_io_data) { - meta_fd = open(meta_device.c_str(), O_DIRECT|O_RDWR); + meta_fd = open(meta_device.c_str(), (cached_io_meta ? O_SYNC : O_DIRECT) | O_RDWR); if (meta_fd == -1) { throw std::runtime_error("Failed to open metadata device "+meta_device+": "+std::string(strerror(errno))); @@ -304,7 +311,7 @@ void blockstore_disk_t::open_meta() { throw std::runtime_error("meta_offset exceeds device size = "+std::to_string(meta_device_size)); } - if (!disable_flock && flock(meta_fd, LOCK_EX|LOCK_NB) != 0) + if (!disable_flock && meta_device != data_device && flock(meta_fd, LOCK_EX|LOCK_NB) != 0) { throw std::runtime_error(std::string("Failed to lock metadata device: ") + strerror(errno)); } @@ -330,15 +337,15 @@ void blockstore_disk_t::open_meta() void blockstore_disk_t::open_journal() { - if (journal_device != meta_device) + if (journal_device != meta_device || cached_io_journal != cached_io_meta) { - journal_fd = open(journal_device.c_str(), O_DIRECT|O_RDWR); + journal_fd = open(journal_device.c_str(), (cached_io_journal ? O_SYNC : O_DIRECT) | O_RDWR); if (journal_fd == -1) { throw std::runtime_error("Failed to open journal device "+journal_device+": "+std::string(strerror(errno))); } check_size(journal_fd, &journal_device_size, &journal_device_sect, "journal device"); - if (!disable_flock && flock(journal_fd, LOCK_EX|LOCK_NB) != 0) + if (!disable_flock && journal_device != meta_device && flock(journal_fd, LOCK_EX|LOCK_NB) != 0) { throw std::runtime_error(std::string("Failed to lock journal device: ") + strerror(errno)); } diff --git a/src/blockstore_disk.h b/src/blockstore_disk.h index 5426de0e..58bfb7cf 100644 --- a/src/blockstore_disk.h +++ b/src/blockstore_disk.h @@ -31,6 +31,8 @@ struct blockstore_disk_t uint32_t csum_block_size = 4096; // By default, Blockstore locks all opened devices exclusively. This option can be used to disable locking bool disable_flock = false; + // Use Linux page cache for reads and writes, i.e. open FDs with O_SYNC instead of O_DIRECT + bool cached_io_data = false, cached_io_meta = false, cached_io_journal = false; int meta_fd = -1, data_fd = -1, journal_fd = -1; uint64_t meta_offset, meta_device_sect, meta_device_size, meta_len, meta_format = 0; diff --git a/src/disk_tool.cpp b/src/disk_tool.cpp index 5d5dcfe9..310e38ef 100644 --- a/src/disk_tool.cpp +++ b/src/disk_tool.cpp @@ -74,8 +74,9 @@ static const char *help_text = " If it doesn't succeed it issues a warning in the system log.\n" " \n" " You can also pass other OSD options here as arguments and they'll be persisted\n" - " to the superblock: max_write_iodepth, max_write_iodepth, min_flusher_count,\n" - " max_flusher_count, inmemory_metadata, inmemory_journal, journal_sector_buffer_count,\n" + " in the superblock: cached_io_data, cached_io_meta, cached_io_journal,\n" + " inmemory_metadata, inmemory_journal, max_write_iodepth,\n" + " min_flusher_count, max_flusher_count, journal_sector_buffer_count,\n" " journal_no_same_sector_overwrites, throttle_small_writes, throttle_target_iops,\n" " throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us.\n" "\n" diff --git a/src/disk_tool_prepare.cpp b/src/disk_tool_prepare.cpp index e6f794fd..610b9737 100644 --- a/src/disk_tool_prepare.cpp +++ b/src/disk_tool_prepare.cpp @@ -8,6 +8,9 @@ int disk_tool_t::prepare_one(std::map options, int is_hdd) { static const char *allow_additional_params[] = { + "cached_io_data", + "cached_io_meta", + "cached_io_journal", "max_write_iodepth", "max_write_iodepth", "min_flusher_count", @@ -116,6 +119,7 @@ int disk_tool_t::prepare_one(std::map options, int is_ try { dsk.parse_config(options); + dsk.cached_io_data = dsk.cached_io_meta = dsk.cached_io_journal = false; dsk.open_data(); dsk.open_meta(); dsk.open_journal(); @@ -479,6 +483,7 @@ int disk_tool_t::get_meta_partition(std::vector & ssds, std { blockstore_disk_t dsk; dsk.parse_config(options); + dsk.cached_io_data = dsk.cached_io_meta = dsk.cached_io_journal = false; dsk.open_data(); dsk.open_meta(); dsk.open_journal(); diff --git a/src/disk_tool_resize.cpp b/src/disk_tool_resize.cpp index d0b32060..9704026b 100644 --- a/src/disk_tool_resize.cpp +++ b/src/disk_tool_resize.cpp @@ -91,6 +91,7 @@ int disk_tool_t::resize_parse_params() try { dsk.parse_config(options); + dsk.cached_io_data = dsk.cached_io_meta = dsk.cached_io_journal = false; dsk.open_data(); dsk.open_meta(); dsk.open_journal();