LINUX.ORG.RU

Одновременная запись в несколько сокетов


2

3

Суть задачи: RedHat Linux MRG Realtime Есть структура, содержащая (условно) список сокетов, в которые надо писать одинаковые данные (мультиплексирование). Сокетов достаточно много - сотни и единицы тысяч.

Операции записи должны быть асинхронными, при этом потокобезопасными. Высокие требования к латентности (распространение рыночных данных).

На какие низкоуровневые средства предложите посмотреть и какие высокоуровневые реализации посоветуете посмотреть?

Спасибо заранее.

nginx уже изобрели до вас
да и мультикаст существовал за долго до nginx

anonymous
()
Ответ на: комментарий от anonymous

nginx справляется с потоком плотностью миллионы сообщений в секунду?

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

westtrd
() автор топика

ØMQ \zeromq\:
 Ø  The socket library that acts as a concurrency framework.
 Ø  Faster than TCP, for clustered products and supercomputing.
 Ø  Carries messages across inproc, IPC, TCP, and multicast.
 Ø  Connect N-to-N via fanout, pubsub, pipeline, request-reply.
 Ø  Asynch I/O for scalable multicore message-passing apps.
 Ø  Large and active open source community.
 Ø  30+ languages including C, C++, Java, .NET, Python.

ukr_unix_user ★★★★
()
Ответ на: комментарий от westtrd

Мультикаст не работает, сокеты из разных подсетей

При грамотной настройке маршрутизаторов, мультикаст отлично работает в разных подсетях (конечно в пределах одной сети организации).

На какие низкоуровневые средства предложите посмотреть

А разве есть выбор? Открываешь сокеты в неблокирующем режиме, ожидаешь входящие пакеты через epoll, а исходящие данные пишешь в каждый сокет в цикле.

m0rph ★★★★★
()
Ответ на: комментарий от ukr_unix_user

Не пойдет, к сожалению, существует собственный бинарный протокол, и требования несколько другие, пожестче

westtrd
() автор топика
Ответ на: комментарий от m0rph

Речь идет про интернет клиенты, поэтому совет про мультикаст, к сожалению, не уместен

Интересует только запись, и ищу средства, которые позволили бы избежать 500 - 1000 системных вызовов на каждый пакет, тут еще и проблема планировки есть - не дело, когда первый клиент всегда будет первым, а последний всегда последним в очереди )

westtrd
() автор топика
Ответ на: комментарий от urykhy

Не подскажете ли как epoll грамотно пользовать именно для записи в группу сокетов

Первый вариант интересен, посмотрю )

westtrd
() автор топика
Ответ на: комментарий от westtrd

epoll позволит отслеживать события от всех твоих сокетов одновременно, но это события поступления данных или закрытия соединений (в случае с tcp). Для записи данных в сокет используй обычный write. Обходить список сокетов в цикле и записывать в них данные все равно придется. Ну а если уж хочется менять очередность сокетов, можешь например циклически сдвигать их в том же самом списке на одну позицию на каждой итерации отправки данных.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

Пока смотрю вот на это http://pubs.opengroup.org/onlinepubs/009604599/functions/lio_listio.html , хотя бы оверхед на массированные системные вызовы убрать, понятно, что внутри оно все равно проходить по списку будет

По планировщику понятно, один из сценариев :)

westtrd
() автор топика

1) сотни и единицы тысяч tcp сокетов ?
tcp это tcp - с какой скоростью будут с него выбирать данные - с той и будет выдавать
как тут возможно обеспечить синхронизацию ?
заполниться буфер отправки у одного сокета - так и нужно будет хранить весь поток - пока этот клиент не заберет данные или не отвалиться

посуществу именно для этого - и идут запросы в ядро - write - не только на посылку данных - но и на проверку - типа EAGAIN или нет еще

2) есть тема с zero копированием данных от сокета к сокету (через dup + tee + splice)
но эта тема скорее на пропускную способность - а не на количество сокетов

3) помоему - единственное решение это ядерный модуль ... или http://www.yl.is.s.u-tokyo.ac.jp/~tosh/kml/

Kernel Mode Linux : Execute user processes in kernel mode

обычьный одно потоковый сервер на epoll-е и отсутвие оверхеда при вызовов ядра - имхо и есть что нужно

ae1234 ★★
()
Ответ на: комментарий от ae1234

По превышению high watermark у сокета, он будет гаситься Задача - минимизировать по максимуму оверхеды для нормального соединения, основное - минимизировать латентность на сервере в части передачи данных

westtrd
() автор топика
Ответ на: комментарий от westtrd

До сих пор ничего круче банального write еще не придумали. Единственное что можно сделать для «одновременности» и типа «ускорения» - пул процессов + пул тредов в каждом, и все это синкать через один инстанс(в смысле какие данные отправить), но тут все равно накладных расходом на синхронизацию в поряде получается. Так что круче write в цикле в принципе ничего нету для общего случая. В некоторых частных случаях есть решения получше.

Jetty ★★★★★
()
Ответ на: комментарий от westtrd

шутка с lio_listio в том что вызывать ее нужно будет с LIO_NOWAIT (насколько я понимаю)

ну и потом - после вызова - для каждого сокета вызывать aio_return - чтоб узнать как завершилась операция записи (и почему нельзя также ее засунуть в lio_listio ? :) )

ae1234 ★★
()

Не сношай нам моск, делай per-socket потоки и очереди.

Всё равно большую часть времени все они будут находиться в состоянии sleep, так что ничего с твоим шедулером не случится.

Это проще, а значит и надежней - в этой схеме практически негде совершить ошибку.

И ещё это решение очень хорошо (если быть точным, линейно) масштабируется добавлением процессоров, памяти и серверов.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

В том то все и дело, что сокеты практически постоянно будут в работе, поток данных разной интенсивности, но он практически никогда не прерывается.

Насчет тредпулов я бы еще подумал, так оно и будет, но 1000 активных потоков заводить только в этом месте мне представляется излишеством

westtrd
() автор топика

если нужно мультиплексировать запись во множество сокетов, то придется лезть в ядро. Например, написать свой модуль, который будет реализовывать новый системный вызов massive_write(int* sockets, size_t sockets_num, char* buf, size_t len, int flag);

:)

и он уже внутри ядра будет дергать ядерный вариант write для каждого сокета, без переключения контекста

Harald ★★★★★
()
Ответ на: комментарий от Harald

Этот вариант понятен, он остается, но хотелось бы обойтись без общения с внутренностями ядра :)

westtrd
() автор топика
Ответ на: комментарий от westtrd

Насчет тредпулов я бы еще подумал, так оно и будет, но 1000 активных потоков заводить только в этом месте мне представляется излишеством

Велл. Давай лучше так переформулирую вопрос: у тебя используется протокол с гарантированной доставкой, или какой-то стримовый протокол, и тебе пофиг дойдет сообщение или нет?

Если второй случай, да с UDP - тогда да, тогда всё просто. Но исходя их того, что у тебя по сокету на клиента - у тебя TCP и всё заметно хуже.

Как отреагирует твой мультиплексор, если в момент на большом потоке у тебя будет клиент на медленном канале? Будет постоянно срубаться из-за того, что лезет EAGAIN? А потом ты под обработку EAGAIN будешь организовывать отдельный буфер, причем индивидуальный для каждого клиента? Посел чего у тебя начинается веселье в алгоритме мультиплексированной посылки «если очередь пуста - то мультиплекс, если нет - добавить в очередь», а уж что в обработке завершения асинхронного I/O что будет - я вообще тащусь :-)

no-dashi ★★★★★
()
Ответ на: комментарий от westtrd

Так что не пудри моск, я серьезно. 3-5 тысяч потоков нынешние железки тянут легко и непринужденно, 10 тысяч - спокойно. У тебя скорей файловые дескрипторы кончаться начнут

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

Спасибо за аргументы, подумаю над решением.

Единственно, что настораживает в случае такого варианта - латентность, есть ли мысли по этому поводу?

westtrd
() автор топика
Ответ на: комментарий от westtrd

Единственно, что настораживает в случае такого варианта - латентность, есть ли мысли по этому поводу?

В этом случае, у тебя латентность определяется скоростью передачи данных к клиенту. Закинуть сообщение в очередь - дело тысячных долей секунды. Всё остальное определяется линией связи. Накладные расходы на очереди конечно будут, но память нынче дешевая как грязь.

Зато плюсы существенны - очень простая архитектура, а значит хорошо поддается тестированию, отладке и будет работать стабильно как слон.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

с тыщей потоков, с какой периодичностью будет каждый поток получать процессорное время? На 4-процессорном сервере, допустим

Harald ★★★★★
()
Ответ на: комментарий от no-dashi

По латентности доставки вопросов и не было.

Вопрос в другом - частые переключения контекста - как они повлияют на внутреннюю латентность самого серверного приложения?

Тысячные доли секунды - для данного класса решений это очень много, оперируем от единиц до сотен микросекунд.

westtrd
() автор топика
Ответ на: комментарий от westtrd

Тысячные доли секунды - для данного класса решений это очень много, оперируем от единиц до сотен микросекунд.

тогда нужно аппаратное решение,

тут господин mv кажется хвастался чем-то подобным, на FPGA и с разработкой схемы на лиспе

Harald ★★★★★
()
Ответ на: комментарий от Harald

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

Обработка ошибок со стороны клиента примитивна - исчерпал он свой лимит по буферам - клиент отключается, и сервер его проблемы не волнуют, пусть переподключается :)

westtrd
() автор топика
Ответ на: комментарий от Harald

с тыщей потоков, с какой периодичностью будет каждый поток получать процессорное время?

С достаточной. 90% активного времени поток всё равно будет в состоянии sleep или где-то в ожидании завершения I/O. Если кому хочется, могу простенький тесткейс сделать, на пропускную способность такого решения, и прогнать его на 2/4 ядерных хостах.

no-dashi ★★★★★
()
Ответ на: комментарий от westtrd

Kernel Mode Linux : Execute user processes in kernel mode

правдо надо патчить ядро

ae1234 ★★
()
Ответ на: комментарий от no-dashi

Речь идет о плотности потока несколько десятков тысяч и сотен тысяч сообщений в секунду (в пике - единиц миллионов), причем все это по нескольким сотням разношерстных подписчиков.

westtrd
() автор топика
Ответ на: комментарий от westtrd

При этом размер отдельно взятого сообщения - десятки и единицы сотен байт

westtrd
() автор топика
Ответ на: комментарий от westtrd

несколько десятков тысяч и сотен тысяч сообщений в секунду
причем все это по нескольким сотням разношерстных подписчиков.

Несколько десятков тысяч - каждому? Ты ради интереса time ping -f -c 100000 127.0.0.1 запусти :-) 80000 пакетов в секунду через loopback, 8000 пакетов в секунду на гигабитном линке. У тебя затык будет _не_ в переключении контекста, честно-честно. Расслабься, реализуй самую простую схему и готовься строить кластер. Не ты первый, не ты последний.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

300 клиентов, 300 сообщений в секунду для каждого на 8-ядерной ноде. Ну максимум в 3 раза больше.

no-dashi ★★★★★
()
Ответ на: комментарий от westtrd

даже и не напрягайся. В IP сетях решение о маршрутизации принимается индивидуально для каждого пакета, дырка на выход очевидна одна и все 100500 пакетов всё одно встанут в одну очередь и будут последовательно обрабатываться. Так что гипотетическая «одновременная запись» в более чем один сокет - утопия.

максимум, что можно сделать - некую затыку-функцию, которая на упрощает код. К тому-же ситуёвина редкая - масса одинаковых пакетов в разные адресаты. Такой случай бывает только у спамеров и в MMORPG :)

MKuznetsov ★★★★★
()
Ответ на: комментарий от no-dashi

Одно из решений - обход стека протоколов TCP, но тут свои нюансы

westtrd
() автор топика
Ответ на: комментарий от westtrd

вам эти рыночные данные только доставить, или еще гарантировать что все клиенты будут получать данные на равных условиях?

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

Второй части нет, да и крайне сложно это обеспечить, если невозможно, при разношерстных каналах. Основное - обеспечить латентность самого сервера

westtrd
() автор топика
Ответ на: комментарий от westtrd

сама по себе латентность сервера лишена смысла - латентность каналов связи придется учитывать в любом случае.

опять же, гарантированная доставка около-микросекундных событий это и вовсе оверхед - их корректной обработки можно добиться только с rt-патчами на ядро. а отладку таких событий мы у себя с осциллографом делаем.

более того, за микросекунду даже свет пройдет всего то 300 метров - тут уже фундаментальные рамки по латентности.

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

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

Качество канала клиента, это проблемы клиента, поэтому если он исчерпывает некий лимит по high watermark, он просто тупо гасится.

Реалтайм патчи, естественно - RedHat Enterprise MRG Realtime

westtrd
() автор топика
Ответ на: комментарий от westtrd

у вас там проглядывает ошибка(или крупный просчёт) в проектировании - добавьте, точнее чётко отделите, уровень «прокси» с свою архитектуру и всё встанет на свои места.

market будет отвечать за корректность и актуальность бизнес-данных, и общается со счётным (еденицы-десятки) proxy по интерфейсам/каналам с гарантированным качеством.

proxy отвечает за сессии (сотни-тысячи) с клиентами и передаёт им данные от маркета, не отвечая впрочем за доставку.

у них и аппаратные требования разные. market`у очевидно нужен процессор,диски (данные он наверное как-то вычислияет/генерит/берёт из базы), в то время как proxy вообще почти любая 1U железка с нормальными сетевыми картами:)

Кстати, про «Реалтайм патчи, естественно» - что-то не видно в вашей задаче требований жёсткого реального времени. Да и число клиентов, сдаётся мне, надумано :)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

http://smart-lab.ru/blog/5288.php Это насчет надуманности

По маркет дате проблем нет - она приходит, для нее выделен отдельный процессор, все в памяти, и тд и тп.

Все верно, основная проблема здесь - реализация высокопроизводительного прокси, и основной компонент обозначен - запись блока данных в сотни сокетов одновременно (условно), а основное, что я хочу получить - стабильно быстрое освобождение серверного процесса после записи в буферы сокетов, при этом нужно минимизировать оверхеды на массированные системные вызовы. Качество соединения обрабатывается просто - клиент не справляется с потоком, сокет дропается по переполнению high watermark, все.

Реализация на двухпроцессорных блейдах, мощности более чем достаточно. Мне не нужно жесткое реальное время, мне нужна низкая латентность на стороне серверного процесса с минимальной девиацией. Именно для этого применяется реалтайм ядро.

westtrd
() автор топика
Ответ на: комментарий от westtrd

Если вы считаете, что возможность одним вызовом отправлять пачку пакетов для вас критична,

то про POSIX AIO уже выше сказали, когда-то были подвижки внести-таки его на уровень ядра Linux, но сильно сомневаюсь что это произошло (давненько не следил за kerneltrap), хотя стоит проверить. Или возьмите ОС в которой более эффективно реализованы эти фичи - Linux`ом мир не ограничивается.

а вообще возьмитесь и реализуйте нужный функционал на epoll - потому как производительности процессор/память более чем достаточно. Убедитесь, что у вас скорее сеть заткнётся - бутылочное горлышко это сетевой интерфейс.

кстати, «сокет дропается по переполнению high watermark» - это у вас самодельный протокол с квитированием крутится, или вы что-то стандартное используете ?

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Такой подход, например, реализован в zeromq

А вообще, high watermark for read&write для сокетов предусмотрен стандартом POSIX и присутствует в большинстве реализаций

westtrd
() автор топика
Ответ на: комментарий от westtrd

из треда не очень понятно что за тыщщи сокетов и на каком протоколе :) Может там не слишком эффективный собственный протокол, да ещё поверх TCP, да ещё и с проблемной реализацией. Всякие чудеса бывают :)

по теме, ещё раз: lio_listio или writev (что практически одни и те-же яйца, вид с разных боков), смотреть уровень поддержки и ограничения в ядре или переползать на другую систему.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

lio_listio или writev - у них вообще нет практически ничего общего

ae1234 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.