Service Broker: ¿conversación de por vida?


9

Estamos tratando de hacer que Service Broker trabaje en nuestro entorno para resolver un caso de negocios. No sé si el título del mensaje es bueno, pero mi pregunta está a continuación. Pero puede que no sea una buena pregunta, así que después de eso es lo que estamos haciendo y por qué creo que es la pregunta correcta.

¿Cuántos mensajes se deben enviar en una conversación antes de finalizarla?

Queremos usar Service Broker para actualizar asincrónicamente una tabla de resultados. La tabla de resultados es aplanada y rápida. Tenemos activadores en las tablas base que envían un mensaje con su tabla y clave principal. Tenemos tres colas:

  • Baja latencia: el objetivo es procesar 15 segundos. Maneja elementos que cambian en relación con un elemento específico.
  • Cola masiva: el objetivo es procesar 5 minutos. Se maneja cuando algo cambia que afecta a muchos cientos (o miles) de elementos. Desglosa la lista de elementos afectados y los alimenta a la Cola de baja latencia diferida
  • Baja latencia diferida: el objetivo es procesar 30 minutos. Esto procesa elementos pero solo desde la cola masiva.

Básicamente, si la información de un cliente se actualiza; eso afecta a muchos productos, por lo que se envía a la cola masiva para un procesamiento más lento. Sin embargo, si un producto se actualiza, se envía a la cola de baja latencia.

Reutilizamos conversaciones similares al blog de Remus Rusanu http://rusanu.com/2007/04/25/reusing-conversations/ , con la excepción de que lo hacemos en función del módulo de la clave primaria. Esto tiene el beneficio secundario de ayudar en la desduplicación de las claves primarias.

Por lo tanto, estamos reutilizando conversaciones y estamos dentro de nuestras pautas. Con dos hilos, pude grabar 125 mensajes / segundo (caída artificial de varios miles de mensajes), que es más que capaz de mantenerse al día con la producción (est. 15 mensajes / segundo).

Sin embargo, el problema que estamos experimentando es que después de un período de tiempo, ~ 4 horas o mensajes de 120K, comenzamos a ver bloques y una alta contención en sysdesend y la tabla de colas. Los bloqueos son LCK_M_U y son bloqueos CLAVE. A veces, la resolución resuelve enviar sysdesend y otras veces a la tabla de cola específica (queue_).

Tenemos un proceso en marcha que finalizará las conversaciones después de 24 horas o 30 minutos de inactividad, por lo que podríamos aumentar el tiempo antes de pasar de una conversación a otra.

Estamos utilizando SQL 2016 Enterprise (13.0.4001.0)

  1. Disparar incendios (enviar a baja latencia o en masa)
  2. Busque o cree un identificador de conversación.
  3. enviar mensaje
  4. Procedimiento activado en cola
  5. Actualizar tabla de resultados

El proceso de limpieza se ejecuta cada 10 minutos para ver si hay conversaciones inactivas. Si los encuentra más de tres veces seguidas, lo marca como inactivo y finaliza las conversaciones.

Avíseme si hay algún detalle adicional que pueda ser beneficioso. No tengo mucha experiencia con Service Broker, así que no sé si nuestros mensajes / segundo son bajos, altos o indiferentes.

ACTUALIZAR

Así que lo intentamos nuevamente hoy y encontramos el mismo problema. Cambiamos la duración de la conversación a 2 horas y eso no tuvo ningún efecto. Entonces implementamos el truco 150; que tenía el mismo problema

Toneladas de espera en ENVIAR CONVERSACIÓN, esperando en sysdesend. ¿Alguien tiene alguna idea más?

ACTUALIZACIÓN 2

Corrimos la prueba durante más tiempo hoy y durante uno de los períodos de muestra de 17 minutos, procesamos 41K mensajes en 4 identificadores de conversación. Pudimos mantener el ritmo, excepto hacia el final cuando las cerraduras en el sysdesend y la mesa de la cola se volvieron demasiado y comenzamos a retroceder antes de detenerlo. Parece que no tenemos problemas para procesar mensajes, sin elementos que entran en la cola, podemos sacarlos y procesarlos al menos 5 veces más rápido. Nuestra velocidad parece estar limitada en función de agregar mensajes.

En una prueba posterior, eliminamos uno de los desencadenantes que representaban el 80% de los mensajes. Incluso con esta carga muy reducida, comenzamos a ver las mismas esperas.

ACTUALIZACIÓN 3

Gracias, Remus por tu consejo (y gracias por publicar tan excelentes artículos de blog sobre el tema, fueron fundamentales para llegar a este punto).

Lo volvimos a ejecutar hoy y lo hicimos mejor (ya que pasamos más tiempo antes de ver las esperas y aún más antes de que nos paralizara). Entonces, los detalles.

Cambiamos: * Aumentamos el número de conversaciones mantenidas por hilo de 1: 1 a 2: 1. Básicamente, teníamos 8 identificadores de conversación para 4 hilos.

  • consolidó la cola masiva (porque un mensaje entrante podría significar cientos de mensajes salientes) para consolidar en menos mensajes más grandes.

Notas sobre este intento:

  • deshabilitando el procedimiento de activación de la cola objetivo. no hubo cambios en el bloqueo (esperamos 5 minutos) y los mensajes se enviaron a sys.transmission_queues.

  • Supervisión de sys.conversation_endpoints. Este número pasó de 0 a 13K muy rápidamente, y luego aumentó más lentamente durante todo el día y terminó alrededor de 25K después de ~ 5 horas. El bloqueo no comenzó a ocurrir hasta que alcanzó 16K +/-

  • Entré en el DAC y ejecuté los comandos DBREINDEX para las colas, aunque a partir de una consulta, los registros fantasma nunca superaron los 200 antes de que apareciera la limpieza y reduje el recuento a 0.

  • sysdesend y sysdercv tenían conteos idénticos de 24,932 cuando terminé la prueba.

  • procesamos ~ 310K mensajes en 5 horas.

Pasamos tanto tiempo antes de que las cosas se derrumbaran que realmente pensé que lo haríamos esta vez. Mañana intentaremos obligar a los mensajes a pasar por el cable.


1
we started seeing blocks and high contention on sysdesend and the queue table.-> ¿Cuál es el tipo de espera - PAGELATCH_EX/SH and WRITELOG? ¿Has usado el truco 150 ? Si las tablas del sistema son su punto de contención, el truco de 150 será muy útil.
Kin Shah

@kin, actualicé la pregunta, pero los tipos de bloqueo son LCK_M_U o LCK_M_X. Había leído sobre el truco 150, pero esperaba que fuera innecesario en 2016 (ya que también habían resuelto el problema de la fuga de tempdb), pero también porque parece un truco. Vamos a hacer otra puñalada al entrar en producción (lamentablemente solo nos encontramos con esto con las cargas de trabajo de producción) e intentaremos primero conversaciones más cortas de por vida. Actualizaré aquí con resultados. El siguiente será el truco 150 al que hizo referencia.
Jonathan Fite

Le pregunté a @RemusRusanu en Twitter: él es EL experto en cosas de corredores de servicios :-)
Kin Shah

Esto no es algo que haya visto antes (degradación de ENVIAR después de un largo tiempo de ejecución). 1) dígame cuál es el número de filas sys.conversation_endpointsdurante la prueba (constante o está aumentando, y qué tan grande es cuando ocurre el bloqueo). 2) Cuando ocurre el bloqueo, la desactivación de la cola objetivo hace una diferencia en el bloqueo de ENVIAR (la desactivación de la cola debe enrutar SEND a sys.transmission_queue). y 3) Obligar a los mensajes a ir al cable, incluso localmente (configurar el punto final SSB, agregar rutas) cambia el comportamiento a largo plazo
Remus Rusanu

Algunas reflexiones más: 4) cuando se produce el bloqueo, ¿detiene la RECEPCIÓN en el objetivo hacer una diferencia (deshabilitar el proceso activado, si lo hay) y 5) cuántos registros fantasmas hay en la cola del objetivo? ¿Correr ALTER QUEUE ... REBUILDhace una diferencia una vez que comienza el bloqueo?
Remus Rusanu

Respuestas:


3

Sé que es una mala forma responder su propia pregunta, pero quería cerrar esto para cualquier persona interesada. Finalmente logramos resolver el problema, o al menos resolverlo lo suficiente como para cumplir con nuestros requisitos. Quiero agradecer a todos los que contribuyeron comentarios; Remus Rusanu y Kin, ya que fueron muy útiles.

Nuestra base de datos está bastante ocupada y está en modo RCSI. Tenemos múltiples (miles) de dispositivos móviles que actualizan su información de ubicación cada 45 segundos. A través de estas actualizaciones, varias tablas obtienen su información actualizada (diseño pobre, ya que habría limitado la información volátil a una sola tabla y luego la uní para obtener los resultados). Estas tablas son las mismas que intentamos generar asincrónicamente información de informes para que los usuarios finales vayan directamente contra las tablas base.

Inicialmente, tuvimos los desencadenantes haciendo un cursor sobre los registros modificados en cada instrucción de actualización / inserción (debería haber sido una fila en la mayoría de los casos) y enviando cada clave principal en un mensaje al intermediario de servicios. Dentro de Service Broker, especialmente la cola masiva, había otros cursores que ejecutaban el procedimiento upsert para el informe (una ejecución por clave primaria).

Lo que finalmente nos hizo trabajar:

  • Quitamos los cursores y decidimos enviar mensajes más grandes. Todavía hay un mensaje por transacción de usuario por tabla, pero ahora enviamos mensajes con más de una clave principal.

  • El procesador masivo también envía varias claves por mensaje, lo que redujo el número de CONVERSACIONES DE ENVÍO que estaban sucediendo a medida que barajaba los mensajes a la otra cola según corresponda.

  • La tabla más volátil (nuestra tabla de datos del dispositivo móvil) tuvo sus desencadenantes eliminados. Actualizamos el procedimiento de actualización para incluir las claves foráneas apropiadas y ahora solo nos unimos de nuevo a esa tabla cuando buscamos resultados para los usuarios. Esta tabla contribuyó fácilmente con el 80% de los mensajes que tuvimos que procesar en un día.

Procesamos ~ 1 millón de mensajes al día (sin la tabla móvil) y la gran mayoría (99% +) de nuestros mensajes se procesan dentro de nuestro objetivo. Todavía tenemos valores atípicos ocasionales, pero dada la naturaleza rara de esto, se considera aceptable.

Factores contribuyentes:

  • Encontré un error en el procedimiento de limpieza de la conversación mencionado anteriormente que en realidad no estaba limpiando las conversaciones de manera adecuada y terminando prematuramente. Esto ahora ha resultado en que nuestro recuento de sysdesend nunca sea más que unos pocos miles (la mayor parte proviene del uso del truco 150).

  • Los cursores en los disparadores parecían tener más bloqueo del previsto (incluso con static, forward_only). eliminarlos parece haber hecho que las cerraduras que vemos en ENVIAR CONVERSACIÓN sean de naturaleza más transitoria (o al menos las veces que vemos son mucho más bajas).

  • Básicamente, estábamos ejecutando dos soluciones una al lado de la otra (el backend de la solución de Service Broker (para probar bajo carga de producción)) y la solución actual (consulta terrible que abarca muchas tablas).

Como beneficio adicional, esto ha descubierto un problema de Limpieza de registros fantasma y, aunque no estaba en las tablas de Service Broker (sistema o cola), está bastante desenfrenado en nuestro sistema y los síntomas se alinean muy bien con nuestra "causa no clara" problemas que experimentamos a veces. Se está llevando a cabo una investigación sobre eso, estamos tratando de encontrar las tablas que contribuyen y probablemente reconstruiremos sus índices de manera rutinaria.

Gracias otra vez.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.