Обработка тайм-аутов веб-службы при выполнении длительных задач базы данных - PullRequest
13 голосов
/ 07 февраля 2009

Архитектура одного из наших продуктов является типичным 3-уровневым решением:

  • C # клиент
  • Веб-сервис WCF
  • База данных SQL Server

Клиент запрашивает информацию у веб-службы. Веб-сервис обращается к базе данных за информацией и возвращает ее клиенту.

Вот проблема. Некоторые из этих запросов могут занимать очень много времени, и мы не знаем заранее, какие из них будут медленными. Мы знаем некоторые, которые часто медленнее других, но даже самые простые запросы могут быть медленными при наличии достаточного количества данных. Иногда используется запрос или запуск отчетов на больших объемах данных. Запросы можно оптимизировать только до тех пор, пока их объем не замедлится.

Если запрос в базе данных достигает максимального времени ожидания запроса на сервере SQL, запрос к базе данных завершается, и веб-служба возвращает ошибку клиенту. Это понятно. Мы можем справиться с этими ошибками.

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

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

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

Было бы здорово, если бы мы могли отделить процесс создания HTTP-запроса от процесса запуска и запуска процесса базы данных. Я видел, как это было сделано с пользовательским сервером в предыдущей компании, но он использовал прямую связь через сокет, и я бы предпочел не заменять веб-сервис каким-либо пользовательским приложением.

Обратите внимание, что с учетом объема данных, с которыми мы имеем дело, мы полностью оптимизируем запросы. Оптимизация запросов, индексы и т. Д. Делают это только тогда, когда объем данных велик. Иногда все просто занимает много времени.

Ответы [ 4 ]

6 голосов
/ 08 февраля 2009

В прошлом я сталкивался с похожими проблемами и использовал один из следующих 3 методов для их решения:

  1. Добавьте все долго выполняющиеся запросы в очередь и обработайте их последовательно.
    В моем случае это были сложные отчеты, которые затем отправлялись по электронной почте клиенту или хранились в постоянных «временных» таблицах для просмотра клиентами после их уведомления.
  2. Мы вызвали веб-сервис с помощью вызова JQuery, который затем вызвал метод обратной передачи javascript, когда он был завершен.
    Это работало хорошо, когда мы не хотели синхронизировать загрузку страницы с тем, что делал веб-сервис.
    Однако это означало, что эта функциональность была недоступна до тех пор, пока не завершился длительный процесс.
  3. Самый сложный.
    Мы открыли другое окно, в котором отображался индикатор выполнения, который также периодически опрашивал сервер.
    Это использовало переменную сеанса, чтобы определить, как далеко, чтобы показать индикатор выполнения.
    После запуска индикатора выполнения был запущен новый поток, который периодически обновлял одну и ту же переменную сеанса.
    Как только значение переменной сеанса было установлено равным 100, всплывающее окно само закрылось.
    Клиенты любили этот метод.

В любом случае, я надеюсь, что один из них поможет вам.

5 голосов
/ 07 февраля 2009

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

2 голосов
/ 18 февраля 2010

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

Например, мы разбили несколько огромных процессов на ряд шагов, таких как «Начало», «Процесс 1», «Завершение» и «Сбор данных отчета». Шаги Process Work могут выполняться параллельно, но они не могут начаться, пока не завершится шаг Start. Шаг Finish должен ждать завершения всех шагов Process Work.

Поскольку клиент контролирует процесс, клиент может сообщить о ходе выполнения, на каком именно этапе он находится.

0 голосов
/ 19 октября 2016

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

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

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

Это немного тяжелый вес (особенно, если вы еще не работаете в веб-сервере), но гарантирует успешную обратную передачу в случае, если время ожидания клиента истекло, но веб-служба правильно получила инструкцию и просто медленно обрабатывает.

Как только это настроено, ваш веб-сервис на самом деле немного ближе к тому, чтобы быть готовым к асинхронному запуску и, таким образом, быстро отвечать клиенту: обычно делают любые проверки, чтобы ответить, если это нормально, или нет, и вызывать медленную операцию на отдельной цикл, с URL обратного вызова, чтобы он мог сообщить клиенту.

Я не уверен, насколько это ортодоксально, кстати, но это действительно решило реальные проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...