1. Про сокеты и миллионы
пакетов в секунду с одного
CPU ядра
Александр Крижановский
2. О сокетах (серверных)
●
●
●
●
●
●
путь пакета в Linux с адаптера в TCP-сокет;
установление новых соединений,
мультиплексирование и чтение из сокетов;
как ускорить прикладной сервер (оптимизация
accept(2), MSI-X и RPS/RFS, GRO);
можно быстрее: Oracle Reliable Datagram Sockets
еще быстрее: переход к полностью синхронным
сокетам
В основном интересовала скорость установления
соединений
3. Путь пакета (recv)
1.RSS (Receive Side
Scaling)
2.MSI-X очереди
3.DCA (Direct Cache
Access)
=> User/kernel:
копирования
=> асинхронность
получения и чтения
8. Пример переключения контекста:
«Наш клиент?»
1.epoll_wait(2)
2.accept(2)
3.getpeername(2)
4.=> не наш клиент: close(2)
7 контекст свитчей
Хорошо: user/kernel context switch не инвалидирует
кэши
9. Пример переключения контекста:
«Наш клиент?»
1.epoll_wait(2)
2.accept(2)
3.getpeername(2)
4.=> не наш клиент: close(2)
7 контекст свитчей
Хорошо: user/kernel context switch не инвалидирует
кэши
10. Что если приходит сразу много
клиентов?
listen(listen_sd, 5);
epoll_ctl(wd, EPOLL_CTL_ADD, listen_sd, &ev);
while (1) {
n = epoll_wait(wd, ev, 64, 1);
for (int i = 0; i < n; ++i) {
if (ev[i].data.fd == listen_sd)
new_sd = accept(listen_sd, NULL, NULL);
}
}
11. Оптимизация accept(2)
BRECHT T., PARIAG D., GAMMO L. «accept()able strategies for improving web
server performance.»
listen(listen_sd, 1000);
fcntl(sd, F_SETFL, flags | O_NONBLOCK);
epoll_ctl(wd, EPOLL_CTL_ADD, listen_sd, &ev)
while (1) {
n = epoll_wait(wd, ev, 64, 1);
for (int i = 0; i < n; ++i) {
if (ev[i].data.fd == listen_sd)
do {
new_sd = accept(listen_sd, NULL, NULL);
} while (new_sd >= 0);
}
}
12. MSI-X, RPS, RFS
1. RSS (Receive Packet
Steering)
2. RFS (Receive Flow
Steering)
3. MSI-X не всегда хорошо
балансирует трафик =>
RPS
4. Но MSI-X - «железный»
13. Сокетные каллбеки
●
●
●
●
●
●
sk_data_ready — вызывается при получении
данных на сокете
sk_state_change — изменение состояния сокета
sk_write_space — у сокета появилось место в
буфере записи
sk_error_report — ошибка на сокете
sk_backlog_rcv — чтение из очереди отложенных
сегментов (!tcp_low_latency)
sk_destruct — вызывается на удалении сокета
14. Oracle Reliable Datagram Sockets
(RDS)
Ядерная реализация сокетов (linux/net/rds):
●
нет копирований и переключений контекстов
●
основная работа происходит на калбеках сокетов
Функции, необходимые accept(), могут спать => wait
queue
16. Synchronous Sockets
●
●
●
●
Всё делается только в softirq
Хорошо подходят для большого числа
короткоживущих соединений
Нужен патч ядра
Могут быть вынесены в некрасивую библиотеку
ядра:
–
–
upcalls & downcalls
Но код с ней в ~2 раза короче (200 vs 364)