Как работает epoll/kqueue и почему они быстрее select/poll

8 минут чтения
Средний рейтинг статьи — 4.9

Когда сервер обрабатывает множество соединений одновременно, важно эффективно следить за готовностью сокетов к чтению и записи. В Linux и BSD для этого есть несколько механизмов: select, poll, epoll (Linux) и kqueue (BSD, macOS). Каждый из них решает одну задачу — уведомлять программу о событиях на файловых дескрипторах — но работает по-разному.

select и poll

select() и poll() — старые API, которые существуют десятки лет. Они работают так:

  • Перед каждым вызовом функции программа формирует массив дескрипторов сокетов, за которыми хочет следить.
  • Функция возвращает, какие дескрипторы готовы к чтению/записи.

Проблемы select/poll

  1. Линейная проверка
    • select и poll просматривают весь список дескрипторов каждый раз
    • Время выполнения растёт пропорционально количеству сокетов
  2. Ограничение на количество дескрипторов
    • select имеет лимит FD_SETSIZE (обычно 1024)
    • Poll ограничений формально нет, но тоже растёт нагрузка при большом числе соединений
  3. Каждый вызов копирует массивы
    • Программе нужно передавать массив всех FD в ядро и обратно
    • Это создаёт лишние системные вызовы и копирование данных

Эти ограничения делают select/poll непригодными для серверов с тысячами одновременных соединений.

epoll (Linux)

epoll был создан для Linux как решение проблем select/poll.

Особенности:

  • Работа с «событийным списком»
    • Программа регистрирует интересующие события один раз через epoll_ctl
    • После этого ядро само отслеживает, какие дескрипторы готовы
  • События возвращаются как готовые
    • Вызов epoll_wait возвращает только активные дескрипторы
  • Производительность O(1)
    • Независимо от числа FD, время обработки событий не растёт линейно

Режимы работы epoll

  1. Level-triggered (LT)
    • Повторно уведомляет, пока дескриптор готов
    • Поведение похоже на poll, но эффективнее
  2. Edge-triggered (ET)
    • Уведомление один раз при изменении состояния
    • Требует неблокирующих сокетов и внимательной обработки
    • Позволяет минимизировать лишние вызовы

Преимущества epoll

  • Отлично подходит для тысяч соединений
  • Минимальные копирования данных между ядром и пользователем
  • Гибкость: LT и ET режимы

kqueue (BSD, macOS)

kqueue — аналог epoll в системах BSD и macOS.

Особенности:

  • Event queue
    • Программа регистрирует события, ядро следит за ними
  • Поддержка множества типов событий
    • Не только сокеты, но и файлы, сигналы, таймеры
  • Производительность O(1)
    • Очень эффективно при большом числе дескрипторов

Отличия от epoll

  • epoll специализируется на файловых дескрипторах (сокеты, файлы)
  • kqueue универсальнее, покрывает больше типов событий
  • API отличается, но принципы похожи: регистрация событий, ожидание активных

Практическая разница

Параметрselect/pollepoll/kqueue
ПроизводительностьO(N)O(1)
Копирование FDданет (только при регистрации)
Масштабируемостьдо ~1000 FDтысячи и десятки тысяч FD
Поддержка событийтолько готовность к read/writeread/write, таймеры, сигналы (kqueue)

Почему это важно

Современные серверы (Nginx, HAProxy, Node.js, Redis) обрабатывают десятки тысяч соединений. Использование select/poll на такой нагрузке приведёт к:

  • высокому CPU на перебор дескрипторов
  • задержкам при пиковых нагрузках

Использование epoll или kqueue позволяет:

  • обрабатывать множество соединений эффективно
  • минимизировать количество системных вызовов
  • уменьшить latency и повысить пропускную способность

Пример на Linux (epoll)

int epfd = epoll_create1(0);
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
while(1) {
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for(int i=0; i<n; i++) {
        if(events[i].events & EPOLLIN) handle_read(events[i].data.fd);
    }
}

Принцип: один раз зарегистрировали интересующие события, и ядро само сообщает, когда что-то готово.

Итог

  • select/poll — простые, старые, подходят для небольшого числа соединений
  • epoll/kqueue — современные, эффективные, масштабируемые, используются в высоконагруженных серверах

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

8 минут чтения
Средний рейтинг статьи — 4.9

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний