Pull to refresh

Comments 27

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

Извините, если не увидел, но возник вопрос: а какой дистрибутив Linux при этом использовался? И не было ли проверки на аналогичное поведение у разных дистрибутивов, например сравнение с Debian или Ubuntu?

Поясню минусы: это работа ядра, дистрибутив не имеет значения (с точностью до параметров по-умолчанию).

Дополнительное пояснение, внимательные читатели увидели, что тестирование проводилось на Ubuntu. Хотя это автором прямо и не писалось, но видно из приведенных логов.


Кто наверняка к моменту чтения комментариев уже упустил, что автор этого сам не писал, но запомнил что тест был на убунте и клацнул вниз за глупый вопрос о дистрибутиве и предложения сравнить Ubuntu с Debian или Ubuntu.

Сложно сказать, насколько низкий уровень работы с диском у указанной QuestDB, но в Винде обычно базы данных (типа MS SQL Server) при работе с данными полностью отключают механизмы кэшей ОС, используемые для прикладных приложений, и реализуют логику кэширований на уровне движка/ядра СУБД. В частности при работе с файлами используются флаги FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING, немного об этом можно почитать например по этой или этой ссылке или в MSDN.

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

В данном случае достаточно было бы FILE_FLAG_RANDOM_ACCESS. Интересно, какой аналог этого флага на linux...

Так есть же в статье: "системный вызов madvise с флагом MADV_RANDOM".

Попробуйте посмореть на это с другой стороны и не выдавать нужду за добродетель. Кэш винды плохо помогает серверным нагрузкам, вот и приходится подменять его самодельным сурогатом. Линуксовый же кэш однозначно хорош для серверных нагрузок, и прикладные разработчики скорее всего реализуют его хуже.
Другой вопрос в том, что из коробки этот дисковый кэш в Linux настроен неверно и тормозит многие нагрузки (например БД). Настроить его правильно с удовольствием поможет RH (разумеется за деньги). Ну или специалист, которого судя по настройкам *dirty* из статьи у разрабов нет.

С этим полностью согласен, в линуксе всё хотя бы предсказуемо, т.к. известно как всё работает. Логика винды же иногда черный ящик, несмотря на достаточно подробное описание некоторых механизмов в MSDN (может работать не совсем так, как описано, либо есть еще куча нюансов/влияние других факторов).

Зависит от СУБД. MySQL любит сам кешами рулить (innodb buffer pool), а PostgreSQL имеет относительно небольшой shared memory кеш, а остальное отдаёт на откуп ОС и надеется на её алгоритмы кеширования.

Как по мне подход MySQL правильнее т.к. ты лучше знаешь как правильно управлять своими объектами. Но тут возможны варианты.

Я вот задумался, когда я работал с другой БД (SqlAnywhere), там вообще считалось вредным работать с кешем на уровне ФС потому как БД думает, что она данные сохранила, а они еще не были сброшены на диск, и любая теоретическая потеря питания могла поломать данные.

А здесь это считается нормальным.

Мало чего знаю про QuestDB, но писать каждую колонку отдельно, записывая одну строку, когда этих колонок сотни, это несколько жесть по нынешним временам. Колонки хороши для чтения, и для batch insert большого количества строк сразу. А для добавления одной строки - можно делать одну запись, а не 100, скажем в LSM, которое по мере наполнения распаковывается в колонки фоновым процессом.

Да вроде бы они по одной строчке и не рекомендуют вставлять. Ну и у них WAL там есть, колонки Append-only - в итоге паттерн доступа последовательный как я понимаю.

А так мне подход Clickhouse больше нравится, да.

В винде 11 можно повторить? Диск(где бекапы хранятся) просыпается раз в пару минут, всякие мониторы дёрганий показывают ничего.

Не знаю работает ли оно еще на Win11 (могли что-нибудь в API и сломать) но предыдущих версиях я такие вещи при помощи process monitor из пакета утилит SysInternals. Чтобы выяснить кто именно и что именно куда пишет.


Только с фильтрами внимательно надо, по умолчанию там в большинстве версия системные процессы из мониторинга исключены. А дергает скорее всего система, в 11й столько всякого мусора, какая нибудь служба или виджет наверно объем сводобного места регулярно проверяет.

Интересно, при mmap же должна быть оптимизация, когда полностью перезаписывают страницы, интересно как она происходит.

Т.е. если мы открыли существующий файл и пишем в него, то как делается что вот это не требует чтения с диска:
char *fdata = mmap(... fd ...);

for (int i = 0; i < PAGE_SIZE; i++)

fdata[i] = data[i * 2];


В то время как вот это требует:

char *fdata = mmap(... fd ...);

for (int i = 0; i < 100; i++)

fdata[i] = data[i * 2];

Это они ещё не доросли до того, чтобы узнають, откуда дети берутся что нельзя просто "записать 105 байт в файл" — нужно "прочитать 224 байта информации + 800 байт нулей и записать обратно 329 байт информации и 695 байт нулей" (а в случае ZFS — так вообще обновить всё дерево вверх до уберблока...)

У меня выше вопрос очень похожий.

Как избежать лишних чтений при mmap && записи достаточно больших блоков.

Т.е. открываем мы через mmap существующий файл и пишем туда "много" информации.
Как технически linux избегает "лишних" чтений из тех блоков диска, которые всё равно будут полностью перезаписаны?

Насколько мне известно, оно не пишет сразу на диск, оно пользуется стандартными фичами буферизации на уровне системы.

Это разумеется. Но вопрос немного про другое.
Вот смотрите как это работает при очевидной реализации:

В общем случае мы должны гарантировать консистентность состояния нашего файла (и даже не столь важно у нас MAP_PRIVATE \ MAP_SHARED_*** ).
При наивной реализации мы при записи первого же байта в страницу отображённую на диск мы обязаны:
1. Сказать, что теперь эта страница отображена в память, а значит:
1.а) прочитать всю страницу с диска в mmap-образ в памяти.
1.б) записать этот 1 байт данных в в mmap-образ в памяти.
2. Работаем дальше. Когда надо будет - скинем всю страницу на диск.

Так вот есть ли в Linux какая-то оптимизация, позволяющая убрать пункт 1.а) ?

Если предварительно не прочитать эту страницу с диска, то как её потом на диск записывать когда придёт время?

Оптимизаций разных под разные типовые use-case можно много разных придумать (*).
Спросил потому, что вы хорошо поставленным уверенным тоном про дисковую подсистему писали - я правильно понял что конкретный вопрос не по адресу.

*) Например при последовательном чтении с начала страницы запоминать кол-во записанных байт, в случае не выполнения оптимизации - читать с диска, больше не применять к файлу.

Я по линухам не специалист, я больше по *BSD.

Sign up to leave a comment.