РИТ++ 2017, Backend Conf
Зал Кейптаун, 6 июня, 15:00
Тезисы:
http://backendconf.ru/2017/abstracts/2710.html
В данном докладе я дам обзор системных интерфейсов, которые предоставляет Linux для эффективной обработки запросов. В частности, речь пойдет о мультиплексировании ввода-вывода, отправке файлов и многопоточной обработке входящих соединений. Расскажу о нюансах и недостатках в сравнении с аналогичными интерфейсами других unix-подобных операционных систем. Личный опыт показывает, что продуманность и качество реализации интерфейса для прикладных программ — это, к сожалению, довольно слабая сторона ядра Linux.
Linux API с точки зрения разработчика веб-сервера / Валентин Бартенев (NGINX, Inc.)
1. с точки зрения разработчика
высокопроизводительного веб сервера
Валентин Бартенев
2. Сверх краткое введение
• набор системных вызовов ядра и библиотек
• Ядро
• Взаимодействие с оборудование
• Управление памятью
• Управление процессами
• Работа с файловыми системами
• Сетевые протоколы
•
4. Цикл обработки соединений
connections[] массив соединений
handle_connction() обработчик соединения
loop {
for (i = 0; i < count; i = i + 1) {
handle_connection(connections[i]);
}
}
5. Цикл с задержкой
loop {
for (i = 0; i < count; i = i + 1) {
handle_connection(connections[i]);
}
sleep(200ms)
}
6. Эффективный цикл
loop {
count = wait_for_events(connections);
for (i = 0; i < count; i = i + 1) {
handle_connection(connections[i]);
}
}
8. Базовый интерфейс
Создание экземпляра int epoll_create();
Регистрация дескрипторов
int epoll_ctl(int epfd, int op, int fd,
struct epoll_event *event);
Ожидание событий
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
9. Параметры
int epoll_ctl(int epfd, int op, int fd,
struct epoll_event *event);
экземпляр
тип операции
отслеживаемый дескриптор
struct epoll_event {
uint32_t events; битовая маска типов событий
epoll_data_t data; пользовательские данные
};
10. События
struct epoll_event {
uint32_t events; битовая маска типов событий
epoll_data_t data; пользовательские данные
};
Основные флаги событий
чтение
запись
ошибка
закрытие соединения
11. Детектирование закрытия соединения
• В появился новый флаг
• На ядрах старше необходимо вычитывать все
данные и делать на один системный вызов больше
• тихо игнорируется старыми ядрами
• Невозможно отличить отсутствие события от
неработоспособности флага
• Приходится тестировать работоспособность
12. Странности
int epoll_ctl(int epfd, int op, int fd,
struct epoll_event *event);
Типы операций
добавление
изменение
удаление
Можно ли было обойтись двумя А одной
int epoll_ctl(epfd, fd, *event);
17. Асинхронная работа с файлами
и т д в
• Обертка от в пользовательском пространстве
• Плохо масштабируется высокие накладные расходы
и т д
• Требования к выравниванию
• Работает только в режиме
18. Собственный пул потоков в
• Пулы потоков ускоряем в и более раз
• Лишние накладные расходы если данные в памяти
• Предложенные решения так и не включены в ядро
• с флагом
•
20. Интерфейс
ssize_t sendfile(int out_fd, int in_fd,
off_t *offset, size_t count);
int sendfile(int fd, int s, off_t offset, size_t nbytes,
struct sf_hdtr *hdtr, off_t *sbytes,
int flags);
ssize_t sendfilev(int fildes, struct sendfilevec *vec,
int sfvcnt, size_t *xferred);
21. Особенности в свежих ядрах
ret = sendfile(out_fd, in_fd, offset, count);
до
• только в самом начале
• эквивалентно
после
• в произвольный момент
• Не отличить от при
• Требуется на один вызов больше
22. и
• В и работает иначе чем в большинстве
других подобных системах и позволяет
• Избежать борьбы за лок на сокете
• Равномерно распределять соединения
• Складывать пакеты от одного отправителя в один
и тот же процесс
• Теряет соединения при закрытии
• В при реализации
консультировались с разработчиками
и проблему решили