Sql Server Service Broker: как структурировать разговоры для простого сценария очереди?
Я начинающий новичок Sql Server Service Broker, и я пытаюсь понять, как лучше всего установить Service Broker для (казалось бы) простого использования: я хочу создать простую рабочую очередь, где одно приложение перестает работать элементы в очередь, а отдельное приложение захватывает рабочие элементы из этой очереди и обрабатывает их. Нет необходимости, чтобы первое приложение получало сообщения статуса со второго. Я хочу, чтобы очередь работала в одном экземпляре сервера Sql.
Что меня больше смущает, так это то, как разговоры/диалоги связаны с этой ситуацией. Я знаю, что вы можете отправлять и получать сообщения только в контексте беседы/диалога, но поскольку между этими двумя приложениями нет обратной связи, я чувствую себя потерянным, когда наступает правильное время для создания новой беседы. Возможны две крайние альтернативы:
- Каждый раз, когда я запускаю рабочий элемент, я начинаю новый разговор. Таким образом, каждый разговор заканчивается тем, что содержит только одно сообщение.
- Во время развертывания я вручную создаю один сеанс бесконечной продолжительности жизни. Когда он время, чтобы enqueue рабочий элемент, я всегда отправляю его как часть этого единственного разговора.
Каковы будут последствия перехода любого из этих маршрутов?
Кроме того, в первом случае кажется, что мне нужно сделать некоторые КОНЕЧНОСТИ КОНЕЦ, чтобы сервер Sql мог очищать ресурсы внутри. Есть ли какие-либо указания относительно того, когда было бы правильным местом для их размещения? (Или, возможно, в будущем лучше будет полагаться на тайминги разговоров?)
Ответы
Ответ 1
Вы должны начать с каждого рабочего элемента в своем собственном разговоре. Производитель (инициатор) начинает диалог и отправляет сообщение, описывающее рабочий элемент, а затем совершает. Пользователь (цель) получает сообщение (или активируется), проверяет полезную нагрузку, чтобы понять детали рабочего элемента, выполняет работу, затем завершает диалог и фиксирует. Полученное сообщение EndDialog отправляется обратно в очередь обслуживания инициатора, и активированная процедура в очереди инициатора отвечает на него, завершая диалог со стороны инициатора.
Это простейшее развертывание, и его запуск и работа гарантируют, что у вас есть основа для создания основы. Не разрезайте углы и не завершайте диалог со стороны инициатора, начиная с того момента, когда производитель вставляет рабочий элемент, это fire-and-forget и имеет несколько обратных сторон.
Если у вас высокие требования к производительности (более 200 запросов в секунду), вам нужно будет начать управлять разговорами более явно. У меня есть запись в блоге повторное использование разговоров по причинам производительности. На стороне приема я рекомендую читать Написание процедур брокерских услуг.
У меня также есть запись в блоге, которая в значительной степени делает то, что вам нужно, хотя оно не расписывает рабочие элементы, а вместо этого запускает пользовательскую процедуру: Выполнение асинхронной процедуры.
Если вы решите потреблять рабочие элементы из активированного контекста, тем самым используя хорошие возможности самостоятельной балансировки активации, вам нужно понять контекст EXECUTE AS под которым происходит активация.
Ответ 2
Мне очень нравится ответ Ремуса, хотя он не особо касается того, почему вы можете предпочесть начать отдельный разговор на рабочий элемент, вместо того, чтобы помещать все рабочие элементы в один разговор. Две заметки, связанные с этим:
Во-первых, включение всех рабочих элементов в один сеанс вызовет проблемы concurrency, если у вас есть несколько потоков/процессов, обрабатывающих рабочие элементы. Процессы рабочих брокерских процессов выглядят так (в псевдокоде):
begin transaction
receive top n work items from queue
process work items
commit transaction
(Не совершая до тех пор, пока рабочие элементы не будут успешно обработаны, вы, например, убедитесь, что если ваш процесс замирает, рабочие элементы, которые он получил, но еще не обработанные, не будут удалены из очереди.)
Проблема concurrency возникла бы из-за того, что сервисный брокер запрограммирован таким образом, что каждая команда RECEIVE получает эксклюзивную блокировку чтения для всех сообщений в очереди, которые используют один и тот же сеанс (или группу разговора), как те, что были RECEIVEd. Эта блокировка сохраняется до тех пор, пока транзакция не будет выполнена. (См. Блокировки группы бесед.) Поэтому, если все рабочие элементы в очереди находятся в одном разговоре, тогда, когда один рабочий процесс находится в процессе рабочие элементы ", никакие другие рабочие процессы не могут выполнять какую-либо работу.
Вторая проблема с размещением большого количества элементов в одном разговоре заключается в том, что он увеличивает количество рабочих элементов, которые вы можете потерять или которые должны быть обработаны в определенных условиях ошибки. Чтобы правильно описать это, я откладываю на Ремуса; см. его Recycling Conversations, особенно часть, в которой говорится, что "повторное использование одного диалога для отправки всех ваших сообщений [...] похоже на то, чтобы положить все ваши яйца в одной корзине". Возможно, вы сможете восстановить некоторые из этих ситуаций с ошибками, но, вероятно, это приведет к большей сложности вашего кода.
Есть, вероятно, еще несколько аргументов против использования единственного разговора для всех рабочих элементов, но я не знаком с ними.
Это не означает, что правильным решением всегда является отдельный разговор для каждого рабочего элемента. Однако, прочитав сообщения Ремуса, его совет кажется звуковым; начните с одного рабочего элемента для разговора, а затем добавьте сложность, если потребуется. (Но, вероятно, ни в коем случае не следует доводить до конца все сообщения в одном разговоре.)