Мы пытаемся заставить Service Broker работать в нашей среде, чтобы решить бизнес-задачу. Я не знаю, подходит ли заголовок сообщения, но мой вопрос ниже. Но, возможно, это не очень хороший вопрос, поэтому после этого мы и делаем то, почему я думаю, что это правильный вопрос.
Сколько сообщений нужно отправить в разговоре до его завершения?
Мы хотим использовать компонент Service Broker для асинхронного обновления таблицы результатов. Таблица результатов сглаживается и быстро. У нас есть триггеры на базовых таблицах, которые отправляют сообщение со своей таблицей и первичным ключом. У нас есть три очереди:
- Низкая задержка - на обработку уходит 15 секунд. Он обрабатывает элементы, которые меняются в зависимости от конкретного элемента.
- Массовая очередь - задача в 5 минут для обработки. Он обрабатывает, когда что-то меняется, затрагивая многие сотни (или тысячи) предметов. Он разбивает список элементов, которые были затронуты, и передает их в отложенную очередь с низкой задержкой
- Отложенная низкая задержка - задача - 30 минут для обработки. Это обрабатывает элементы, но только из основной очереди.
В основном, если информация клиента обновляется; это влияет на многие продукты, поэтому отправляется в массовую очередь для более медленной обработки. Однако, если продукт обновляется, он отправляется в очередь с низкой задержкой.
Мы повторно используем разговоры, похожие на блог Ремуса Русану http://rusanu.com/2007/04/25/reusing-conversations/ , за исключением того, что мы делаем это на основе модуля первичного ключа. У этого есть побочное преимущество помощи в дедупликации первичных ключей.
Таким образом, мы повторно используем разговоры и следуем нашим правилам. С двумя потоками мне удалось прожечь 125 сообщений в секунду (искусственное отбрасывание нескольких тысяч сообщений), что более чем в состоянии поддерживать производительность (оценка 15 сообщений в секунду).
Однако проблема, с которой мы сталкиваемся, заключается в том, что через некоторое время, ~ 4 часа или 120 КБ сообщений, мы начали видеть блоки и высокий уровень конкуренции в sysdesend и таблице очередей. Блокировки LCK_M_U и KEY блокировки. Иногда hobt преобразуется в sysdesend, а иногда в конкретную таблицу очередей (queue_).
У нас есть процесс, который завершает разговоры через 24 часа или 30 минут бездействия, поэтому мы могли бы просто увеличить время перед циклом разговоров.
Мы используем SQL 2016 Enterprise (13.0.4001.0)
- Триггерные огни (отправка с низкой задержкой или массовым)
- Посмотрите или создайте ручку разговора.
- Отправить сообщение
- Процедура активации очереди
- Обновить таблицу результатов
Процесс очистки запускается каждые 10 минут, чтобы увидеть, нет ли каких-либо пустых разговоров. если он находит их более трех раз подряд, он помечает его как неактивный и завершает разговоры.
Пожалуйста, дайте мне знать, если есть какие-либо дополнительные детали, которые могут быть полезны. У меня нет большого опыта работы с Service Broker, поэтому я не знаю, являются ли наши сообщения в секунду низкими, высокими или безразличными.
ОБНОВИТЬ
Поэтому мы попробовали еще раз сегодня и столкнулись с той же проблемой. Мы изменили продолжительность разговора до 2 часов, и это не имело никакого эффекта. Итак, мы реализовали трюк 150; который имел ту же проблему.
Тонны ожидания на отправку разговора, ожидания на sysdesend. У кого-нибудь есть еще идеи?
ОБНОВЛЕНИЕ 2
Сегодня мы продлили тест дольше и в течение одного из 17-минутных тестовых периодов мы обработали 41 тыс. Сообщений на 4 ручках разговора. Мы могли идти в ногу, кроме как к концу, когда блокировки на sysdesend и таблице очереди стали слишком большими, и мы начали дрейфовать позади, прежде чем остановить его. Кажется, у нас нет проблем с обработкой сообщений, без поступления вещей в очередь, мы можем их обработать и обработать как минимум в 5 раз быстрее. Наша скорость кажется ограниченной из-за добавления сообщений.
В последующем тесте мы удалили один из триггеров, на которые приходилось 80% сообщений. Даже с такой значительно сниженной нагрузкой мы начали видеть то же самое ожидание.
ОБНОВЛЕНИЕ 3
Спасибо, Ремус за твой совет (и спасибо за публикацию таких замечательных статей в блоге на эту тему, они сыграли важную роль в достижении этой точки).
Мы повторили это сегодня и сделали лучше (так как мы шли дольше, прежде чем увидели ожидания, и еще дольше, пока это не подорвало нас). Итак, подробности.
Мы изменили: * Увеличено количество поддерживаемых разговоров в потоке с 1: 1 до 2: 1. В основном у нас было 8 дескрипторов разговоров для 4 потоков.
- консолидировать массовую очередь (потому что одно входящее сообщение может означать сотни исходящих сообщений) для консолидации в меньшее количество более крупных сообщений.
Примечания об этой попытке:
отключение процедуры активации целевой очереди. никаких изменений в блокировке (мы подождали 5 минут), и сообщения были отправлены на sys.transmission_queues.
мониторинг sys.conversation_endpoints. Это число очень быстро выросло с 0 до 13 000, а затем более медленно росло в течение дня и заканчивалось около 25 000 через ~ 5 часов. Блокировка не начиналась, пока не достигла 16K +/-
Я вошел в ЦАП и выполнил команды DBREINDEX для очередей, хотя из запроса записи о призраках никогда не превышали 200 или около того, пока не началась очистка, и сбросили счетчик до 0.
sysdesend и sysdercv имели одинаковые значения 24 932, когда я закончил тест.
мы обработали ~ 310K сообщений за 5 часов.
Мы ушли так долго, прежде чем все развалилось, что я действительно думал, что мы сделаем это на этот раз. Завтра мы попытаемся заставить сообщения пройти по проводам.
источник
we started seeing blocks and high contention on sysdesend and the queue table.
-> Какой тип ожидания -PAGELATCH_EX/SH and WRITELOG
? Вы использовали 150 трюк ? Если ваши системные разногласия являются системными таблицами, трюк 150 будет очень полезен.sys.conversation_endpoints
во время теста (постоянное или увеличивается, и насколько оно велико, когда происходит блокировка). 2) Когда происходит блокировка, делает ли отключение целевой очереди разницу в блокировке SEND (отключение очереди должно направлять SEND к sys.transmission_queue). и 3)ALTER QUEUE ... REBUILD
когда начинается блокировка?Ответы:
Я знаю, что отвечать на свой вопрос - это дурной тон, но я хотел бы закрыть это для всех, кому было интересно. Нам наконец удалось решить проблему или, по крайней мере, решить ее достаточно, чтобы удовлетворить наши требования. Я хочу поблагодарить всех, кто предоставил комментарии; Ремус Русану и Кин, как они были очень полезны.
Наша база данных довольно занята и находится в режиме RCSI. У нас есть несколько (тысячи) мобильных устройств, которые обновляют информацию о своем местоположении каждые 45 секунд. Благодаря этим обновлениям несколько таблиц обновляют свою информацию (плохой дизайн, поскольку я бы ограничил изменчивую информацию одной таблицей, а затем соединил ее для получения результатов). Эти таблицы - те же самые, для которых мы пытались генерировать отчетную информацию асинхронно, вместо того, чтобы конечные пользователи обращались непосредственно к базовым таблицам.
Изначально у нас были триггеры, которые делали курсор на измененные записи в каждом операторе update / insert (в большинстве случаев это была одна строка) и отправляли каждый первичный ключ в сообщении сервисному брокеру. Внутри сервисного брокера, особенно объемной очереди, были дополнительные курсоры, которые выполняли процедуру upsert для отчета (одно выполнение на первичный ключ).
Что наконец заставило нас работать:
Мы удалили курсоры и решили отправлять сообщения большего размера. По-прежнему одно сообщение на пользовательскую транзакцию на таблицу, но теперь мы отправляем сообщения с более чем одним первичным ключом.
Массовый процессор также отправляет несколько ключей для каждого сообщения, что сокращает количество отправленных сообщений, когда оно перетасовывает сообщения в другую очередь, в зависимости от ситуации.
В самой изменчивой таблице (нашей таблице данных мобильных устройств) были удалены триггеры. Мы обновили процедуру upsert для включения соответствующих внешних ключей, и теперь мы просто присоединяемся к этой таблице при получении результатов для пользователей. Эта таблица легко дала 80% сообщений, которые мы должны были обработать за день.
Мы обрабатываем ~ 1 млн сообщений в день (без таблицы Mobile), и подавляющее большинство (99% +) наших сообщений обрабатываются в рамках нашей цели. У нас все еще есть случайные выбросы, но учитывая редкий характер того, что он считается приемлемым.
Способствующие факторы:
Я обнаружил ошибку в упомянутой ранее процедуре очистки разговора, которая на самом деле не очищала разговоры должным образом и не заканчивала их преждевременно. Это теперь привело к тому, что число наших системных запросов никогда не превышало нескольких тысяч (большая часть из которых получается при использовании трюка 150).
Кажется, что курсоры в триггерах удерживают больше блокировок, чем ожидалось (даже со статическим, forward_only). удаление этих, кажется, сделало замки, которые мы видим в SEND CONVERSATION, более преходящими по природе (или, по крайней мере, времена, которые мы видим, намного ниже).
По сути, мы работали над двумя решениями (серверная часть решения Service Broker (для тестирования под рабочей нагрузкой)) и текущим решением (ужасный запрос, охватывающий множество таблиц).
В качестве дополнительного преимущества это позволило выявить проблему очистки Ghost Record Cleanup, и, хотя ее не было в таблицах Service Broker (в системе или в очереди), в нашей системе она широко распространена, и симптомы действительно хорошо сочетаются с нашей «неясной причиной» проблемы, которые мы испытываем время от времени. По этому вопросу продолжается расследование, мы пытаемся найти таблицы, которые способствуют этому, и мы, вероятно, просто будем регулярно перестраивать их индексы.
Спасибо еще раз.
источник