Hacker News Digest

Тег: #io-uring

Постов: 8

How to stop Linux threads cleanly (mazzo.li)

Остановка потоков Linux требует аккуратного подхода, особенно при работе с низкоуровневыми потоками, созданными через pthread_create или std::thread. В отличие от запуска, корректное завершение потоков позволяет выполнить очистку ресурсов — освобождение памяти, блокировок, сброс логов. Идеального универсального решения не существует, но есть несколько подходов.

Простой метод — организация квази-активного ожидания в каждом потоке с проверкой флага остановки. Когда нужно завершить поток, флаг устанавливается в true, после чего вызывается pthread_join. Цикл не должен быть полностью неблокирующим, но должен завершаться за разумное время. Для потоков, блокирующихся на системных вызовах, используются сигналы для прерывания выполнения. Важно, что даже с этим подходом нужно учитывать обработку сигналов для корректной работы с буферизированным выводом.

by signa11 • 15 октября 2025 г. в 07:28 • 223 points

ОригиналHN

#linux#pthreads#threads#multithreading#posix#signals#io-uring#poll#select#epoll

Комментарии (77)

  • Проблема заключается в том, что POSIX не предоставляет безопасного механизма для остановки потока, и это приводит к тому, что разработчики вынуждены полагаться на pthread_cancel, который небезопасен и может привести к утечкам ресурсов или повреждению состояния.
  • Попытки использовать SIGUSR1 и signalfd для обработки сигналов в пространстве пользователя не решают проблему, потому что большинство библиотек не ожидают, что их вызовы будут прерваны, и это может привести к повреждению состояния.
  • Вместо этого, вместо попыток остановить поток, который может быть в любой точке, лучше структурировать код так, чтобы он мог реагировать на сигнал остановки, или использовать модель, где потоки не блокируются на системных вызовах, а вместо этого используют асинхронные вызовы и ожидают на poll/select/epoll/io_uring.
  • Некоторые комментаторы отмечают, что в Linux существует io_uring, который позволяет прервать системный вызов, и что это может быть использовано для реализации остановки потока, но это не решает проблему, что не все вызовы могут быть прерваны таким образом.
  • В конечном счёте, вместо попыток убить поток, который может быть в любой точке, лучше писать код так, чтобы он был отзывчив к сигналу остановки, и использовать модели, где потоки не блокируются на системных вызовах, а вместо этого используют асинхронные вызовы и ожидают на poll/select/epoll/io_uring.

Benchmarking Postgres 17 vs. 18 (planetscale.com)

PostgreSQL 18 представил новую опцию конфигурации io_method, дающую пользователям больше контроля над обработкой дискового ввода-вывода. В отличие от версии 17, где использовались только синхронные запросы, в 18 доступны три режима: sync (старое поведение), worker (новый стандарт по умолчанию с фоновыми процессами) и io_uring (асинхронный интерфейс Linux для чтения с диска).

В ходе тестирования с использованием sysbench на базе данных размером ~300 GB на различных конфигурациях EC2 были получены неожиданные результаты. При одиночном подключении и сетевых хранилищах (gp3, io2) версии 18 в режимах sync и worker показали производительность выше, чем 17 и 18 с io_uring. Полные результаты для высококонкурентных сценариев и быстрых NVMe-накопителей еще ожидаются.

by bddicken • 14 октября 2025 г. в 15:35 • 165 points

ОригиналHN

#postgresql#io-uring#aws#ec2#sysbench#cloud-storage#performance-benchmarking#nvme#timescaledb

Комментарии (57)

  • Обсуждение подтвердило, что при использовании локального NVMe диска разница между 17 и 18 версиями PostgreSQL незначительна, но при этом сетевое хранилище всё ещё сильно уступает по производительности.
  • Участники отметили, что важно понимать, что при использовании облачного хранилища вы платите не за IOPS, а за то, чтобы кто-то другой имел дело с резервным копированием, репликацией и обслуживанием оборудования.
  • Также было отмечено, что в настоящее время PostgreSQL не поддерживает прямой ввод/вывод, но над этим ведётся работа.
  • Были высказаны опасения, что использование VPS с локальным диском может повлечь за собой вопросы надёжности, так как такие диски, как правило, не имеют избыточности.
  • В контексте обсуждения также поднялся вопрос о том, что влияние на производительность может оказать использование или отсутствие расширения, такого как TimescaleDB.

Tuning async IO in PostgreSQL 18 (vondra.me)

В PostgreSQL 18 появилась поддержка асинхронного ввода-вывода (AIO), что позволяет эффективнее использовать хранилище. Основные параметры для настройки — io_method и io_workers. По умолчанию io_method = worker использует пул процессов для выполнения операций ввода-вывода, что обеспечивает кроссплатформенность и стабильность. Альтернатива io_uring эффективнее, но работает только на Linux и может быть недоступна в некоторых контейнерах из-за проблем безопасности.

Значение io_workers = 3 слишком консервативно для серверов с большим количеством ядер. Рекомендуется увеличивать его пропорционально числу CPU, особенно для интенсивных рабочих нагрузок. Например, на системе с 64 ядрами можно установить 16–32 воркеров. Важно тестировать настройки под конкретную нагрузку, так как универсального решения нет.

by fanf2 • 29 сентября 2025 г. в 11:42 • 82 points

ОригиналHN

#postgresql#async-io#io-uring#zfs#azure

Комментарии (12)

  • Ожидание тестирования новой функции async I/O на базах данных в Azure с использованием ZFS для повышения производительности последовательного сканирования.
  • Обсуждение выбора метода worker по умолчанию вместо io_uring из-за его универсальности и проблем безопасности с io_uring в некоторых средах.
  • Вопрос о причинах более низкой производительности io_uring в сравнении с worker в некоторых бенчмарках и является ли это ошибкой или ограничением технологии.
  • Дебаты о целесообразности использования CoW-файловых систем (например, ZFS, btrfs) для Postgres и сжатия на уровне ФС против встроенного сжатия СУБД.
  • Уточнение, что новая функция async I/O сейчас применяется только для последовательных и bitmap-сканирований, но не для индексных.

io_uring is faster than mmap (bitflux.ai) 🔥 Горячее

TL;DR
Чтение напрямую с диска быстрее, чем из кеша в памяти: пропускная способность SSD растёт, а латентность памяти стоит на месте. Нужны новые инструменты.

Эксперимент

  • Задача: подсчитать количество десяток в 50 ГБ псевдослучайных int.
  • Железо: AMD EPYC 7551P, 96 ГБ DDR4-2133, два Samsung PM983a PCIe 3.0 SSD (3,1 ГБ/с каждый) в RAID-0.
  • Ограничения:
    • Память: 13 ГБ/с на поток (3 канала × 2133 МТ/с × 8 Б / 4 NUMA-домена).
    • Диски: 6,2 ГБ/с суммарно.

Код

int* data = mmap(..., size, PROT_READ, MAP_SHARED, fd, 0);
for (...) if (data[i] == 10) count++;

Результаты

  • Первый запуск (с диска): 0,61 ГБ/с — ограничение диск.
  • Второй запуск (из кеша): 3,71 ГБ/с — всё ещё ниже пропускной способности памяти.
  • Бутылочное горлышко: не векторизованный цикл, ~3–4,5 млрд инструкций/с.

by ghuntley • 04 сентября 2025 г. в 22:01 • 265 points

ОригиналHN

#io-uring#mmap#ssd#raid-0#pci-e#amd#nvme#memory#disk#performance

Комментарии (120)

  • mmap тормозит из-за последовательных page-fault и 4 Кб страниц; io_uring на 6 потоках читает буферы заранее и просто отдаёт готовые.
  • Пропущены MAP_POPULATE / MADV_SEQUENTIAL / hugepages — без них сравнение «mmap vs io_uring» нечестое.
  • Автор признаёт кликбейтное название «Memory is slow, Disk is fast»; суть: «RAID-0 NVMe даёт больше пропускной канала, чем DDR5-каналов на тестовой машине».
  • Под капотом io_uring + O_DIRECT сам управляет кэшем, mmap же полагается на page-cache ядра.
  • PCIe-5 ×128 линий серверных CPU уже >1 ТБ/с, что выше DDR5-6400 12-канального узла (~600 ГБ/с), но данные всё равно идут в RAM перед CPU.

Hitting Peak File IO Performance with Zig (steelcake.com)

Как выжать максимум из файлового IO в Linux на Zig + io_uring

Тест

  • Железо: Ubuntu 24.04, 6.14, NVMe, 32 ядер, 756 ГБ ОЗУ (не влияет, direct_io).
  • Параметры: 512 КБ блок, очередь 64, 16 ГБ файл, один поток.

Результаты

fio Zig
write 4.08 ГБ/с 3.80 ГБ/с
read 7.33 ГБ/с 7.00 ГБ/с

Zig на 5–7 % медленнее fio, но близко к пределу SSD.

Ключевые фишки реализации

  1. Полл-режим (IOPOLL) + nvme.poll_queues=16 → прерывания не нужны.
  2. Два экземпляра io_uring: один с IOPOLL (только read/write), второй – для остального.
  3. Зарегистрированные буферы: память выделяется заранее, пользователь получает/возвращает готовые блоки.
  4. Выравнивание:
    • чтение – внутренняя «перехватка» невыравненных запросов;
    • запись – пользователь сам выравнивает, иначе лишние read-modify-write.
  5. Без слияния IO внутри библиотеки – проще и гибче на уровне приложения.

Код: steelcake/csio

by ozgrakkurt • 04 сентября 2025 г. в 19:15 • 123 points

ОригиналHN

#zig#io-uring#nvme#file-io#linux#ubuntu#performance-optimization#direct-io

Комментарии (11)

  • Пользователи указывают, что 7 ГБ/с при 512 КБ блоках — это всего ~14 000 IOPS (~70 мкс/IO), и требуется лишь 1 предзагрузка для полной полосы.
  • Напоминают, что Zig 0.15.1 всё ещё меняет IO-API, поэтому версию нужно явно указывать в посте.
  • Рекомендуют проверить/увеличить логический блок NVMe до 4 КБ через nvme-format вместо хардкода ALIGN=512.
  • Разница 4,08 ГБ/с (fio) и 3,80 ГБ/с (Zig) объясняется путаницей GiB ↔ GB.
  • Для io_uring важно использовать registered fds — дают заметный прирост.
  • Интересуются, как будет работать тот же код на FreeBSD AIO.
  • Предлагают вместо «овераллокации» брать выровненную память через page-аллокатор.

Io_uring, kTLS and Rust for zero syscall HTTPS server (blog.habets.se) 🔥 Горячее

  • История: от pre-fork до epoll — каждый шаг уменьшал сисколлы, но они всё ещё оставались узким местом.
  • io_uring — кольцевые очереди в памяти: сервер пишет команды, ядро асинхронно их выполняет и кладёт результат обратно. При высокой нагрузке strace не покажет ни одного сисколла.
  • 1 поток = 1 ядро без разделяемых структур; память берётся только из локального NUMA-узла.
  • Память: заранее выделяем фиксированный буфер на соединение — без brk/mmap, без фрагментации.
  • kTLS — после рукопожатия шифрование переходит в ядро. Плюсы:
    1. Работает sendfile, данные не копируются в userspace.
    2. Возможно аппаратное ускорение NIC.

by guntars • 22 августа 2025 г. в 03:51 • 442 points

ОригиналHN

#io-uring#ktls#rust#https#syscalls#epoll#numa#dpdk

Комментарии (137)

  • io_uring даёт «zero-syscall» при высокой нагрузке, но требует ручного управления памятью: безопасность не обеспечивается ни borrow checker, ни runtime.
  • На большинстве облачных платформ io_uring выключен по умолчанию, поэтому остаётся нишевым.
  • Автор статьи сначала чистит код, а потом будет мерить производительность — что вызвало одобрение читателей.
  • Обсуждаются альтернативы: epoll, kTLS, DPDK, eBPF, а также споры «один поток на ядро» vs oversubscription.
  • Некоторые считают, что сложность io_uring и async Rust — цена за неспособность ОС ускорить syscalls без нарушения обратной совместимости.

Without the futex, it's futile (h4x0r.org) 🔥 Горячее

Без futex всё тленно

Книга The Art of Multiprocessor Programming (2-е изд., 2021) считается канонической, но она обходит стороной futex — ключевой примитив современной многопоточности. Это упущение делает пособие бесполезным для практиков.

Futex ≠ mutex
Название происходит от «fast userspace mutex», но futex — это не мьютекс, а основа для всех высокоэффективных примитивов синхронизации. До него всё строилось на громоздких System V IPC, которые не масштабировались: при 1000 потоков futex в 2002-м оказался в 20–120 раз быстрее sysv-блокировок. Windows и macOS добавили аналоги только в 2012 и 2016 гг.

Суть futex
Он разделяет блокировку и ожидание/пробуждение:

  • В user-space проверяем состояние; если свободно — захватываем без системного вызова.
  • При конфликте вызываем futex_wait(addr, expected), засыпаем в ядре на конкретном адресе.
  • Пробуждение — futex_wake(addr, n), где n обычно 1 или «все».

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

Такой подход убирает лишние системные вызовы и позволяет строить быстрые мьютексы, rw-lock’и, семафоры и пр. без поллинга и экспоненциальных бэкоффов.

Итог
Любая современная библиотека (pthreads, C++ std::mutex, Rust std::sync) опирается на futex. Учебник, игнорирующий этот примитив, не готовит к реальной разработке.

by eatonphil • 19 августа 2025 г. в 13:53 • 284 points

ОригиналHN

#futex#multithreading#system-v#linux#pthreads#rust#c++#io-uring#numa#synchronization

Комментарии (138)

  • Futex — это быстрый примитив синхронизации, который экономит системные вызовы при отсутствии конфликтов и не требует выделения ядром объектов.
  • В отличие от Benaphore и старых SysV-механизмов, futex не требует предварительной инициализации в ядре и исчезает, когда нет ожидающих.
  • Обсуждение подчёркивает, что современные учебники по многопроцессорному программированию обязаны упоминать futex, но «The Art of Multiprocessor Programming» этому не уделяет внимания.
  • Улучшения futex2 (Linux ≥5.16) добавили NUMA-поддержку и аналог Windows WaitForMultipleObjects, а io_uring теперь умеет работать с futex.
  • Для надёжности при падении потока существуют robust-locks и списки futex, которые ядро автоматически разблокирует.

Faster Index I/O with NVMe SSDs (marginalia.nu)

Поисковый индекс Marginalia переписан, чтобы лучше использовать NVMe-накопители.
Основные изменения:

  • Объём: после ослабления фильтров и добавления рекламного детектора база выросла с 350 до 800 млн документов; ожидается дальнейший рост при добавлении новых языков.
  • Структура: обратный индекс остался «картой терм → список (документ, позиции)», но B-дерево теперь читается в режиме O_DIRECT, минуя кэш страниц.
  • Чтение:
    • Буферизованные чтения неэффективны при случайном доступе к файлам, превышающим RAM.
    • Прямые чтения требуют выравнивания по 512/4096 Б, но дают стабильную задержку и не копируют данные лишний раз.
    • В Linux появляется RWF_DONTCACHE, но поддержка пока неполная.

Первая оптимизация — переписать B-дерево под O_DIRECT; дальнейшие шаги ещё описываются.

by ingve • 17 августа 2025 г. в 13:17 • 156 points

ОригиналHN

#nvme#ssd#b-tree#linux#io-uring#spdk#lba#search-index#io-performance#direct-i-o

Комментарии (24)

  • 128–256 КБ считаются «классическим» оптимальным размером блока, но в 2024 г. всё чаще замеряют индивидуально: всё зависит от архитектуры I/O.
  • Для NVMe при высокой параллельности 4 КБ работает не хуже, если использовать AsyncIO/IO_uring или SPDK и выдавать много одновременных запросов.
  • Меньшие блоки экономят чтение, но не избавляют от внутреннего read-amplification SSD; нужно знать минимальный физический размер чтения контроллера.
  • Формат LBA (512 B vs 4 КБ+) и опции sysfs (optimal_io_size) влияют на производительность и стоит их проверять.
  • В задачах индексного поиска параллельность ограничена, поэтому крупные блоки остаются практичным выбором при отсутствии точных данных о «железе».