LINUX.ORG.RU

В ядро Linux добавлена возможность буферизированной работы с ФС без кеширования

 , ,


0

2

В master ядра Linux принята серия патчей, позволяющая отдельным программам работать с файловой системой без использования страничного кеша.

Современные NVMe устройства работают настолько быстро, что страничный кеш оказывается полностью заполнен в течении нескольких секунд, в результате чего начинается экстренный сброс данных на диск. После сброса данных круг повторяется заново. Такой цикл не позволяет достичь пика производительности диска, ведет к неоптимальному использованию памяти и непредсказуемым задержкам, что сказывается на работе как десктопных GUI приложений, так и баз данных, веб-серверов, и т.д.

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

Предложенный подход решает эту проблему: вместо отправки запроса напрямую в диск, запрос все ещё проходит через страничный кеш, но только для буферизации. Как только данные попадают в кеш, ядро инициирует необходимые дисковые операции, дожидается их выполнения, завершает системный вызов, и инвалидирует страницу кеша. На приложение не накладывается никаких дополнительных ограничений.

По словам автора (Jens Axboe), ему удалось добиться увеличения производительности на 65% в тестовом сценарии, обеспечив предсказуемые задержки операций и заметно снизив нагрузку на CPU.

Чтобы использовать новую возможность, нужно установить флаг операции RWF_UNCACHED. Для приложений, использующих традиционные интерфейсы вроде read(3) и write(3), потребуется переход на функции preadv2(2) и pwritev2(2), т.к. только эти функции позволяют передавать флаги операций. Для приложений, использующих io_uring, достаточно выставить флаг в sqe->rw_flags. Таким образом, приложение может контролировать, какие данные нужно кешировать, а какие – нет.

Подробности

Перемещено dataman из kernel



Последнее исправление: gaylord (всего исправлений: 8)
Ответ на: комментарий от dataman

Больше месяца назад?

Да, но ядро ещё не вышло. Это будет в составе 6.14. Я решил это отдельной новостью сделать, потому что, кажется, это довольно важная веха, которая позволит тому же постгресу наконец-то перестать перекешировать ненужное.

gaylord
() автор топика
Ответ на: комментарий от anonymous

Интересно, когда эта фича докатится до юзерспейса

В 6.14 будет доступно, а насколько быстро приложения до этого доберутся это уже большой вопрос.

gaylord
() автор топика

Современные NVMe устройства работают настолько быстро, что страничный кеш оказывается полностью заполнен в течении нескольких секунд, в результате чего начинается экстренный сброс данных на диск. После сброса данных круг повторяется заново. Такой цикл не позволяет достичь пика производительности диска,

Ага, и вместо того чтобы исправить битую логику работы кеша, они начали лепить костыли с полукешом, да ещё и требовать от софта указания на то, что ему нужен этот режим.

firkax ★★★★★
()
Ответ на: комментарий от gaylord

позволит тому же постгресу наконец-то перестать перекешировать ненужное

А постгрес не самостоятельно своими кешами управляет?

[edit] а да, прочитал

требуется использовать выравненные блоки данных по 512 или 4096 байт (в зависимости от размера блока диска). Это делает затруднительным использование этой техники в таких приложениях как PostgreSQL

Ну это какой-то позор, теперь уже не ядра а постгреса, не осилить работу с блоками а таком солидном уже возрасте.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от gaylord

И что, что полно систем с hdd? Это в данном контесте не имеет значения. И на всякий случай поясню: я ни в коем случае не хочу сказать, будто ядро должно проверять тип накопителя для вкл/выкл этой опции, или что оно должно замерять его скорость перед началом работы. Я о том, что алгоритм кеша походу кривой и костыльный, раз он ломается от непредусмотренной скорости работы накопителя. Ладно, простим, раз он и правда делался без учёта таких скоростей, но дальше должно последовать исправление, а не накидывание костылей чтобы спрятать проблему. И никаких опций монтирования для этого тоже не должно быть.

firkax ★★★★★
()
Ответ на: комментарий от gaylord

Я знаю. Даже признаюсь, что сам пробовал его использовать и у меня так и не получилось прочитать с его помощью хоть что-то (всегда выдавало ошибку, хотя выравнивания, даже на 1048576 байт, я делал). К счастью, на линуксе я прогу только тестировал, а прод у неё фрибсд, в котором O_DIRECT работает без левых проблем, так что я на это дело забил и не стал дальше разбираться. Но в новости сказано не про это, а про то что они не смогли поблочную работу организовать.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Ты не понимаешь проблему. У тебя современный накопитель может писать по три гигабайта в секунду. Это моментально выжирает всю память без какого-либо смысла. Наверное имело бы смысл сделать эвристику на основе типа диска, и, кажется, теперь это сделать будет легче.

gaylord
() автор топика
Ответ на: комментарий от gaylord

Всё я понимаю.

Это моментально выжирает всю память без какого-либо смысла.

Выжирает из-за дефективных алгоритмов кеширования.

Наверное имело бы смысл сделать эвристику на основе типа диска

Ещё раз повторю: нет, никаких выборов на основании как типа накопителя, так и даже его скорости, быть не должно. Это вредные костыли. Нужно исправить алгоритм управления памятью чтобы быстрая запись (хоть 3гб/сек хоть 10гб/сек) не приводила к засорению памяти. И третий раз повторю: не в виде отдельной ветки if(speed>gb/s) а в виде алгоритма, который своими силами динамически всё делает.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Нужно исправить алгоритм управления памятью чтобы быстрая запись (хоть 3гб/сек хоть 10гб/сек) не приводила к засорению памяти.

Так вот и принесли. Я думаю, что это станет дефолтом через какое-то время, по крайней мере для дисков с rotational=0.

gaylord
() автор топика
Ответ на: комментарий от firkax

Алгоритм должен одинаково хорошо управлять в обоих случаях.

Он может это делать только в том случае, если вход и выход сбалансированы. То есть ты накидываешь столько же, сколько скидываешь. Это либо вот это, либо mount -o sync.

gaylord
() автор топика
Ответ на: комментарий от gaylord

Он может это делать только в том случае ...

Я не сомневаюсь, что линуксовый алгоритм может нормально работать только в узком диапазоне разных обстоятельств. Хотя ситуация улучшается, вот про 12309 уже почти не вспоминают.

Речь как раз про то, что такая ситуация - не норма, и алгоритм надо исправлять - алгоритм должен работать хорошо (в рамках возможностей железа, разумеется) во всех случаях и делать это самостоятельно.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от gaylord

Ты глупость написал. С такой «ситуацией» линукс как раз справляется, просто введи dd if=/dev/zero of=filename bs=1048576, только надо где-то найти древний HDD у которого такая маленькая скорость, и увидишь, что ничего плохого происходить не будет. В скорости генерации нулей /dev/zero, я надеюсь, ты не сомневаешься.

firkax ★★★★★
()
Ответ на: комментарий от gaylord

Все ручки уже есть. vm.dirty_background_bytes задаёт нижнюю границу, начиная с которой грязный кэш начинает сбрасываться на диск, vm.dirty_bytes задаёт верхнюю границу, выше которой грязный кэш не растёт, vm.dirty_writeback_centisecs задаёт период запуска сброса. Если у тебя быстрый носитель, поставь период поменьше, а верхнюю границу повыше.

А у Дженса прирост вышел просто из-за меньшего количества переключений контекста. Ведь отключение writeback кеширования отключает по сути активацию pdflush.

iliyap ★★★★★
()
Ответ на: комментарий от iliyap

Все ручки уже есть. vm.dirty_background_bytes задаёт нижнюю границу, начиная с которой грязный кэш начинает сбрасываться на диск, vm.dirty_bytes задаёт верхнюю границу, выше которой грязный кэш не растёт, vm.dirty_writeback_centisecs задаёт период запуска сброса. Если у тебя быстрый носитель, поставь период поменьше, а верхнюю границу повыше.

В теории да, но на практике цифры все равно прыгают.

А у Дженса прирост вышел просто из-за меньшего количества переключений контекста. Ведь отключение writeback кеширования отключает по сути активацию pdflush.

Там все куда сложнее, из уравнения исключается kswapd, но основная проблема с ним это не контекст свичи, а попытки оптимизировать сброс.

gaylord
() автор топика
Ответ на: комментарий от gaylord

То есть ты накидываешь столько же, сколько скидываешь

Так вроде у быстрого диска содержимое кэша при записи наоборот должно быстрее скидываться на диск и незаписанный кэш должен уменьшаться. Почему же он увеличивается?

watchcat382
()
Ответ на: комментарий от firkax

Тип диска ни при чём! Скорость - тоже! Алгоритм должен одинаково хорошо управлять в обоих случаях.

Наверняка, в алгоритме придётся самому запускать таймер и определять эту скорость. Сопоставлять с размером оперативки и делать вывод.

gag ★★★★★
()
Ответ на: комментарий от watchcat382

Если коротко, то потому что кеш общий на всю систему и пытается балансировать между всем существующими кейсами. Ожидаемо, делает это хуже, чем мог бы, если бы был специализированным.

gaylord
() автор топика
Ответ на: комментарий от gaylord

Вот и мне наболело, когда ради этого дискового кэша пол фаерфокса улетает в своп. А файл записывался, и обращений затем к нему не было, т.е. зря полезные данные активных программ были выгружены.

gag ★★★★★
()
Ответ на: комментарий от gag

Да, все так. Поэтому мне и кажется, что uncached режим вскоре станет дефолтным для nvme накопителей, потому что весь предыдущий опыт вышел в окно когда консьюмерские девайсы уже по 300к iops влегкую выдают. Кеширование теперь только мешает.

gaylord
() автор топика
Ответ на: комментарий от gag

Ты опять описываешь костыль. Какая там скорость - не важно, важно поддерживать «здоровое» состояние памяти вне зависимости от того, с какой скоростью в неё добавляется мусор.

firkax ★★★★★
()
Ответ на: комментарий от gag

Налицо неправильная оценка полезности тех или иных страниц. Вот её и надо исправлять. Вероятно там сделано тупое LRU, раз оно так себя ведёт. Как минимум могли бы учесть частоту обращений. Ещё лучше, наверно, двумерная метрика (в которой и частота и LRU) и балансировать чтобы топ обеих сторон попадал в память, но не выгружал друг друга.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Какая там скорость - не важно, важно поддерживать «здоровое» состояние памяти вне зависимости от того, с какой скоростью в неё добавляется мусор.

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

gaylord
() автор топика
Ответ на: комментарий от gaylord

Потому что как только самый медленный носитель (флешка) забьет грязными данными весь кеш, встанет вся остальная система

Повторю ещё раз, сделай dd if=/dev/zero of=filename bs=1048576 на медленной флешке и обнаружь что никакую память она не забивает. Память забивается чистыми данными, а не грязными. И то, что ядро не умеет их правильно вовремя дропать - именно дефективность алгоритма.

А анон в очередной раз предлагает убогий костыль.

firkax ★★★★★
()
Ответ на: комментарий от gaylord

А задержка какая? Все эти дикие IOPSы от многопотока, который далеко не всем нужен. У меня 99% юзкейсов это однопоток по-моему. Уверен, что RAM тут на порядки быстрей NVMe.

vbr ★★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Ответ на: комментарий от vbr

А задержка какая? Все эти дикие IOPSы от многопотока, который далеко не всем нужен. У меня 99% юзкейсов это однопоток по-моему. Уверен, что RAM тут на порядки быстрей NVMe.

Десятки микросекунд обычно. Цель в том, чтобы кешировать то, что нужно, а не то, что получилось. А это сложно, и возможно лучше сделать флаг «кешируй», чем «не кешируй». А может быть и нет. Увидим :)

gaylord
() автор топика
Ответ на: комментарий от gaylord

Вообще я подозреваю, что кешировать всё подряд это околонулевые затраты. Ты отдаёшь команду на трансфер с PCI-шины в указанный адрес памяти, скорей всего так ведь. Потом трансфер заканчивается и ты эту память передаёшь в кеши, а приложению уже в юзерспейс копируешь через его API что ему там надо.

vbr ★★★★★
()
Ответ на: комментарий от vbr

Вообще я подозреваю, что кешировать всё подряд это околонулевые затраты.

Нет, потому что потом это надо выкидывать из кеша, когда требуется аллоцировать память кому-то другому. Это, очевидно, быстрее, чем сбрасывать грязное на диск, но вот тебе цифры cache/nocache для чтения:


Reading bs 65536, uncached 0
  1s: 145945MB/sec
  2s: 158067MB/sec
  3s: 157007MB/sec
  4s: 148622MB/sec
  5s: 118824MB/sec
  6s: 70494MB/sec
  7s: 41754MB/sec
  8s: 90811MB/sec
  9s: 92204MB/sec
 10s: 95178MB/sec
 11s: 95488MB/sec
 12s: 95552MB/sec
 13s: 96275MB/sec

Reading bs 65536, uncached 1
  1s: 153144MB/sec
  2s: 156760MB/sec
  3s: 158110MB/sec
  4s: 158009MB/sec
  5s: 158043MB/sec
  6s: 157638MB/sec
  7s: 157999MB/sec
  8s: 158024MB/sec
  9s: 157764MB/sec
 10s: 157477MB/sec
 11s: 157417MB/sec
 12s: 157455MB/sec
 13s: 157233MB/sec

Все потому что нет необходимости делать reclaim.

gaylord
() автор топика
Ответ на: комментарий от vbr

Не понимаю, какие там могут быть затраты на сброс кеша, это же просто перещёлкивание нескольких указателей.

Добро пожаловать в чудесный мир mm/ :)

gaylord
() автор топика