Как уведомить службу Windows (c #) об изменении таблицы БД (sql 2005)?

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

Тип постобработки также довольно тяжелый, настолько, что служба прослушивания Windows фактически передает обработку нескольким машинам. Однако эта часть приложения уже запущена и работает, полностью асинхронная, и не то, что мне нужно, чтобы помочь - я просто хотел упомянуть об этом просто потому, что это влияет на проектное решение, поскольку мы не могли просто загрузить некоторый объект CLR в БД для завершения обработки.

Итак, остается простая проблема: изменения данных в таблице, я хочу выполнить некоторую обработку в коде c # на удаленном сервере.

В настоящее время мы придумали использовать SQL-триггер, который выполняет «xp_cmdshell», чтобы запустить exe-файл, который вызывает событие, которое ожидает служба Windows. Это просто плохо.

Тем не менее, другие решения, на которые я смотрел онлайн, также выглядят довольно запутанными. Например, настройка SQLCacheDependancy также предполагает необходимость настройки компонента Service Broker. Другим возможным решением является использование триггера CLR, который может вызывать веб-сервис, но в Интернете так много предупреждений о том, что это плохой способ сделать это, особенно когда производительность критична.

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

Любая помощь будет наиболее ценной.

Резюме:

  • Необходимо реагировать на изменения данных таблицы в режиме реального времени
  • Производительность имеет решающее значение
  • Ожидается большой объем трафика
  • Опрос и запланированные задачи не вариант (или в режиме реального времени)
  • Реализация сервисного брокера слишком велика (но может быть единственным решением?)
  • Код CLR еще не исключен, но должен быть перфомантом, если предлагается
  • Слушатель / монитор может быть удаленным компьютером (вероятно, это та же физическая сеть)
13.10.2009 11:13:37
При удаленном расположении событие или опрос не будут иметь большого значения, потому что сама задержка в сети превышает несколько миллисекунд опроса. Если вы посмотрите на какую-либо архитектуру, то сами события также в какой-то момент основаны на опросе. Опрос неплох, если его тщательно продумать.
Akash Kava 13.10.2009 14:08:50
5 ОТВЕТОВ
РЕШЕНИЕ

У вас действительно не так много способов обнаружить изменения в SQL 2005. Вы уже перечислили большинство из них.

Уведомления о запросах . Это технология, которая поддерживает SqlDependency и его производные, вы можете прочитать больше подробностей в Таинственном Уведомлении . Но QN предназначен для аннулирования результатов, а не для предварительного уведомления об изменении содержимого. Вы будете знать только, что в таблице есть изменения, не зная, что изменилось. В загруженной системе это не будет работать, так как уведомления будут приходить постоянно.

Вход чтение . Это то, что использует репликация транзакций и является наименее навязчивым способом обнаружения изменений. К сожалению, доступно только для внутренних компонентов. Даже если вам удастся понять формат журнала, проблема заключается в том, что вам нужна поддержка движка, чтобы пометить журнал как «используемый», пока вы его не прочитаете, или он может быть перезаписан. Только транзакционная репликация может сделать такую ​​специальную маркировку.

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

Уровень приложений . Это лучший вариант в теории, если только нет изменений в данных, выходящих за рамки приложения, и в этом случае они рушатся. На практике всегда происходят изменения, выходящие за рамки приложения.

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

Всегда есть предложения сделать тесно связанные синхронные уведомления (через xp_cmdshell, xp_olecreate, CLR, уведомить с помощью WCF, вы называете это), но на практике все эти схемы не работают, потому что они в корне ошибочны:
- они не учитывают согласованность транзакций и откаты
- они вводят зависимости доступности (система OLTP не может
работать, пока уведомленный компонент не подключен) - они работают ужасно, поскольку каждая операция DML должна ждать завершения вызова RPC какой-либо формы

Если триггеры на самом деле не активно уведомляют слушателей, а только ставят в очередь уведомления, возникает проблема с мониторингом очереди уведомлений (когда я говорю «очередь», я имею в виду любую таблицу, которая действует как очередь). Мониторинг подразумевает получение новых записей в очереди, что означает правильное соотношение частоты проверок с нагрузкой изменений и реагирование на скачки нагрузки. Это совсем не тривиально, на самом деле это очень сложно. Однако есть один оператор на SQL-сервере, который имеет семантику, которую нужно блокировать, не вытягивая, пока не станут доступны изменения: WAITFOR (RECEIVE) . Это означает, что Service Broker. Вы упоминали SSB несколько раз в своем посте, но, по правде говоря, боитесь его развернуть из-за большого неизвестного. Но реальность такова, что она, безусловно, лучше всего подходит для задачи, которую вы описали.

Вам не нужно развертывать полную архитектуру SSB, где уведомление доставляется до удаленного сервиса (для этого все равно потребуется удаленный экземпляр SQL, даже экспресс). Все, что вам нужно сделать, это отделить момент обнаружения изменения (триггер DML) с момента доставки уведомления (после того, как изменение зафиксировано). Для этого все, что вам нужно, это локальная очередь и служба SSB. В триггере вы ОТПРАВЛЯЕТЕ уведомление об изменении в местную службу. После фиксации исходной транзакции DML сервисная процедура активирует и доставляет уведомление, например, с использованием CLR. Вы можете увидеть пример чего-то подобного в Асинхронном T-SQL .

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

Что касается средств обнаружения изменений, в SQL 2008, очевидно, добавлены новые параметры: сбор данных изменений и отслеживание изменений . Я подчеркиваю «по-видимому», так как они не являются действительно новыми технологиями. CDC использует программу чтения журнала и основана на существующих механизмах репликации транзакций. CT использует триггеры и очень похож на существующие механизмы репликации Merge. Они оба предназначены для периодически подключенных систем, которые должны синхронизироваться и, следовательно, не подходить для уведомления об изменениях в реальном времени. Они могут заполнять таблицы изменений, но перед вами стоит задача следить за изменениями в этих таблицах, что именно с того места, с которого вы начали.

20
13.10.2009 18:24:59
Большое спасибо за ваш исчерпывающий ответ. Я могу четко сказать, что вы понимаете проблемную область. Возможность использования SSB, безусловно, есть, и мне понадобится дополнительное чтение, чтобы убедиться. Еще раз спасибо
Mike Tours 15.10.2009 10:29:12
Что касается уведомлений о запросах и SqlDependency, имеет ли смысл создавать триггеры DLM для нескольких таблиц, которые бы создавали элемент в очереди при каждом изменении и зависели ли запросы SqlDependency от этой конкретной очереди?
tadalendas 15.08.2016 17:15:37

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

Почему просто создали запланированное задание, которое обрабатывает новые данные, идентифицированные столбцом флага, и обрабатывает данные большими кусками?

-1
13.10.2009 11:21:01
Спасибо за ответ. К сожалению, это решение, как я понимаю, не будет в режиме реального времени, равно как и любое решение, требующее механизма опроса.
Mike Tours 13.10.2009 11:27:49

Это можно сделать разными способами. Метод ниже прост, так как вы не хотите использовать триггеры CLR и параметры sqlcmd.

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

  • И разработать специализированный оконный сервис, который активно опрашивает таблицу отслеживания и обновляет удаленный сервис, если есть какие-либо изменения в данных, и устанавливает статус в таблице отслеживания как выполненный (чтобы он больше не выбирался).

РЕДАКТИРОВАТЬ:

Я думаю, что службы синхронизации Microsoft для ADO.Net могут работать на вас. Проверьте ссылки ниже. Это может вам помочь

1
13.10.2009 11:39:19
Спасибо за ответ. Нам действительно нравится быть уведомлением, а не использовать опрос. К сожалению, опрос был обсужден и исключен как решение, а также не в режиме реального времени. Еще раз спасибо
Mike Tours 13.10.2009 11:39:24
Еще раз спасибо. Я посмотрел на это, но, как брокер, это довольно тупой способ найти решение. По большей части это способ отслеживать все изменения, в том числе изменения схемы. В статье также упоминается, что у нее есть ряд недостатков, что, учитывая мои требования к «реальному времени» и «высокой производительности», затруднит реализацию.
Mike Tours 13.10.2009 12:53:44

Используйте типичный триггер для запуска CLR в базе данных. Этот CLR только запустит программу удаленно, используя класс Win32_Process:

http://motevich.blogspot.com/2007/11/execute-program-on-remote-computer.html

-1
13.10.2009 14:02:22
Спасибо за ответ. Это не слишком упрощает подход, при котором мы используем EXEC sp_cmdShell для запуска процесса. Ваш подход касается возможности запуска его удаленно, однако я все еще не чувствую, что этот подход является лучшим ... т.е. изменения данных, запуск триггера, запуск CLR, запуск exe (локально или удаленно), запуск события, окна Сервис слушает событие. Это кажется немного сумасшедшим, но я начинаю чувствовать, что это единственный выход. Еще раз спасибо
Mike Tours 13.10.2009 14:58:21
по крайней мере, с помощью этого метода он фактически запускает обработку на удаленной машине в режиме реального времени, он не выдает запрос, который должен ждать некоторого опроса для его обработки. Вы можете удалить clr и использовать триггер для вызова EXEC sp_cmdShell XYZ.exe, а XYZ.exe использует класс Win32_Process для удаленного запуска exec. Боюсь, что это еще не все, что вы можете сделать.
KM. 13.10.2009 15:14:21

В аналогичных обстоятельствах мы используем триггер CLR, который записывает сообщения в очередь (MSMQ). Сервис, написанный на C #, отслеживает очередь и выполняет постобработку. В нашем случае все это делается на одном и том же сервере, но вы можете отправлять эти сообщения непосредственно в удаленную очередь, на другом компьютере, полностью обходя «локальный прослушиватель».

Код, вызываемый из триггера, выглядит следующим образом:

public static void SendMsmqMessage(string queueName, string data)
{
    //Define the queue path based on the input parameter.
    string QueuePath = String.Format(".\\private$\\{0}", queueName);

    try
    {
        if (!MessageQueue.Exists(QueuePath))
            MessageQueue.Create(QueuePath);

        //Open the queue with the Send access mode
        MessageQueue MSMQueue = new MessageQueue(QueuePath, QueueAccessMode.Send);

        //Define the queue message formatting and create message
        BinaryMessageFormatter MessageFormatter = new BinaryMessageFormatter();
        Message MSMQMessage = new Message(data, MessageFormatter);

        MSMQueue.Send(MSMQMessage);
    }
    catch (Exception x)
    {
        // async logging: gotta return from the trigger ASAP
        System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(LogException), x);
    }
}
0
13.10.2009 20:49:53
Благодарю за ваш ответ. Я думаю, что у меня есть те же самые недостатки, что и при использовании Service Broker. Служба слушателей, с которой мы хотим поговорить, изначально была написана с целью, в первую очередь, избежать досады от MSMQ. Таким образом, кажется, что нужно сделать шаг назад, чтобы реализовать MSMQ, и снова подвергнуть нас первоначальной проблеме необходимости опроса очереди на наличие новых сообщений. Мы могли бы также опросить базу данных на предмет изменений? Но, если это единственный путь вперед, это одно из лучших решений, и я предпочитаю использовать xp_cmdshell наверняка.
Mike Tours 15.10.2009 10:34:20