Какой сетевой протокол использовать для легкого уведомления об удаленных приложениях?

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

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

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

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

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

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

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

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

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

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

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

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

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

TIA,
Chris

ОБНОВЛЕНИЕ 30.04.2010:
Продемонстрировав, что наличие 7 вторых уведомлений не является ни легким, ни дешевым, особенно не выходя на улицу из корпоративного стандарта HTTPS/SOAP/брандмауэров, мы, вероятно, собираемся передать двухфазное решение. Phase1 сделает, чтобы клиенты опросили "по запросу" с GetMessageCount, выполняемым через SOAP, ничто не полагает здесь. Будет кнопка "обновления" для получения по запросу новых данных (который разумен здесь, поскольку у пользователя обычно будет причина подозревать, что новые данные готовы, т.е. они просто изменились, матрица раскрашивают систему онлайн, таким образом, они знают для нажатия на REFRESH прежде, чем просмотреть поставлющуюся декларацию на рабочем столе, и теперь они видят цвет в описании.) (Это - Едва ли приложение предмета одежды/вида, но Вы получаете идею). Понятие наличия двух aps всегда быть в синхронизации, с обновлениями в реальном времени, продвинутыми от хоста, находится все еще на таблице, с помощью технологий, обсужденных здесь. Но я ожидаю, что это будет отодвинуто для другого выпуска, поскольку мы можем поставить 85% функциональности, не имея необходимость делать это. Однако я надеюсь, что мы добираемся, чтобы сделать Подтверждение концепции и можем продемонстрировать, что оно будет работать. Я возвращусь и отправлю будущие обновления. Спасибо за общую справку на этом.

10
задан Chris Thornton 30 April 2010 в 13:28
поделиться

9 ответов

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

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

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

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

- jeroen

3
ответ дан 3 December 2019 в 16:09
поделиться

Push-уведомления для iPhone работают, только если вашими удаленными устройствами являются iPhone. Единственные другие варианты - это держать соединение открытым (хотя в основном в режиме ожидания) или опрос от клиента.

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

1
ответ дан 3 December 2019 в 16:09
поделиться

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

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

1
ответ дан 3 December 2019 в 16:09
поделиться

Вы можете попробовать позвонить на сервер и подождать на сервере некоторое время (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, который имеет НАМНОГО меньше накладных расходов, чем SOAP + HTTP, и работает очень быстро! Так что, если вы можете это использовать, я действительно могу это порекомендовать! (в вашем случае вам нужны Remobjects для Delphi и RemObjects для .Net). Используйте протокол SOAP только в том случае, если вам необходимо подключиться к третьим сторонам, и используйте HTTP только в том случае, если он вам нужен из-за Интернета / брандмауэра. SOAP хорош, но имеет большие накладные расходы и проблемы с производительностью.

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

3
ответ дан 3 December 2019 в 16:09
поделиться

Я бы посмотрел на kbmMW

Я бы, возможно, использовал метод, аналогичный MS Exchange - соединение и аутентификация через tcp / ip, затем уведомление об обновлениях от сервера к клиенту через udp, затем клиент получает запрос udp и загружает обновление через tcp / ip.

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

4
ответ дан 3 December 2019 в 16:09
поделиться

Подумайте о том, чтобы немного "поиграть" по протоколу 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 активных потоков, которые также в основном простаивают ...
  • В зависимости от технологии, которую вы используете для серверного кода, ПАМЯТЬ может быть ограничивающим фактором.
7
ответ дан 3 December 2019 в 16:09
поделиться

Я провел тестирование производительности на системах, даже больше, чем ваши клиенты 10K, и когда вы достигнете указанного количества запросов в секунду, вы, скорее всего, столкнетесь с проблемами, связанными с количеством подключений в секунду, одновременными открытыми подключениями, медленными брандмауэрами и т. Д. ( Примерно те же проблемы, с которыми может столкнуться Torrent Tracker).

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

Сам протокол на самом деле может быть таким же простым, как отправка на сервер сообщения «Что-нибудь новое с [гггг-мм-дд чч: мм: сс]» с ответом с 1-байтовым числом (возможно 256 ответов).

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

3
ответ дан 3 December 2019 в 16:09
поделиться

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

  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
ответ дан 3 December 2019 в 16:09
поделиться

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

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

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

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

2
ответ дан 3 December 2019 в 16:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: