Как уведомить службу windows (c#) об изменении таблицы БД(sql 2005)?
У меня есть таблица с большой нагрузкой(много вставок/обновлений/удалений) в базе данных SQL2005. Я хотел бы сделать некоторую пост-обработку для всех этих изменений как можно ближе к реальному времени(асинхронно, чтобы никоим образом не блокировать таблицу). Я просмотрел несколько возможных решений, но просто не могу найти одно аккуратное решение, которое кажется правильным.
вид пост-обработки также довольно тяжелый, так что служба прослушивателя windows фактически собирается проходит обработку на нескольких машинах. Однако эта часть приложения уже запущена и работает, полностью асинхронна, а не то, что мне нужна помощь - я просто хотел упомянуть об этом просто потому, что это влияет на проектное решение в том, что мы не могли просто загрузить некоторый объект CLR в БД для завершения обработки.
Итак, остается простая проблема: данные меняются в таблице, я хочу сделать некоторую обработку в коде C# на удаленном сервере.
В настоящее время мы придумали использовать триггер sql, который выполняет "xp_cmdshell", чтобы lauch exe, который вызывает событие, которое прослушивает служба windows. Это просто неприятно.
однако другие решения, которые я смотрел в интернете, тоже кажутся довольно запутанными. Например, настройка SQLCacheDependancy также включает в себя настройку Service broker. Другим возможным решением является использование триггера CLR, который может вызывать веб-сервис, но у этого есть так много предупреждений в интернете о том, что это плохой способ занимайтесь этим, особенно когда производительность критична.
Idealy мы бы не depnd на изменения таблицы, но предпочли бы перехватить вызов внутри нашего приложения и уведомить службу оттуда, к сожалению, хотя у нас есть некоторые устаревшие приложения, вносящие изменения в данные тоже, и мониторинг таблицы является единственным централизованным местом на данный момент.
любая помощь была бы весьма признательна.
резюме:
- потребность ответить таблице изменения данных в режиме реального времени
- производительность
- ожидается большой объем трафика
- опрос и запланированные задачи не являются опцией (или в режиме реального времени)
- реализация Service broker слишком велика (но может быть только решением?)
- код CLR еще не исключен, но должен быть perfomant, если предложено
- прослушиватель / монитор может быть удаленной машиной (вероятно, той же физической сетью)
5 ответов
У вас действительно не так много способов обнаружения изменений в SQL 2005. Вы уже перечислили большинство из них.
Уведомления О Запросах. Это технология, которая питает SqlDependency и его производные, вы можете прочитать более подробную информацию о Таинственное Уведомление. Но QN предназначен для недействительным результаты, а не про-активно уведомлять об изменении контента. Вы будете знать только, что таблица имеет изменения, не зная, что изменилось. На занятом система это не сработает,так как уведомления будут приходить довольно часто.
журнал читать. Это то, что использует репликация транзакций и является наименее интрузивным способом обнаружения изменений. К сожалению, доступен только для внутренних компонентов. Даже если вам удастся понять формат журнала, проблема в том, что вам нужна поддержка движка, чтобы пометить журнал как "используемый", пока вы его не прочитаете, или он может быть перезаписан. Это может сделать только репликация транзакций рода специальная маркировка.
сравнение данных. Для обнаружения изменений используйте столбцы timestamp. Также тянуть на основе, довольно intrussive и имеет проблемы с обнаружением удалений.
Слой Приложения. Это лучший вариант в теории, если нет изменений, происходящих с данными вне сферы применения, и в этом случае он рушится. На практике есть всегда изменения, происходящие за пределами приложение.
триггеры. В конечном счете, это единственный приемлемый вариант. Все механизмы изменения, основанные на триггерах, работают одинаково: они выстраивают уведомление об изменении в очередь к компоненту, который отслеживает очередь.
всегда есть предложения сделать тесно связанное Синхронное уведомление (через xp_cmdshell, xp_olecreate, CLR, notify с WCF, вы называете это), но все эти схемы терпят неудачу на практике, потому что они принципиально ошибочны:
- они не учитывайте последовательность транзакций и откаты
- они вводят зависимости доступности (система OLTP не может продолжить, если уведомленный компонент не находится в сети)
- они выполняют ужасно, так как каждая операция DML должна ждать вызова RPC какой-либо формы для завершения
Если триггеры фактически не активно уведомляют слушателей, а только выстраивают уведомления в очередь, возникает проблема в мониторинге очереди уведомлений (когда я говорю "очередь", я имею в виду таблица, которая действует как очередь). Мониторинг подразумевает вытягивание новых записей в очереди, что означает правильное балансирование частоты проверок с нагрузкой изменений и реагирование на пиковые нагрузки. Это совсем не тривиально, на самом деле очень сложно. Однако в SQL server Есть одна инструкция, которая имеет семантику для блокировки, без вытягивания, пока изменения не станут доступными:WAITFOR (ПРИЕМ). Это означает Service Broker. Вы несколько раз упоминали SSB в своем посте, но вы боятся развернуть его из-за большого неизвестного. Но реальность такова, что это, безусловно, лучше всего подходит для задачи, которую вы описали.
вам не нужно развертывать полную архитектуру SSB, где notificaition доставляется полностью в удаленную службу (для этого все равно потребуется удаленный экземпляр SQL, даже Экспресс-экземпляр). Все, что вам нужно сделать, это отделить момент обнаружения изменения (триггер DML) от момента уведомления доставляется (после смены верен). Для этого все, что вам нужно, это локальная очередь SSB и обслуживание. В триггере ты отправить уведомление об изменении в местную службу. После фиксации исходной транзакции DML процедура обслуживания активация и доставляет уведомление, используя CLR, например. Вы можете увидеть пример чего-то похожего на это в асинхронный T-SQL.
Если вы идете по этому пути, есть некоторые трюки, которые вы будете нужно научиться добиваться высокого troughput и вы должны понимать концепцию заказанной доставки сообщений в SSB. Я рекомендую вам прочитать эти ссылки:
О средствах обнаружения изменений, SQL 2008 видимо добавлены новые параметры: изменить сбор данных и Изменение Отслеживания. Я подчеркиваю "по-видимому", поскольку на самом деле это не новые технологии. CDC использует средство чтения журналов и основан на существующих механизмах репликации транзакций. CT использует триггеры и очень похож на существующие механизмы репликации слиянием. Они оба предназначены для иногда связаны системы, которые необходимо синхронизировать и, следовательно, не appropiate для уведомления об изменении в режиме реального времени. Они могут заполнять таблицы изменений, но вы остаетесь с задачей для мониторинга эти таблицы для изменений, которые именно с того места, где вы начали.
Это можно сделать многими способами. ниже метод прост, так как вы не хотите использовать триггеры CLR и параметры sqlcmd.
вместо использования триггеров CLR вы можете создать обычный триггер вставки, который обновляет выделенную таблицу отслеживания на каждой вставке.
и разработать специальную службу окон, которая активно опрашивает таблицу отслеживания и обновляет удаленную службу, если есть какие-либо изменения в данных и установить статус в отслеживание таблицы сделано (так что она не будет выбрана снова)..
EDIT:
Я думаю, что службы Microsoft sync services для ADO.Net могу работать на тебя. Ознакомьтесь с приведенными ниже ссылками. Это может помочь вам
в подобных обстоятельствах мы используем триггер 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);
}
}
Так как вы сказали, что на этой таблице много вставок, пакетная обработка может поместиться лучше.
Почему просто создали запланированное задание, которое обрабатывает новые данные, идентифицированные столбцом флага, и обрабатывает данные большими кусками?
используйте типичный триггер для запуска среды CLR в базе данных. Эта среда CLR запускает программу удаленно только с помощью класса Win32_Process:
http://motevich.blogspot.com/2007/11/execute-program-on-remote-computer.html