Неожиданно низкая производительность io_uring при записи нескольких сокетов TCP.Linux

Ответить
Anonymous
 Неожиданно низкая производительность io_uring при записи нескольких сокетов TCP.

Сообщение Anonymous »

Мне нужны рекомендации по использованию io_uring для интенсивной записи TCP.
У меня есть приложение на Rust, которое ожидает события в узком цикле. Всякий раз, когда происходит событие, одна и та же полезная нагрузка должна быть записана в несколько сокетов TCP. В настоящее время я использую стандартные неблокирующие сокеты и просто перебираю все сокеты, вызывая запись для каждого из них.
Этот подход работает правильно, но производительность снижается по мере увеличения количества сокетов; общая задержка растет примерно линейно с увеличением количества сокетов.
Я предполагал, что io_uring может улучшить этот сценарий. Идея заключалась в том, чтобы поставить все операции записи (в идеале без копирования данных) в очередь отправки, а затем отправить их с помощью одного системного вызова.
Я реализовал прототип, основанный на этой идее, но результаты были неожиданными: он значительно медленнее, чем неблокирующий цикл записи, а производительность еще больше снижается по мере увеличения количества запросов на запись в очереди.
Ниже приведена соответствующая часть цикла с использованием io_uring:

Код: Выделить всё

    let mut ring = IoUring::new(1024)?;

// ...setup accepting tcp sockets...

let mut next_message_time = current_nano_time() + ONE_SECOND;
loop {
if next_message_time < current_nano_time() {
let message = format!("{}\n", next_message_time);
next_message_time = current_nano_time() + ONE_SECOND;

// start pushing send request to the queue
let time_start = current_nano_time();

let mut count = 0;
for connection in connections.iter_mut() {
if connection.state == State::Active {
push_send(&mut ring, connection, &message);
count += 1;
}
}
if count == 0 {
continue;
}

let time_pushed = current_nano_time();

// submit pushed requests
ring.submit().expect("submit returned error");

let time_submitted = current_nano_time();

println!(
"latencies for {} entries: push={}us, submit={}us",
count,
(time_pushed - time_start) / 1000,
(time_submitted - time_pushed) / 1000
);
}

let cqe = ring.completion().next();

if cqe.is_none() {
yield_now();
continue;
}

// ...handle cqe...

}
полный исходный код находится здесь: https://github.com/eXistence/iouring_te ... rc/main.rs
Вывод журнала выглядит следующим образом:

Код: Выделить всё

new client connected
latencies for 1 entries: push=0us, submit=57us
latencies for 1 entries: push=0us, submit=33us
new client connected
latencies for 2 entries: push=0us, submit=32us
latencies for 2 entries: push=0us, submit=47us
new client connected
latencies for 3 entries: push=0us, submit=49us
latencies for 3 entries: push=0us, submit=72us
new client connected
latencies for 4 entries: push=0us, submit=66us
latencies for 4 entries: push=0us, submit=59us
new client connected
latencies for 5 entries: push=0us, submit=72us
latencies for 5 entries: push=0us, submit=109us
Постановка запросов на запись в очередь отправки происходит очень быстро, как и ожидалось. Однако вызов submit() выполняется значительно медленнее и становится все дороже по мере увеличения количества записей в очереди.
Ожидается ли такое поведение? Я неправильно использую io_uring или мое понимание его характеристик производительности в этом случае неверно?

Подробнее здесь: https://stackoverflow.com/questions/798 ... ket-writes
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»