Как уведомить службу Windows (c #) об изменении таблицы БД (sql 2005)? - PullRequest
16 голосов
/ 13 октября 2009

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

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

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

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

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

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

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

Резюме:

  • Необходимо реагировать на изменения данных таблицы в режиме реального времени
  • Производительность критична
  • Ожидается большой объем трафика
  • Опрос и запланированные задачи не являются опцией (или в режиме реального времени)
  • Реализация сервисного брокера слишком велика (но может быть единственным решением?)
  • Код CLR еще не исключен, но, если это необходимо, его необходимо выполнить,
  • Слушатель / монитор может быть удаленной машиной (вероятно, это та же физическая сеть)

Ответы [ 5 ]

19 голосов
/ 13 октября 2009

У вас действительно не так много способов обнаружить изменения в 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. Они оба предназначены для иногда подключенных систем, которые должны синхронизироваться и, следовательно, не подходить для уведомления об изменениях в реальном времени. Они могут заполнять таблицы изменений, но у вас остается задача следить за изменениями в этих таблицах, что именно с того места, с которого вы начали.

1 голос
/ 13 октября 2009

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

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

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

EDIT:

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

0 голосов
/ 14 октября 2009

В аналогичных обстоятельствах мы используем триггер 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 октября 2009

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

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

0 голосов
/ 13 октября 2009

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

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

...