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

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

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

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

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

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

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

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

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

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

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

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

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

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

ТИА,
Крис

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

Ответ 1

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

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

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

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

- Йерун

Ответ 2

Подумайте о том, чтобы немного "проиграть" 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;

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

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

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

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

Ответ 3

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

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

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

Ответ 4

Вы можете попробовать позвонить на сервер и подождать на сервере в течение некоторого времени (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;

Отрицательная точка: вы поддерживаете соединение открытым относительно долгое время (что, если соединение потеряно из-за wifi и т.д.) и высокая загрузка сервера (каждое соединение имеет поток, остается открытым: если у вас много клиентов вы можете избавиться от ресурсов).

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

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

Сейчас мы говорим очень мало данных и очень мало времени для простого "флага", даже не считая.

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