2009-10-13 21 views
14

Tengo una tabla con una carga pesada (muchas inserciones/actualizaciones/eliminaciones) en una base de datos SQL2005. Me gustaría hacer un procesamiento posterior para todos estos cambios lo más cerca posible al tiempo real (de forma asíncrona para no bloquear la tabla de ninguna manera). He buscado una serie de posibles soluciones, pero parece que no puedo encontrar esa solución que se sienta bien.Cómo notificar a un servicio de Windows (C#) de un cambio de tabla DB (sql 2005)?

El tipo de procesamiento posterior también es bastante pesado, tanto que el servicio de escucha de Windows va a pasar el procesamiento a varias máquinas. Sin embargo, esta parte de la aplicación ya está en funcionamiento, completamente asíncrona, y no es algo con lo que necesito ayuda. Solo quería mencionar esto simplemente porque afecta la decisión de diseño en el sentido de que no podríamos simplemente cargar un objeto CLR en el DB para completar el procesamiento.

Por lo tanto, el problema simple sigue siendo: los cambios de datos en una tabla, quiero hacer algo de procesamiento en código C# en un servidor remoto.

En la actualidad, hemos encontrado el uso de un disparador sql, que ejecuta "xp_cmdshell" para crear un exe que genera un evento que el servicio de Windows está escuchando. Esto solo se siente mal.

Sin embargo, otras soluciones que he visto en línea también se sienten complicadas. Por ejemplo, configurar SQLCacheDependancy también implica tener que configurar Service Broker. Otra posible solución es usar un activador CLR, que puede llamar a un servicio web, pero esto tiene tantas advertencias en línea sobre que es una mala forma de hacerlo, especialmente cuando el rendimiento es crítico.

Idealmente no nos detendríamos en los cambios de la tabla, sino que preferiríamos interceptar la llamada dentro de nuestra aplicación y notificar al servicio desde allí, lamentablemente tenemos algunas aplicaciones heredadas que también realizan cambios en los datos, y la supervisión de la tabla es único lugar centralizado en este momento.

Cualquier ayuda sería muy apreciada.

Resumen:

  • necesidad de responder a los cambios de datos de tabla en tiempo real
  • rendimiento es crítico
  • se espera
  • alto volumen de tráfico
  • de sondeo y las tareas programadas no son una opción (o tiempo real)
  • Implementación de un agente de servicio demasiado grande (¿pero podría ser la única solución?)
  • Código CLR aún no descartado , pero hay que perfomant si sugirió
  • Listener/monitor puede ser máquina remota (probabilidades de ser misma red phyisical)
+0

En caso ubicación remota o de votación no hará gran diferencia, porque el tiempo de retardo de red en sí es superior a unos pocos milisegundos de votación. Si observas cualquier arquitectura, los eventos también se basan en encuestas en algún punto. La votación no es mala si está cuidadosamente diseñada. –

Respuesta

18

Usted realmente no tiene que muchas maneras para detectar cambios en SQL 2005. Ya enumeró la mayoría de ellos.

Query Notifications. Esta es la tecnología que impulsa SqlDependency y sus derivados, puede leer más detalles en The Mysterious Notification. Pero QN está diseñado para invalidar los resultados de, no para notificar proactivamente el cambio de contenido. Solo sabrá que la tabla tiene cambios, sin saber qué cambió. En un sistema ocupado, esto no funcionará, ya que las notificaciones llegarán casi continuamente.

Lectura de registro. Esto es lo que usa la replicación transaccional y es la forma menos intrusiva de detectar cambios. Lamentablemente, solo está disponible para componentes internos. Incluso si logra comprender el formato de registro, el problema es que necesita soporte del motor para marcar el registro como 'en uso' hasta que lo lea, o puede sobrescribirse. Solo la replicación transaccional puede hacer este tipo de marcado especial.

Comparación de datos. Confíe en las columnas de marcas de tiempo para detectar cambios. También está basado en el tirón, bastante intrusivo y tiene problemas para detectar eliminaciones.

Capa de aplicación. Esta es la mejor opción en teoría, a menos que ocurran cambios en los datos fuera del alcance de la aplicación, en cuyo caso se desmorona. En la práctica, hay siempre cambios que ocurren fuera del alcance de la aplicación.

Disparadores. En definitiva, esta es la única opción viable. Todos los mecanismos de cambio basados ​​en desencadenantes funcionan de la misma manera, ponen en cola la notificación de cambio a un componente que supervisa la cola.

Siempre hay sugerencias que hacer una notificación fuertemente acoplado, sincrónica (a través de xp_cmdshell, xp_olecreate, CLR, notifique con WCF, lo que sea), pero todos estos sistemas fallan en la práctica, ya que son fundamentalmente defectuoso:
- se no tienen en cuenta la coherencia y la reversión de transacciones
- introducen dependencias de disponibilidad (el sistema OLTP no puede continuar a menos que el componente notificado esté en línea)
- funcionan de forma horrible ya que cada operación DML tiene que esperar a que se complete una llamada RPC

Si los activadores no notifican activamente a los oyentes, sino Para poner en cola las notificaciones, hay un problema al monitorear la cola de notificaciones (cuando digo 'cola', me refiero a cualquier tabla que actúa como cola). El monitoreo implica atraer nuevas entradas en la cola, lo que significa equilibrar la frecuencia de las comprobaciones correctamente con la carga de cambios y reaccionar a los picos de carga. Esto no es trivial en absoluto, en realidad es muy difícil. Sin embargo, hay una instrucción en el servidor SQL que tiene la semántica para bloquear, sin tirar, hasta que los cambios estén disponibles: WAITFOR(RECEIVE). Eso significa Service Broker. Usted mencionó SSB varias veces en su publicación, pero lo está haciendo, con miedo de desplegarlo debido a la gran incógnita. Pero la realidad es que es, de lejos, la mejor opción para la tarea que describiste.

No tiene que implementar una arquitectura de SSB completa, donde la notificación se entrega hasta el servicio remoto (que requeriría una instancia remota de SQL de todos modos, incluso una Express). Todo lo que necesita para ser cómplice es desacoplar el momento en que se detecta el cambio (el desencadenante DML) desde el momento en que se entrega la notificación (después de que se haya realizado el cambio). Para esto, todo lo que necesita es una cola y un servicio de SSB local. En el desencadenador, SEND una notificación de cambio al servicio local. Después de que la transacción DML original se confirma, el procedimiento de servicio activates y entrega la notificación, usando CLR, por ejemplo. Puede ver un ejemplo de algo similar a esto en Asynchronous T-SQL.

Si va por ese camino, hay algunos trucos que deberá aprender para lograr un alto rendimiento y debe comprender el concepto de entrega ordenada de mensajes en SSB. Yo le recomendaría que lea estos enlaces:

Sobre los medios para detectar cambios, SQL 2008 parecer añade nuevas opciones: Change Data Capture and Change Tracking. Enfatizo 'aparentemente', ya que no son realmente nuevas tecnologías. CDC utiliza el lector de registro y se basa en los mecanismos de replicación transaccional existentes. CT utiliza desencadenantes y es muy similar a los mecanismos de replicación Merge existentes. Ambos están destinados a conectados ocasionalmente a los sistemas que deben sincronizarse y, por lo tanto, no son apropiados para la notificación de cambio en tiempo real. Pueden completar las tablas de cambios, pero se le deja la tarea de supervisar estas tablas en busca de cambios, que es exactamente desde donde comenzó.

+0

Muchas gracias por su respuesta integral. Puedo decirle claramente que comprende el dominio del problema. La posibilidad de usar SSB está ciertamente allí, y tendré que tomar la lectura adicional para estar seguro. Gracias de nuevo –

+0

En cuanto a Query Notifications y SqlDependency, ¿tendría sentido crear triggers DLM en varias tablas, lo que crearía un elemento en una cola en cada cambio y la consulta SqlDependency dependerá de una cola en particular? – tadalendas

-1

ya que dijo hay muchas inserciones que se ejecutan en esa mesa, un procesamiento por lotes podía encajar mejor.

¿Por qué simplemente creó un trabajo programado, que maneja los datos nuevos identificados por una columna de indicador y procesa los datos en trozos grandes?

+0

Gracias por la respuesta. Lamentablemente, esta solución, tal como la entiendo, no sería en tiempo real, ni tampoco una solución que requiriera un mecanismo de sondeo. –

1

Esto se puede hacer de muchas maneras. El siguiente método es simple, ya que no desea utilizar los desencadenadores CLR y las opciones sqlcmd.

  • En lugar de utilizar activadores CLR, puede crear el activador de inserción normal que actualiza la tabla de seguimiento dedicada en cada inserción.

  • Desarrolle un servicio de ventana dedicado que sondee activamente la tabla de seguimiento y actualice el servicio remoto si hay algún cambio en los datos y establezca el estado en la tabla de seguimiento (para que no vuelva a elegirse) ..

EDIT:

Creo que los servicios de sincronización de Microsoft para ADO.Net pueden trabajar para usted. Mira los enlaces a continuación. Puede ayudarle a

+0

Gracias por la respuesta. Realmente nos gusta que sea una notificación en lugar de usar encuestas. El sondeo ha sido discutido y descartado como una solución desafortunadamente y tampoco es en tiempo real. Gracias de nuevo –

+0

@Mike, echa un vistazo a mi edición ... que puede ser útil. – RameshVel

+0

Gracias de nuevo. Eché un vistazo a esto, pero como agente de servicios es una forma bastante obtusa de intentar encontrar una solución. En su mayor parte, es una forma de supervisar todos los cambios que incluyen los cambios de esquema. El artículo también menciona que tiene una serie de desventajas, que teniendo en cuenta mis requisitos de "tiempo real" y "alto rendimiento" van a dificultar su implementación. –

-1

uso típico el gatillo para disparar un CLR en la base de datos. Este CLR sólo se iniciará un programa de forma remota utilizando la clase Win32_Process:

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

+0

Gracias por la respuesta. Esto no es demasiado desalentador para el enfoque mediante el cual usamos EXEC sp_cmdShell para iniciar un proceso. Su enfoque aborda la posibilidad de iniciarlo de forma remota, sin embargo, todavía no creo que el enfoque sea el mejor ... es decir, cambios de datos, desencadenador de incendios, ejecutar CLR, iniciar exe (local o remoto), desencadenar un evento, ventanas el servicio escucha el evento Parece un poco enojado, pero estoy empezando a sentir que es la única forma. Gracias de nuevo –

+0

al menos con este método, en realidad inicia el procesamiento en la máquina remota en tiempo real, no emite una solicitud que tiene que esperar a que algún sondeo lo procese. Puede eliminar el clr y usar un desencadenador para llamar a EXEC sp_cmdShell XYZ.exe y XYZ.exe usa la clase Win32_Process para ejecutar remotamente el ejecutor. Me temo que no hay mucho más que puedas hacer. –

0

En circunstancias similares, estamos utilizando el disparador CLR que está escribiendo mensajes en la cola (MSMQ). El servicio escrito en C# está monitoreando la cola y haciendo el post-procesamiento. En nuestro caso, todo se hace en el mismo servidor, pero puede enviar esos mensajes directamente a la cola remota, en una máquina diferente, evitando por completo el "oyente local".

El código de llamada del gatillo se ve así:

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

Gracias por su respuesta. Creo que esto tiene el mismo tipo de drawbacs para mí que usar Service Broker. El servicio de escucha con el que queremos hablar fue originalmente escrito con el propósito de salir del MSMQ desde el principio. Por lo tanto, parece un paso atrás tener que implementar MSMQ, y nuevamente nos expone al problema original de tener que sondear los nuevos mensajes en la cola. ¿Podríamos también sondear la base de datos en busca de cambios? Pero, si este es el único camino a seguir, es una de las soluciones más ordenadas y prefiero usar xp_cmdshell con seguridad. –

Cuestiones relacionadas