Zero-copy в Linux. Как работает sendfile, mmap и почему это быстрее
Когда приложение передаёт данные — например, отдаёт файл по HTTP — данные обычно проходят несколько этапов копирования:
- диск → kernel space
- kernel → user space
- user space → kernel
- kernel → сеть
Каждое копирование — это лишняя нагрузка на CPU и память. В высоконагруженных системах это становится узким местом.
Zero-copy — это подход, который позволяет минимизировать или полностью убрать лишние копирования.
Почему копирование — это дорого
При каждом copy происходит:
- загрузка данных в CPU cache
- перемещение между буферами
- переключение контекста (syscalls)
Это приводит к:
- увеличению CPU usage
- росту latency
- снижению throughput
Особенно критично при работе с большими файлами и большим количеством соединений.
Что такое zero-copy
Zero-copy — это техника, при которой данные не копируются между user space и kernel space без необходимости.
Идея:
- данные остаются в kernel
- приложение только управляет передачей
Результат:
- меньше копий
- меньше syscalls
- выше производительность
sendfile
sendfile() — один из самых известных zero-copy механизмов.
Он позволяет передать данные напрямую:
file → socket
без промежуточного копирования в user space.
Как работает
Обычный путь:
read() → user buffer → write()
С sendfile:
kernel buffer → socket
Пример:
sendfile(out_fd, in_fd, NULL, size);Где используется
- Nginx
- Apache
- файловые серверы
Плюсы
- меньше CPU
- меньше копирования
- выше throughput
mmap
mmap() отображает файл в память процесса.
Вместо чтения файла через read, вы работаете с ним как с обычным массивом.
Как работает
- файл отображается в виртуальную память
- данные подгружаются по мере доступа (page fault)
Пример:
void* data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);Особенности
- нет явного копирования
- ленивое чтение
- работа через page cache
Когда это быстрее
- случайный доступ к файлам
- большие файлы
Минусы
- сложнее управление памятью
- возможны page faults (латентность)
sendfile vs mmap
| Параметр | sendfile | mmap |
|---|---|---|
| Основной кейс | file → socket | работа с файлами |
| Копирование | минимальное | отсутствует явно |
| Контроль | простой API | больше контроля |
| Использование | веб-серверы | базы данных, кеши |
Дополнительные механизмы
splice
Позволяет передавать данные между файловыми дескрипторами через pipe без копирования.
fd → pipe → fd
sendfile + page cache
Важно понимать:
- данные всё равно проходят через page cache
- но не копируются в user space
Почему это быстрее
- Меньше копирований
- Меньше syscalls
- Меньше нагрузки на CPU cache
- Эффективное использование page cache
В реальности это даёт:
-
- throughput
-
- latency
-
- CPU usage
Когда zero-copy особенно важен
- CDN
- веб-серверы (Nginx)
- стриминг
- прокси (HAProxy)
Ограничения
- не всегда применим (например, когда нужно модифицировать данные)
- зависит от ОС и файловой системы
- требует понимания работы kernel
Практические советы
- Используйте sendfile для отдачи файлов
- mmap — для сложной работы с файлами
- избегайте лишних read/write
- профилируйте CPU и syscalls
Итог
Zero-copy — это мощная оптимизация для систем с большим объёмом I/O.
- sendfile ускоряет передачу файлов в сеть
- mmap упрощает работу с данными в памяти
Если упрощать:
- меньше копий → меньше нагрузки → выше скорость
Понимание этих механизмов позволяет строить более эффективные и масштабируемые системы.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний