Какие советы по использованию буфера и настройке в пользовательских службах TCP? - PullRequest
2 голосов
/ 22 января 2010

В последнее время я исследовал ряд сетевых библиотек и сред, таких как libevent, libev, Facebook Tornado и Concurrence (Python).

Одна вещь, которую я замечаю в их реализациях, - это использование буферов чтения / записи на уровне приложения (например, IOStream в Tornado) - даже HAProxy имеет такие буферы.

В дополнение к этим буферам прикладного уровня в каждом сокете есть буферы реализации TCP ядра ОС.

Я могу понять, что app / lib использует буфер чтения, я думаю: app / lib читает из буфера ядра в буфер приложения, и приложение что-то делает с данными (например, десериализует содержащееся в них сообщение).

Однако я запутался в необходимости / использовании буфера записи. Почему бы просто не записать в буфер отправки / записи ядра? Чтобы избежать издержек при системных вызовах (записи)? Я полагаю, что дело в том, чтобы быть готовым к большему количеству данных для загрузки в буфер записи ядра, когда ядро ​​уведомляет app / lib, что сокет «доступен для записи» ( например, EPOLLOUT). Но почему бы просто не покончить с буфером записи приложения и настроить буфер записи TCP ядра таким же большим?

Кроме того, рассмотрим сервис, для которого имеет смысл отключение алгоритма Nagle (например, игровой сервер). В такой конфигурации, я полагаю, я бы хотел наоборот: нет буфера записи ядра, но буфер записи приложения, да? Когда приложение готово отправить полное сообщение, оно записывает буфер приложения через send () и т. Д., И ядро ​​пропускает его.

Помоги мне прояснить мои мысли об этом понимании, если хочешь. Спасибо!

Ответы [ 2 ]

1 голос
/ 22 января 2010

Что касается haproxy, в нем нет различий между буферами чтения и записи, для обеих целей используется буфер, который сохраняет копию. Тем не менее, это действительно больно делать некоторые изменения. Например, иногда вам приходится переписывать HTTP-заголовок, и вам нужно правильно перемещать данные для перезаписи и сохранять некоторое состояние относительно значения предыдущего заголовка. В haproxy заголовок соединения может быть переписан, а его предыдущее и новое состояния сохранены, потому что они понадобятся позже, после перезаписи. При использовании буфера чтения и записи такая сложность отсутствует, поскольку вы всегда можете оглянуться назад в своем буфере чтения, если вам нужны какие-либо исходные данные.

Haproxy также может использовать соединение между сокетами в Linux. Это означает, что он не читает и не записывает данные, он просто сообщает ядру, что взять, куда и куда его перемещать. Затем ядро ​​автоматически перемещает указатели без копирования данных для передачи сегментов TCP с сетевой карты на другую (когда это возможно), но затем данные никогда не передаются в пространство пользователя, что позволяет избежать двойной копии.

Вы совершенно правы в том, что в общем случае вам не нужно копировать данные между буферами. Это трата пропускной способности памяти. Haproxy работает на скорости 10 Гбит / с с 20% ЦП со сплайсингом, но без сплайсинга (еще 2 копии) он близок к 100%. Но затем подумайте о сложности альтернатив и сделайте свой выбор.

Надеюсь, это поможет.

0 голосов
/ 02 декабря 2013

Когда вы используете асинхронную операцию ввода-вывода сокета, асинхронная операция чтения / записи немедленно возвращается, поскольку асинхронная операция не гарантирует обработку всех данных (т.е. помещает все необходимые данные в буфер сокета TCP или получает все необходимые данные из него) успешно с одним вызовом, частичные данные должны пережить несколько операций.Затем вам понадобится буферное пространство приложения для хранения данных в течение всего времени операций ввода-вывода.

...