Добрый день! Есть клиент-серверное приложение для передачи торговой информации.Есть две проблемы:
1) Низкая производительность сервиса ( до 1500 колбеков в секунду)
2) Когда один из клиентов начинает зависать(например,проблемы с интернетом) все пользователи начинают медленнее получать данные (до 200 колбеков в секунду)
Здравствуйте, alex_2371430, Вы писали: _>Подскажите,пожалуйста,как можно решить эти проблемы
Никак. Большое количество маленьких сообщений — killing scenario для WCF. Группируй сообщения в пачки и рассылай всем 2-3 раза в секунду — уже станет полегче. С "плохим каналом у одного клиента" из коробки пожалуй ничего не сделаешь — придется ручками реализовывать очередь поставщик-потребитель и писать свой биндинг. И еще наткнешься на ограниченное кол-во одновременно подключенных клиентов — у меня после 2 тысяч одновременных колбеков все становилось совсем плохо и где-то после 4х — все умирало напрочь.
Здравствуйте, itslave, Вы писали:
I>Здравствуйте, alex_2371430, Вы писали: _>>Подскажите,пожалуйста,как можно решить эти проблемы I>Никак. Большое количество маленьких сообщений — killing scenario для WCF. Группируй сообщения в пачки и рассылай всем 2-3 раза в секунду — уже станет полегче. С "плохим каналом у одного клиента" из коробки пожалуй ничего не сделаешь — придется ручками реализовывать очередь поставщик-потребитель и писать свой биндинг. И еще наткнешься на ограниченное кол-во одновременно подключенных клиентов — у меня после 2 тысяч одновременных колбеков все становилось совсем плохо и где-то после 4х — все умирало напрочь.
Хотя по поводу своего биндинга я погорячился. Достаточно очереди поставщик-потребитель при отправке колбеков.
Из описания совсем-совсем непонятно, кто кого вызывает и как вообще все устроено.
Сервер все время пушит клиентам данные (через callback-интерфейс)? Если да — то по какому принципу? В бесконечном цикле, так часто, как успеет? Или как?
Здравствуйте, Tom, Вы писали:
Tom>А ты уверен что проблема в WCF? А не в коде который собственно эти колбэки и вызывает? Вызываются они надеюсь не последовательно а паралельно?
100% у него последовательно.
Однако распареллеливание "в лоб", через ThreadPool, убьет перфоманс быстрей последовательной отправки
И ет я про оверхед трафика молчу
Здравствуйте, scale_tone, Вы писали:
_>Из описания совсем-совсем непонятно, кто кого вызывает и как вообще все устроено.
Судя по именам методов, я догадываюсь про предметную область, а судя по постановке вопроса — про "архитектуру" _>Сервер все время пушит клиентам данные (через callback-интерфейс)? Если да — то по какому принципу? В бесконечном цикле, так часто, как успеет? Или как?
100% сервер оповещает клиентов, по наступлению некоторого события. Достаточно часто, до 300 раз в секунду.
Tom>>А ты уверен что проблема в WCF? А не в коде который собственно эти колбэки и вызывает? Вызываются они надеюсь не последовательно а паралельно? I>100% у него последовательно.
В этом и проблема
I>Однако распареллеливание "в лоб", через ThreadPool, убьет перфоманс быстрей последовательной отправки
Ты попробуй через таски, там не совсем честный ThreadPool.
Есть ещё очереди откуда таск работающий в потоке ThreadPool-а может брать таски.
Должно работать очень эффективно.
По крайней мере стоит проверить.
I>И ет я про оверхед трафика молчу
А причём тут трафик вообще? Я про последовательный/паралельный вызов колбэков...
Здравствуйте, Tom, Вы писали:
I>>Однако распареллеливание "в лоб", через ThreadPool, убьет перфоманс быстрей последовательной отправки Tom>Ты попробуй через таски, там не совсем честный ThreadPool. Tom>Есть ещё очереди откуда таск работающий в потоке ThreadPool-а может брать таски. Tom>Должно работать очень эффективно. Tom>По крайней мере стоит проверить.
А там можно выделить максимальное число потоков на обслуживание тасков? Если да — то тот жы поставщик-потребитель, только в профиль. Если нет — на нагрузках ТС(тысячи подключенных клиентов, которых надо оповестить сотни раз в секунду) оно все равно умрет. Может чуть медленее.
Tom>А причём тут трафик вообще? Я про последовательный/паралельный вызов колбэков...
А ет следующий вопрос, который задаст ТС
Здравствуйте, scale_tone, Вы писали:
_>Здравствуйте, alex_2371430, Вы писали:
_>Из описания совсем-совсем непонятно, кто кого вызывает и как вообще все устроено.
_>Сервер все время пушит клиентам данные (через callback-интерфейс)? Если да — то по какому принципу? В бесконечном цикле, так часто, как успеет? Или как?
_>Или клиент что-то спрашивает, а сервер отвечает?
Да,сервер рассылает клиентам данные (через callback-интерфейс).
Если упустить подробности:есть BlockingCollection<T> в нее добавляются объекты для отправки,есть 8 Task'ов которые обрабатывают её примерно следующим:
factory.StartNew(() => Sending(DeliveryBuffer));
public void Sending( BlockingCollection<ConvertedEntity> sendBuff)
{
foreach(var ent in sendBuff.GetConsumingEnumerable() )
{
//send update..
}
}
Решение которое мы приняли — отказ от WCF и переход на Socket'ы и ProtoBuff .NET для сериализации.Результат — до 30к апдейтов в секунду.Думаю тема более не актуальна
Здравствуйте, alex_2371430, Вы писали:
_>Здравствуйте, scale_tone, Вы писали:
_>>Здравствуйте, alex_2371430, Вы писали:
_>>Из описания совсем-совсем непонятно, кто кого вызывает и как вообще все устроено.
_>>Сервер все время пушит клиентам данные (через callback-интерфейс)? Если да — то по какому принципу? В бесконечном цикле, так часто, как успеет? Или как?
_>>Или клиент что-то спрашивает, а сервер отвечает?
_>Да,сервер рассылает клиентам данные (через callback-интерфейс). _>Если упустить подробности:есть BlockingCollection<T> в нее добавляются объекты для отправки,есть 8 Task'ов которые обрабатывают её примерно следующим: _>
Есть подозрение что в foreach у тебя лочится вся коллекция и все потоки дружно ждут, пока один из них не пробежит целый цикл.
Надо отправку одного сообщения одному клиенту выделять в отдельную задачу — тогда будет могопоточность. Но ет имха тебя не сильно спасет. Озвучь требования к количеству одновременно подключенных клиентов и к количеству событий в секунду, о которых надо оповестить клиентов.
Здравствуйте, alex_2371430, Вы писали:
_>Решение которое мы приняли — отказ от WCF и переход на Socket'ы и ProtoBuff .NET для сериализации.Результат — до 30к апдейтов в секунду.Думаю тема более не актуальна
Самопальные протоколы — это тот еще геморой. Затрахаетесь с "допиливанием" — поддержкой безопасного соединения, масштабируемость и т.д.
Поэтому, я бы рекомендовал
1. Найти низкоуровневую сетевую "сокетную" библиотеку. Они есть.
2. Реализовать на ней высоконагруженную часть, т.е. колбеки.
3. Все остальное оставить на WCF. Потом придется прикручивать секурити, ssl и т.д. — в WCF ет делается просто и легко.
Здравствуйте, alex_2371430, Вы писали:
I>>Надо отправку одного сообщения одному клиенту выделять в отдельную задачу — тогда будет могопоточность.
_>Изначально так было,но отказались от такого варианта — слишком большое количество потоков,производительность была только хуже
3й раз: очередь поставщик-потребитель, специально для такого придумана...
Здравствуйте, itslave, Вы писали:
I>Здравствуйте, alex_2371430, Вы писали:
_>>Решение которое мы приняли — отказ от WCF и переход на Socket'ы и ProtoBuff .NET для сериализации.Результат — до 30к апдейтов в секунду.Думаю тема более не актуальна I>Самопальные протоколы — это тот еще геморой. Затрахаетесь с "допиливанием" — поддержкой безопасного соединения, масштабируемость и т.д. I>Поэтому, я бы рекомендовал I>1. Найти низкоуровневую сетевую "сокетную" библиотеку. Они есть. I>2. Реализовать на ней высоконагруженную часть, т.е. колбеки. I>3. Все остальное оставить на WCF. Потом придется прикручивать секурити, ssl и т.д. — в WCF ет делается просто и легко.
Примерно так и сделали) Только: I>1. Найти низкоуровневую сетевую "сокетную" библиотеку. Они есть.
А чем плохие обычные System.Net.Sockets? I>Самопальные протоколы — это тот еще геморой. Затрахаетесь с "допиливанием" — поддержкой безопасного соединения, масштабируемость и т.д.
Здравствуйте, alex_2371430, Вы писали: _>А чем плохие обычные System.Net.Sockets?
Тем что прийдется очень многие веще реализовывать вручную. Ту же очередь поставщик-потребитель, поддержку безопасного соединения, хождение через прокси сервера, обработку ошибок, передачу креденшналов, обработку обрывов соединений и многое другое. Другими словами вы построите кучу велосипедов с квадратными колесами, убьете дофига сил и времени, чтобы сделать колеса восьмиугольными и будете жутко гордиться своими достижениями. _>ProtoBuf .net — не самопальный протокол,а протокол для сериализации от Google. http://code.google.com/p/protobuf-net/
Это я в курсе, мой камент был про использование сокетов. Померяйте оверхед сериализации ProtoBuf, я думаю он не сильно будет больше оверхеда стандартных сериализаторов. Кстате можно ышо и паковать на лету перед отправкой. Но ет уже детали.
В любом случае, если я правильно понимаю предметную область, раздачу котировок "в лоб с одного сервера на 10 000 клиентов" сделать не получится. Ни с сокетами ни с WCF.
I>Есть подозрение что в foreach у тебя лочится вся коллекция и все потоки дружно ждут, пока один из них не пробежит целый цикл.
Нет,после вызова GetConsumingEnumerable коллекция не лочится.Одновременно несколько потоков пихают в нее данные,и несколько обрабатывают.
Я не думаю что проблема в коде,скорее дело в конфигурации или каких-то хитростях WCF.При локальном подключении (сервер и клиент запущен на одной машине) скорость возрастает в 2-3 раза.
Предметную область ты понял правильно,нужно отдавать маркетдату клиентам, цель — хотя-бы 3-4к апдейтов на всех пользователей.
Здравствуйте, itslave, Вы писали:
I>Здравствуйте, alex_2371430, Вы писали: _>>А чем плохие обычные System.Net.Sockets? I>Тем что прийдется очень многие веще реализовывать вручную. Ту же очередь поставщик-потребитель, поддержку безопасного соединения, хождение через прокси сервера, обработку ошибок, передачу креденшналов, обработку обрывов соединений и многое другое. Другими словами вы построите кучу велосипедов с квадратными колесами, убьете дофига сил и времени, чтобы сделать колеса восьмиугольными и будете жутко гордиться своими достижениями.
Не посоветуешь библиотеку с указанным тобой функционалом?
I>А там можно выделить максимальное число потоков на обслуживание тасков? Если да — то тот жы поставщик-потребитель, только в профиль. Если нет — на нагрузках ТС(тысячи подключенных клиентов, которых надо оповестить сотни раз в секунду) оно все равно умрет. Может чуть медленее.
Советую сделать эксперимент а не теоретизировать.
И почитать про work stealing у тасков.
И почитать про IO Completion Port.
Последовательный вызов тысяч клиентов да ещё и в торговой системе это звучит даже не смешно а страшно.
Вместо тасков можно попробовать асинхронный вызов, используя асинхронный IO.
Результат вызова всё равно придёт через IO Completion Port но смысл в том что во время вызова не будет задействован поток.
Tom>>А причём тут трафик вообще? Я про последовательный/паралельный вызов колбэков... I>А ет следующий вопрос, который задаст ТС
Я не умею читать мысли на расстоянии.
Здравствуйте, alex_2371430, Вы писали:
_>Нет,после вызова GetConsumingEnumerable коллекция не лочится.Одновременно несколько потоков пихают в нее данные,и несколько обрабатывают.
Ога, почитал доку — так и есть. _>Я не думаю что проблема в коде,скорее дело в конфигурации или каких-то хитростях WCF.При локальном подключении (сервер и клиент запущен на одной машине) скорость возрастает в 2-3 раза.
Разница есть. В чем — хз, скорей всего оптимизация на уровне драйверов сетевухи — емнип loopback. _>Предметную область ты понял правильно,нужно отдавать маркетдату клиентам, цель — хотя-бы 3-4к апдейтов на всех пользователей.
"На всех" — это на скольких? От этого много зависит. Даже если удасться написать "идеальный" сервис, то все упрется в пропускную способность канала провайдера. Поэтому определись, сколько одновременных коннекшнов надо держать и действительно нужно ли им получать по 4 тыщи пакетов инфы в секунду. Ну и оптимизируй размер пакета.
Вот тебе инфа для размышления.
Допустим у тебя подключено всего ничего 100 клиентов и ты на них гониш по 4000 пакетов инфы в секунду, размером по 100 байт каждый(что сущие копейки, один хеш пароля будет весить раз в 5 больше), то тебе надо иметь на сервере канал шириной 100*4000*100 = 40Мбайт/сек = 320Мбит/сек. Запас для надежности хотя бы раза в 3 накинь...
Думай. Большы сказать не могу.
Здравствуйте, Tom, Вы писали:
Tom>И почитать про IO Completion Port.
Я в курсе. Это противоречит использованию очереди для асинхронной отправки пакета/ожидания ответа?
I>>А ет следующий вопрос, который задаст ТС Tom>Я не умею читать мысли на расстоянии.
А я умею
Tom>>И почитать про IO Completion Port. I>Я в курсе. Это противоречит использованию очереди для асинхронной отправки пакета/ожидания ответа?
Это противоречит заявлениям что оно убьёт производительность.
Тем более есть огромные сомнения что твоя очередь будет более эффективной чем та что реализована внутри IO Completion Port.
Здравствуйте, Tom, Вы писали:
Tom>>>И почитать про IO Completion Port. I>>Я в курсе. Это противоречит использованию очереди для асинхронной отправки пакета/ожидания ответа? Tom>Это противоречит заявлениям что оно убьёт производительность. Tom>Тем более есть огромные сомнения что твоя очередь будет более эффективной чем та что реализована внутри IO Completion Port.
Я заявлял что использование IO Completion Port убьет производительность? Я высказывался что возможно использование тасков может это сделать.
В любом случае я советовал ТСу заюзать готовую библиотеку, а не заниматься велосипедостроением.
I>Я заявлял что использование IO Completion Port убьет производительность? Я высказывался что возможно использование тасков может это сделать.
Дефолтный шедулер т асков выполняет их в пуле потоков который по сути является обьектом IO Completion Port.
I>В любом случае я советовал ТСу заюзать готовую библиотеку, а не заниматься велосипедостроением.
Главное что бы это НЕ была библиотека сокетов...
Здравствуйте, Tom, Вы писали: I>>В любом случае я советовал ТСу заюзать готовую библиотеку, а не заниматься велосипедостроением. Tom>Главное что бы это НЕ была библиотека сокетов...
На это я тоже указал ТСу, он как раз хотел заюзать "родные" сокеты.
Здравствуйте, itslave, Вы писали:
I>Здравствуйте, Tom, Вы писали: I>>>В любом случае я советовал ТСу заюзать готовую библиотеку, а не заниматься велосипедостроением. Tom>>Главное что бы это НЕ была библиотека сокетов... I>На это я тоже указал ТСу, он как раз хотел заюзать "родные" сокеты.
Возможно я не правильно понял,но ты советовал взять готовую надстройку над сокетами с готовым функционалом:
I>Тем что прийдется очень многие веще реализовывать вручную. Ту же очередь поставщик-потребитель, поддержку безопасного соединения, хождение через прокси сервера, I>обработку ошибок, передачу креденшналов, обработку обрывов соединений и многое другое. Другими словами вы построите кучу велосипедов с квадратными колесами, I>убьете дофига сил и времени, чтобы сделать колеса восьмиугольными и будете жутко гордиться своими достижениями.
А Tom вообще советует отказаться от сокетных библиотек
_>А Tom вообще советует отказаться от сокетных библиотек
Не, надстройки, если они человеческие конечно можно использовать.
Но напрямую работать с сокетами лучше не стоит.
Иначе придётся заботиться о многих вещах самому.
Писать свой протокол, заботиться об определении того что клиент/сервер "умер", т.е. о пересоздании соединения и в целом о reliability, заботиться о протоколе, очень часто при этом приходится делать протокол с подтверждениями, а это влечёт за собой создание state machine.
vf>С этим понятно, здесь никаких препятствий нет. А какое отношение ThreadPool к IOCP имеет?
Самое непосредственное.
На Windows пока ещё не придумали как эффективно реализовывать Thread Pool без IOCP.
В .NET пуле их правда 2 используется, для IO и Worker потоков.
Здравствуйте, Tom, Вы писали:
vf>>С этим понятно, здесь никаких препятствий нет. А какое отношение ThreadPool к IOCP имеет? Tom>Самое непосредственное.
Пруф дайте, пожалуйста.
Tom>На Windows пока ещё не придумали как эффективно реализовывать Thread Pool без IOCP. Tom>В .NET пуле их правда 2 используется, для IO и Worker потоков.
Каким образом работает ThreadPool в связке с IOCP для Worker потоков, как вы себе это представляете?
vf>Каким образом работает ThreadPool в связке с IOCP для Worker потоков, как вы себе это представляете?
У IOCP есть 5 внутренних очередей. Все перечислять не надо?
Одна из этих очередей — очередь завершённых операций воода вывода.
Если в этой очереди есть пакет — IOCP будит один из потоков и отдаёт ему на обслуживание этот пакет (поток ожидает получения при помощи вызова GetQueuedCompletionStatus).
В эту очередь так же можно записать пакет руками, вызвав функцию PostQueuedCompletionStatus.
Таким образом если мы хотим организовать обработку каких то заданий асинхронно ThreadPool-ом построенным на основе IOCP то мы просто можем вызывать PostQueuedCompletionStatus. PostQueuedCompletionStatus так же используется для того что бы завершить поток ожидающий пакета из IOCP.
Обычно у каждого процесса есть дефолтный Thread Pool, он нужен например для того что бы обрабатывать входящие RPC вызовы, либо срабатывания таймера.
В 2008-ой появилось новое API для работы с ThreadPool-ом (CreateThreadpool и иже с ним... ).
Это обёртка над IOCP, разница с чистым IOCP заключается в том что в случае IOCP потоками управляешь ты сам, т.е. сам решаешь когда и сколько их создать и когда разрушать. В случае ThreadPool API это решает за тебя OS
I>Любая сетевая библиотека по сути есть "надстройка над сокетами"
HTTP стек не является. По крайней мере серверная сторона.
Он перенесён на уровень драйвера.
Это дало например возможность реализовать в IIS-е Application Pool-ы и в целом шарить один и тот же порт с различными приложениями.
Здравствуйте, Tom, Вы писали:
_>>А Tom вообще советует отказаться от сокетных библиотек Tom>Не, надстройки, если они человеческие конечно можно использовать. Tom>Но напрямую работать с сокетами лучше не стоит. Tom>Иначе придётся заботиться о многих вещах самому. Tom>Писать свой протокол, заботиться об определении того что клиент/сервер "умер", т.е. о пересоздании соединения и в целом о reliability, заботиться о протоколе, очень часто при этом приходится делать протокол с подтверждениями, а это влечёт за собой создание state machine.
Приведи,пожалуйста, пример "человеческих" библиотек?
Здравствуйте, alex_2371430, Вы писали:
_>А чем плохие обычные System.Net.Sockets?
Тем, что тогда всё сразу начнёт работать, причём независимо от виндовоз-платформы. Мелкомягким это не нужно, поэтому они и усираются, сувая свой WCF с эфемерными преимуществами в каждую дыру.
Не переживайте, если в вашем проекте не будет очередного базворда — клиенты этого даже не заметят.
Здравствуйте, Tom, Вы писали:
Tom>>WCF Tom>+ Конечно Windows Azure Service Bus
Нет. Тестил конкретно для задач которые у ТС.
Лана, колюсь: http://www.zeromq.org/ потянет эту задачу. Если ТС конечно правильно будет ее использовать.
Здравствуйте, alex_2371430, Вы писали:
_>Добрый день! Есть клиент-серверное приложение для передачи торговой информации.Есть две проблемы: _>1) Низкая производительность сервиса ( до 1500 колбеков в секунду)
Это довольно приличная величина. WCF не заточен под сценарии, где требуется куча микровызовов — слишком много расходов на внутреннюю машинерию.
_>2) Когда один из клиентов начинает зависать(например,проблемы с интернетом) все пользователи начинают медленнее получать данные (до 200 колбеков в секунду)
Специфика реализации коллбеков в дуплексных каналах. Тут нужно или чат делать для каждого клиента (ака WebSockets) или хотя бы что то вроде long polling. WCF из коробки вроде бы такого не умеет, хотя последнии версии я не смотрел.
_>Подскажите,пожалуйста,как можно решить эти проблемы
Моя имха — для колбеков организовать отдельный канал на базе HTTP Server API и WebSockets со своим сериализатором. Остальное можно оставить в WCF на другом порту.
... << RSDN@Home 1.2.0 alpha 5 rev. 59 on Windows 7 6.1.7601.65536>>