2010-04-20 5 views
10

У меня есть эта ситуация .... Клиент-инициированный SOAP 1.1 обмен данными между одним сервером и, скажем, десятками тысяч клиентов. Клиенты являются внешними, входящими через наш брандмауэр, аутентифицированными сертификатом, https и т. Д. Они могут быть в любом месте и обычно имеют свои собственные брандмауэры, NAT-маршрутизаторы и т. Д. Они являются действительно внешними, а не просто удаленными корпоративными офисами. Они могут быть в корпоративной/университетской сети, DSL/Cable, даже Dialup.Какой сетевой протокол используется для облегченного уведомления о удаленных приложениях?

Клиент использует Delphi (исправления 2005 + SOAP с 2007 года), а сервер - C#, но с точки зрения архитектуры/дизайна это не имеет значения.

В настоящее время клиенты выталкивают новые данные на сервер и вытаскивают новые данные с сервера на 15-минутный цикл опроса. Сервер в настоящее время не передает данные - клиент попадает в метод «messagecount», чтобы узнать, есть ли новые данные для вытягивания. Если 0, он спит еще 15 минут и снова проверяет.

Мы пытаемся довести это до 7 секунд.

Если бы это было внутреннее приложение с одним или несколькими десятками клиентов, мы бы написали услугу мыла cilent «прослушиватель» и подталкивали бы к ней данные. Но поскольку они являются внешними, сидите за собственными брандмауэрами, а иногда и частными сетями за NAT-маршрутизаторами, это нецелесообразно.

Итак, у нас остается опрос в гораздо более быстрой петле. Клиенты 10K, каждый из которых проверяет свой messagecount каждые 10 секунд, составят 1000/sec-сообщений, которые в основном будут использовать только пропускную способность, сервер, брандмауэр и ресурсы аутентификатора.

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

Я не думаю, что было бы целесообразно, чтобы сервер посылал мыльные сообщения клиенту (push), так как это потребовало бы слишком большой конфигурации на стороне клиента. Но я думаю, что есть альтернативы, о которых я не знаю. Например:

1) Есть ли способ для клиента сделать запрос GetMessageCount() через Soap 1.1 и получить ответ, а затем, возможно, «остаться на линии», возможно, на 5-10 минут до получать дополнительные ответы в случае поступления новых данных? т.е. сервер говорит «0», а затем через минуту в ответ на некоторый триггер SQL (сервер C# на сервере Sql, btw), знает, что этот клиент по-прежнему «находится в строке» и отправляет обновленное количество сообщений «5» «?

2) Есть ли другой протокол, который мы могли бы использовать для «ping» клиента, используя информацию, полученную из последнего запроса GetMessageCount()?

3) Я даже не знаю. Думаю, я ищу какой-то магический протокол, где клиент может отправить запрос GetMessageCount(), который будет включать в себя информацию для «о, кстати, в случае, если ответ изменится в следующий час, пингуйте меня по этому адресу ... ».

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

Есть ли что-нибудь в этом роде? Или я почти застрял в опросе?

ТИА,
Крис

UPDATE 4/30/2010:
Продемонстрировав, что с 7-второе уведомление не является ни легким, ни дешевым, особенно, не выходя за пределы корпоративного стандарта HTTPS/SOAP/Firewalls , мы, вероятно, собираемся передать двухфазное решение. Фаза 1 будет проводить опрос клиентов по запросу, при этом GetMessageCount выполняется через SOAP, здесь ничего особенного. Появится кнопка «Обновить», чтобы вытащить новые данные (что разумно здесь, поскольку у пользователя обычно есть основания подозревать, что новые данные готовы, т. Е. Они просто изменили цвет ткани в онлайн-системе, поэтому они знают, что нужно щелкнуть REFRESH, прежде чем просматривать декларацию доставки на рабочем столе, и теперь они видят цвет в описании.) (Это не приложение для одежды и моды, но вы получаете идею). Понятие о том, что два aps всегда синхронизированы, с обновлениями в реальном времени, вытесненными с хоста, все еще находится на столе, используя технологии, обсуждаемые здесь. Но я ожидаю, что он будет оттеснен на другой выпуск, так как мы можем доставить 85% функциональности, не делая этого. Однако я надеюсь, что мы сможем сделать Proof Of Concept и продемонстрировать, что это сработает. Я вернусь и опубликую будущие обновления. Спасибо за помощь всем.

+0

Привет, ребята, я добавил щедрость, но это не значит, что мне не нравятся ответы до сих пор! Я хотел убедиться, что это было рассмотрено как можно больше, и, кроме того, я всегда хотел сделать щедрость ... Здесь много замечательных ответов, и я очень ценю это. –

+0

Хотелось бы, чтобы я мог разделить щедрость ... здесь есть много замечательных ответов, и, возможно, самое полезное на данный момент в проекте - это подавляющее согласие, соглашающееся с моей позицией, что мы не можем обрабатывать 10K-соединения, которые делают быстрый опрос, и мы можем нажимать на них данные как обычные слушатели SOAP. –

ответ

3

Две крупные партии по развитию многоуровневых в Delphi являются components4developers (с их kbmMW продукта, описанного в ответ Марк Робинсон) и RemObjects с их продуктом RemObjects SDK (у них есть хороший пример, который может быть похож на то, что вы хотите: Push notifications for iPhone).

В вашей сложной среде многопроцессорный UDP не может ее обрезать, но с точки зрения перспективы он непревзойден.

Если соединение открыто, его можно использовать двунаправленным способом (это также используется удалением .NET и WCF), но имеет дополнительные накладные расходы.

Вам нужно будет найти баланс между сохранением связей в реальном времени (блокирование ресурсов) и созданием новых соединений (время ожидания и латентность).

--jeroen

+0

Спасибо - у нас действительно есть лицензия на RemObjects здесь, она была куплена для проекта, который не сошел с земли. Я выкопаю его и просмотрю их пример. –

+0

@Chris: Если вы решите свою проблему, сообщите нам, как вы ее решили! –

+0

+ Принято как это, вероятно, будет нашим решением. Хотелось бы, чтобы я расколол щедрость на этом и несколько других, рекомендующих RemObjects и kbmMW. Спасибо всем! –

4

Я бы взглянуть на kbmMW

я бы, возможно, использовать метод, аналогичный MS Exchange - тогда подключения и авторизации через TCP/IP, затем уведомления об обновлении (ов) от сервера к клиенту через UDP, клиент получает запрос udp и загружает обновление через tcp/ip.

(По крайней мере, как я понимаю, MS Exchange работает)

+0

Ницца - я посмотрю. Мне нравится часть: «использование сообщений на основе публикации/подписки через несколько типов доступных для разработчиков и настраиваемых очередей сообщений». –

+0

Ваше уведомление udp звучит так же, как и я. Знаете ли вы, сможет ли он вернуться через один и тот же порт брандмауэра? Я надеюсь на нулевую конфигурацию здесь (нуль поверх того, что им уже нужно для SOAP через https). –

+0

У меня есть большая любовь к kbmMW - это немного кривая обучения, но тогда это просто просто бессмысленная базовая версия! –

1

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

Возможно, вы сможете сократить накладные расходы на опрос, упростив вызов. Используйте простое веб-действие, чтобы вернуть наивысший номер сообщения клиенту и попросить клиента выполнить простой HTTP GET, чтобы получить этот номер. Это уменьшает пропускную способность и упрощает ее. Если тогда клиент должен получить обновленные данные, можно сделать полный вызов мыла.

1

В любое время, когда у вас есть один сервер и более 10 000 клиентов, и вам нужно каждые несколько секунд получать обновления, в которые вы столкнетесь. Я бы получил еще несколько серверов и поддерживал подключение клиентов в фоновом потоке на клиенте, который изначально подключается, а затем ждет, чтобы уведомления поступали с сервера с помощью встроенного механизма keep alive.

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

3

Вы можете попробовать позвонить на сервер и подождать на сервере в течение некоторого времени (1 минута?), Пока у вас не будет обновлений. Таким образом, вам не нужно подключение от сервера к клиенту, и вы получаете почти мгновенные результаты для клиента (если у вас есть обновления в течение 1 минуты, вы заканчиваете ожидание вызова). Это относительная легкость и широко (?), Используемая веб-приложениями (например, Gmail: у нее есть фоновое соединение, подобное этому: если новое письмо приходит, вы сразу видите его в папке «Входящие»!). Я использую что-то вроде этого (RemObjects):

function TLoggingViewService.GetMessageOrWait: TLogMessageArray; 
begin 
    if (Session.Outputbuffer.Count > 0) or 
    //or wait till new message (max 3s) 
    Session.Outputbuffer.WaitForNewObject(3 * 1000) 
    then 
    //get all messages from list (without wait) 
    Result := PeekMessage; 
end; 

Отрицательная точка: вы держите соединение открытым для относительного длительного времени (?, Что если соединение теряется из-за Wi-Fi и т.д.) и высокий сервер «нагрузки» (каждое соединение имеет поток, остается открытым: если у вас много клиентов, вы можете получить ресурсы).

Здесь мы используем RemObjects и используем TCP + Binmessage, у которого MUCH MUCH меньше накладных расходов, чем SOAP + HTTP, и очень быстро! Поэтому, если вы можете использовать это, я действительно рекомендую это! (в вашем случае вам нужны Remobjects для Delphi и RemObjects для .Net). Используйте только SOAP, если вам нужно подключиться к сторонним сторонам и использовать HTTP только в том случае, если это необходимо из-за интернета/брандмауэра. SOAP хорош, но имеет высокие накладные расходы и проблемы с производительностью.

Вы также можете использовать комбинацию из них: простое (RemObjects) TCP-соединение (с низкими накладными расходами) в фоновом потоке, опрос каждого 10-ти и ожидание 5 секунд для новых данных.

7

Рассмотрите возможность «играть» по протоколу HTTP, чтобы получить то, что вы хотите, в то же время имея возможность просматривать все прокси и NAT и брандмауэры, которые могут быть на стороне клиента.

У каждого отдельного клиента есть простой HTTP-запрос для подсчета сообщений таким образом, который препятствует какому-либо кешированию (пример: GET http://yourserver.org/getcount/nodeid/timeofday/sequence). В серверной реализации задержки HTTP-сервера, предоставляющей ответ, если «счетчик» является таким же, как раньше (т. Е. Нет новых сообщений).

Я сделал это для приложения в стиле Ajax, которое запускалось в браузере и немного походило на приложение чата, но ваше решение может быть еще быстрее. Я реализовал серверный материал с использованием сервера TIdHttp, и это позволило мне фактически отложить предоставление ответа на клиентский материал просто Sleep() - в его потоке. Со стороны клиента он выглядел как сервер, который иногда очень медленно дал ответ.

псевдокода для серверного материала:

function ClientHasMessages(ClientID:Integer; MaxWait:TDateTime):Boolean; 
var MaxTime:TDateTime; 
begin 
    if ClientActuallyHasMessage(ClientID) then Result := True 
    else 
    begin 
     MaxTime := Now + MaxWait; 
     while Now < MaxTime do 
     begin 
     if ClientActuallyHasMessage(ClientID) then 
      begin 
      Result := True; 
      Exit; 
      end 
     else 
      Sleep(1000); 
     end; 
     Result := False; // TimeOut 
    end; 
end; 

Идея этого кода: Она работает в потоке на ваш собственном сервере, где он может проверить количество сообщений, по-видимому, очень мало затрат:

  • Он не вызывает сетевого трафика во время ожидания.
  • Он не использует процессор во время сна.
  • Это позволит пользователю узнать о его сообщении очень быстро.
  • Это позволяет клиенту контролировать, как долго может быть ожидание (клиент увеличит время, в течение которого сервер может задержать ответ, пока он больше не получит ответ, а затем немного отступит - таким образом протокол адаптируется к любой багги-маршрутизатор NAT, который использует клиент).
  • Вы можете уйти с длинными периодами отсутствия связи TCP/IP и все еще иметь возможность предоставить ответ мгновенно. 30 секунд легко сделать, и для клиентов с хорошими маршрутизаторами NAT это может быть намного дольше.

Обратного размером этого будет требованием на сервере, но я соблазн сказать, что они выполнимы:

  • нуждается в реализации TCP/IP сервера для отслеживания довольно ряда одновременных подключений (каждый клиент будет всегда иметь HTTP-запрос активным). Моя Linux-машина NAT отслеживает соединения 15K прямо сейчас, и она в основном бездействует, поэтому она может работать.
  • Сервер будет иметь поток, открытый для каждого запроса HTTP-клиента, и всегда: «Рабочая станция» Server 2008 «Я использую эту запись (спасибо MSDN за то, что позволила мне делать такие возмутительные вещи) около 1500 потоков активны, а также в основном бездействуют ...
  • В зависимости от технологии, используемой для серверного кода, ПАМЯТЬ может быть ограничивающим фактором.
3

Я провел тестирование производительности в системах, даже больших, чем у ваших 10K-клиентов, и когда вы достигнете указанного количества запросов/сек, вы, скорее всего, столкнетесь с проблемами с Connections/sec, одновременными открытыми соединениями, брандмауэрами, становящимися медленными и т. д. (Значительно те же проблемы, с которыми может столкнуться Torrent Tracker).

Если клиентам нужно только «спросить, есть ли что-то новое», самый легкий протокол, который легко реализовать, это UDP, следующим легким будет чистый TCP, как с использованием клиентов Indy.

Сам протокол действительно может быть таким же простым, как отправка «Все новое с момента [yyyy-mm-dd hh: mm: ss]» на сервер и ответ с 1 байтовым номером (возможно 256 ответов).

С помощью TCP у вас будет дополнительное преимущество в том, чтобы держать «трубу» открытой в течение нескольких минут, и вы можете отправлять «что-нибудь новое» сообщение каждые х секунд. Также с TCP сервер может «нажимать» информацию на канал (клиент (ы)), когда что-то происходит, учитывая, что клиент периодически проверяет данные в трубе.

+1

Поскольку IP-пакет имеет довольно накладные расходы, на самом деле нет смысла отвечать одним байтом. Если вы вызываете отправку пакета, просто отправьте обратно то, что необходимо для передачи информации - 4 или 8 байтов вместо 1, например, не будет делать *, что * большая разница ... – mghie

+0

Совершенно верно, так что на самом деле можно просто пойти для клиента, который затем прослушивает что-то на какое-то время и отключается, если ничего не существует ... Реальный трюк заключается в выборе хороших значений для того, чтобы оставаться на связи, и когда снова подключаться ... –

+0

Вдоль этих строк, я думаю, что возможно, мы должны создать второй сервер «messagecount», вне брандмауэра. Основной сервер будет подталкивать сообщения к ним, когда они меняются. Затем клиенты будут подключаться к серверу MessageCount с помощью одного из этих методов. Даже если мы прибегаем к вызовам http get, они не будут беспокоить наши внутренние брандмауэры и аутентификаторы, поскольку предположительно, messagecount может быть представлен таким образом, что его не нужно будет защищать. Интересно! –

2

Я попытался бы распределить нагрузку как можно больше между несколькими серверами. Для этого я бы сделал следующее:

  1. Клиенты регистрируются в вашем сервисе для получения уведомлений. Они получают идентификатор сеанса, который действителен в течение заданного времени (15 минут).
  2. Серверы будут периодически проверять, у какого зарегистрированного клиента есть входящее сообщение, и сгенерировать список таких клиентов (технически я бы ввел это в другую БД в DMZ).
  3. Вы запускаете несколько серверов «push-уведомления», которые следуют очень и очень простному протоколу: они получают URL-запрос, содержащий идентификатор сеанса, и отвечают коротким ответом HTTP: либо 404, либо 200 с (подписанным) URL-адрес сервера SOAP для адресации, чтобы захватить сообщения. Для дополнительных характеристик вы можете использовать HTTP 1.1 и постоянные соединения.
  4. Клиент будет объединять эти серверы push-уведомлений так часто, как они хотят. Поскольку они очень просты и строго предназначены для чтения, они могут очень быстро отвечать на запросы и будут легко масштабироваться.
  5. Если клиент получает ответ 302, он может подключиться к правильному SOAP-серверу (вы также можете использовать его для распределения нагрузки, если хотите) и вытащить сообщения.

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

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

2

Мы используем RemObjects SDK «событие» для этого, но это может быть не подходят для вас, потому что

A: Это работает только с RemObjects собственного бинарного протокола, не SOAP (т.е. клиенты должны включать код RO)

b: В принципе, это подход «держать линию открытой». поэтому масштабирование до клиентов 10K является потенциальной проблемой.

Я бы попробовал несколько тестов, чтобы увидеть, что на самом деле имеет накладные 10K розетки. Если все, что вам нужно, это пара концертов дополнительной серверной памяти, это будет дешевое решение. И поскольку сокет открывается со стороны клиента, он не должен вызывать проблемы с брандмауэром. Самое худшее, что может сделать брандмауэр, это закрыть сокет, поэтому вашему клиенту потребуется его снова открыть, когда это произойдет.

+0

Спасибо, это подход, к которому я склоняюсь, но с завихрением: я думаю о наличии отдельного сервера только для уведомлений. Поскольку уведомления не содержат фактическую полезную нагрузку данных (которая останется в SOAP, https, аутентификация сертификатов через брандмауэр и т. Д.) И будет иметь только идентификатор клиента и количество сообщений, безопасность не такая большая беспокойство. Таким образом, мы можем поместить это в DMZ или даже использовать внешний хостинг. cont ... –

+0

... Итак, теперь возникает вопрос о том, «сколько серверов вам нужно обрабатывать 10K RemObjects», вместо «сколько $$$ будет стоить поддержка 10K SOAP reqests, через https, с аутентификацией сертификата клиента через наш ESB, вплоть до нашей базы данных Sql * Server? " –

+0

@ Родди, могу я спросить, сколько клиентов вы открываете одновременно? И есть ли пример проекта, который вы бы рекомендовали мне посмотреть, используя RO SDK? Я надеюсь получить некоторое время, чтобы прототип его через несколько недель (похоронили с производством прямо сейчас). –

0

Что-то немного в левом поле.

Почему аутентификация требуется только для получения флага, в котором говорится, что обновления готовы? Почему бы не иметь машину за пределами брандмауэра аутентификации ... или даже в облаке ..., которая ничего не делает, кроме как обрабатывать эти запросы «что угодно». Затем, если что-то доступно, клиент может пройти через обручи, чтобы получить реальные данные. Этот сервер запросов мог бы сделать 7-секундный getcount с реального сервера.

Мы сейчас говорим очень мало данных и очень мало времени на установку простого «флага», даже не подсчета.

Его по-прежнему тысячи запросов, но тысячи запросов с минимальными накладными расходами по сравнению с полным аутентифицированным запросом.

Смежные вопросы