Надежная асинхронная обработка в SQL Server

Некоторые услуги предоставляются нашим клиентам третьей стороной. Данные, которые создаются на их удаленных серверах, реплицируются на локальный SQL-сервер. Мне нужно выполнить некоторую работу на этом стороннем сервере, база данных которого недоступна мне напрямую. Для этой цели они предоставляют набор API. Работа выполняется на связанном сервере SQL заданием агента SQL Server.

Бизнес-сценарий: клиенты могут получать «значки». Значок может быть предоставлен клиенту, вызвав веб-метод UpdateCustomerBadgeInfo на стороннем сервере.

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

"Найдите всех клиентов, которые заходили в систему более 50 раз в течение дня, дайте им значок [has-no-life] и отправьте им SMS-уведомление"

Алгоритм будет таким:

- Select all the matching accounts into a #TempTable  
 for each customer record:
 - Call UpdateCustomerBadgeInfo() method (via CLR)
 - If successfully updated badge info-> Enqueue SMS message (queue table)
 - Log successful actions (so that the record will not be picked up next time)

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

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

Вопрос в том :

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


person mcl    schedule 06.07.2013    source источник


Ответы (1)


Этот ответ действителен, только если я правильно понял ситуацию:

  • Сторонний сервер, используемый для предоставления веб-метода для обновления клиентов по одному
  • теперь они ожидают получить эту информацию из доступной вам таблицы SQL Server для INSERT/UPDATE/DELETE
  • вы можете просто запихнуть в эту таблицу свои запросы, связанные с клиентами, и через некоторое время они будут обработаны
  • когда информация, связанная с клиентом, обновляется, вам необходимо выполнить некоторые дополнительные локальные действия (поставить SMS в очередь, зарегистрировать активность)

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

  1. Выберите все совпадающие аккаунты в #TempTable

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

  2. для каждой записи клиента...

    Это должно быть единственным изменением в вашей реализации. Теперь он имеет значение - для каждой записи о клиенте, которая асинхронно обрабатывается на сторонней стороне. Конечно, ваша третья сторона должна дать вам некоторое представление о том, что они действительно обработали ваш запрос клиента, иначе вы понятия не имеете, с чем работать. Итак, когда они проверяют и обрабатывают данные, они могут предоставить, например. Обнуляемые столбцы «success_time» и «error_time», чтобы оставить вам сообщение о том, что было сделано и когда. Если есть успех, вы продолжаете обработку. Если нет, вы, вероятно, можете что-то сделать и с этим.

    Но как реагировать, когда вы получаете обратно асинхронную информацию (например, sucess_time IS NOT NULL)? Ну, есть несколько способов сделать это. Лично я стараюсь избегать триггеров, потому что они могут усложнить вам жизнь (отстойная их видимость, могут вызвать проблемы с репликацией, могут вызвать проблемы с транзакциями...) Я использую их, если мне действительно нужно первоклассное немедленная отзывчивость. Другая возможность — использование асинхронных очередей с настраиваемой активацией, что означает Service Broker. Тем не менее, многие люди избегают использования технологии SB - она ​​отличается от остальной части SQL-сервера, у нее есть свои особенности, отладка не так проста, как с простыми старыми операторами SQL и т. д. Другой возможностью может быть пакетная обработка асинхронных ответов на вашей стороне. используя задание агента. Так как вы уже используете работу, вы должны быть в порядке с ней. По сути, таблица должна действовать как точка синхронизации — вы заполняете свои запросы (INSERT), третья сторона их обрабатывает (SELECT). После обработки запросов они помечают их как таковые (UPDATE Success_time или error_time), и в конце вы обрабатываете этот ответ (SELECT) с помощью задачи задания агента. И ваша обработка включает в себя SMS-сообщение и регистрацию, возможно, даже УДАЛЕНИЕ из сторонней таблицы.

    Еще одна вещь, которую следует упомянуть, это то, что вам нужны методы синхронизации здесь. Во-первых, ничего не делайте без транзакций, иначе вы можете в конечном итоге обработать фантомные ответы и/или пропустить действительные ожидающие ответы. Во-вторых, когда вы ВЫБИРАЕТЕ ответы (строки, которые обрабатываются сторонней стороной), вы можете получить некоторое улучшение, используя подсказку READPAST (пропустить то, что заблокировано). Однако, если вам нужно обновить/удалить из вашей сторонней таблицы после обработки ответа, вы можете использовать SELECT с UPDLOCK, чтобы заблокировать другую сторону темперирования с данными между вашими INSERT и UPDATE. Или вы не используете какие-либо подсказки блокировки, если вы не совсем уверены, что происходит с рассматриваемой таблицей.

Надеюсь, поможет.

person OzrenTkalcecKrznaric    schedule 06.07.2013
comment
Озрен, спасибо за ваш быстрый ответ! Итак, в основном, если до сих пор вся работа выполнялась в одной процедуре (с циклом WHILE), теперь мне нужно разделить работу на два отдельных задания, одно для постановки в очередь запросов на информацию о значке. обновления, еще один, чтобы прочитать статус обработанных строк и отправить SMS? - person mcl; 07.07.2013
comment
Это был бы один из способов сделать это. Другой — иметь одну и ту же работу, чтобы последовательно сначала обрабатывать текущие ответы, а затем отправлять новые запросы. Таким образом, вам не нужно беспокоиться о проблемах синхронизации между вашими собственными задачами. Однако иметь две работы — это более модульный подход. - person OzrenTkalcecKrznaric; 07.07.2013