En la versión 9.7, DB2 comenzó a ofrecer un nuevo método de monitorización para el interbloqueo (deadlocks). Aunque esta publicación describe la forma «antigua», este método también funciona en db2 9.7. Los monitores de eventos Detailedeadlock han quedado en desuso, pero aún no se han eliminado. Esto significa que incluso en 9.7, aún puede crearlos y trabajar con ellos.
Si está confundido acerca de la diferencia entre los deadlocks y los lock timeouts, lea primero mi publicación en Deadlocks VS. Lock timeouts.
Crear el monitor de eventos de punto muerto
Una de las cosas más críticas aquí es que debe tener el monitor de eventos detailedeadlock creado y funcionando antes de encontrarse con un problema. Por defecto (incluso en 9.7), db2 tiene uno llamado simplemente «db2detaildeadlock». El único problema es que puede quedarse sin espacio con bastante rapidez. Como resultado, lo creo cada vez, utilizando esta sintaxis (por supuesto, necesitará una conexión a la base de datos):
db2 "create event monitor my_detaildeadlock for deadlocks with details write to file 'my_detaildeadlock' maxfiles 2000 maxfilesize 10000 blocked append autostart" DB20000I The SQL command completed successfully.
Además, hay que crear manualmente el directorio para el monitor de eventos. Va en el subdirectorio «db2event» de la ruta de la base de datos, por lo que en mi último ejemplo, utilicé algo así para crearlo:
mkdir /db_data/db2inst1/NODE0000/SQL00002/db2event/my_detaildeadlock
Y luego hay que activar el nuevo y eliminar el viejo:
db2 "set event monitor ros_detaildeadlock state=1" DB20000I The SQL command completed successfully. db2 "set event monitor db2detaildeadlock state=0" DB20000I The SQL command completed successfully. db2 "drop event monitor db2detaildeadlock" DB20000I The SQL command completed successfully.
Finalmente, usted querrá verificar el estado del monitor de eventos recién creado:
> db2 "select substr(evmonname,1,30) as evmonname, EVENT_MON_STATE(evmonname) as state from syscat.eventmonitors with ur" EVMONNAME STATE ------------------------------ ----------- ROS_DETAILDEADLOCK 1 1 record(s) selected.
1 significa estado activo y 0 significa no activo, por lo que esta es la salida que queremos.
Formateando y analizando los resultados
Ahora que tenemos el monitor de eventos en funcionamiento, ¿qué hacemos con él? Bueno, suponiendo que realmente tenga algunos puntos muertos o deadlocks (como puede ver a través del snapshot event monitor, usando db2top, db2pd, vistas administrativas de db2 o el comando get snapshot), querrá vaciar el monitor de eventos que hemos creado y convertir su contenido a un formato legible.
> db2 flush event monitor MY_DETAILDEADLOCK DB20000I The SQL command completed successfully.
> db2evmon -path /db_data/db2inst1/NODE0000/SQL00002/db2event/my_detaildeadlock >deadlocks.out Reading /db_data/db2inst1/NODE0000/SQL00002/db2event/ros_detaildeadlock/00000000.evt ...
Su ruta puede ser diferente, por supuesto. Prefiero emplear la opción de ruta en db2evmon porque he tenido menos problemas con ella. Hay una opción para especificar el nombre de la base de datos y el del monitor de eventos pero sencillamente no me parece tan fiable.
Así que ahora hemos hecho la parte fácil. Sí, así es, esa es la parte fácil. Dependiendo de la cantidad de puntos muertos, ahora puede tener un archivo gigante. Creo recordar haber analizado un fichero de 15 GB de una sola vez. Aquí hay algunos fragmentos de la salida para dar una idea de lo que está viendo:
379) Deadlock Event ... Deadlock ID: 20 Number of applications deadlocked: 2 Deadlock detection time: 01/03/2012 14:06:13.425034 Rolled back Appl participant no: 2 Rolled back Appl Id: 172.19.10.61.37259.120103200006 Rolled back Appl seq number: : 0009
...
381) Deadlocked Connection ... Deadlock ID: 20 Participant no.: 2 Participant no. holding the lock: 1 Appl Id: 172.19.10.61.37259.120103200006 Appl Seq number: 00009 Tpmon Client Workstation: spp27comm02x Appl Id of connection holding the lock: 172.19.10.61.62895.120103194755 Seq. no. of connection holding the lock: 00001 Lock wait start time: 01/03/2012 14:06:03.651592 Lock Name : 0x02000C1A1500BCE31800000052 Lock Attributes : 0x00000000 Release Flags : 0x00000001 Lock Count : 1 Hold Count : 0 Current Mode : none Deadlock detection time: 01/03/2012 14:06:13.425119 Table of lock waited on : USERS Schema of lock waited on : WSCOMUSR Data partition id for table : 0 Tablespace of lock waited on : USERSPACE1 Type of lock: Row Mode of lock: X - Exclusive Mode application requested on lock: NS - Share (and Next Key Share) Node lock occured on: 0 Lock object name: 106899963925 Application Handle: 47264 Deadlocked Statement: Type : Dynamic Operation: Fetch Section : 2 Creator : NULLID Package : SYSSH200 Cursor : SQL_CURSH200C2 Cursor was blocking: FALSE Text : SELECT T1.STATE, T1.MEMBER_ID, T1.OPTCOUNTER, T1.TYPE, T2.FIELD2, T2.REGISTRATIONUPDATE, T2.FIELD3, T2.LASTORDER, T2.LANGUAGE_ID, T2.PREVLASTSESSION, T2.SETCCURR, T2.DN, T2.REGISTRATIONCANCEL, T2.LASTSESSION, T2.REGISTRATION, T2.FIELD1, T2.REGISTERTYPE, T2.PROFILETYPE, T2.PERSONALIZATIONID FROM MEMBER T1, USERS T2 WHERE T1.TYPE = 'U' AND T1.MEMBER_ID = T2.USERS_ID AND T1.MEMBER_ID = ? List of Locks:
...
383) Deadlocked Connection ... Deadlock ID: 20 Participant no.: 1 Participant no. holding the lock: 2 Appl Id: 172.19.10.61.62895.120103194755 Appl Seq number: 00905 Tpmon Client Workstation: spp27comm02x Appl Id of connection holding the lock: 172.19.10.61.37259.120103200006 Seq. no. of connection holding the lock: 00001 Lock wait start time: 01/03/2012 14:06:03.657097 Lock Name : 0x02000D0E2F00F8D61800000052 Lock Attributes : 0x00000000 Release Flags : 0x40000000 Lock Count : 1 Hold Count : 0 Current Mode : U - Update Deadlock detection time: 01/03/2012 14:06:13.425274 Table of lock waited on : MEMBER Schema of lock waited on : WSCOMUSR Data partition id for table : 0 Tablespace of lock waited on : USERSPACE1 Type of lock: Row Mode of lock: NS - Share (and Next Key Share) Mode application requested on lock: X - Exclusive Node lock occured on: 0 Lock object name: 106685792303 Application Handle: 47206 Deadlocked Statement: Type : Dynamic Operation: Execute Section : 25 Creator : NULLID Package : SYSSH200 Cursor : SQL_CURSH200C25 Cursor was blocking: FALSE Text : UPDATE MEMBER SET STATE = ?, OPTCOUNTER = ? WHERE MEMBER_ID = ? AND OPTCOUNTER = ? List of Locks:
...
He eliminado la lista de bloqueos debido a la longitud, y también las entradas en los eventos de conexión, pero no he alterado la salida real aquí.
La «Deadlock ID» nos permite identificar en qué punto muerto participó este. Los puntos muertos más frecuentemente involucran 2 conexiones, pero pueden involucrar 3, 4, 5 o incluso más.
Si observa el «Participant no» tanto en la sección «Deadlock Event» como en las secciones de «Deadlocked Connection» y «Rolled back Appl participant no» en la sección «Deadlock Event», puede comprender qué declaración se deshizo con rollback y cuál se permitió continuar.
Hay mucha más información útil para analizar, la mayor parte es bastante obvia en su significado.
Es bueno revisar y determinar si las mismas sentencias estuvieron involucradas en puntos muertos una y otra vez, y qué sentencias estuvieron involucradas con mayor frecuencia en un punto muerto. También es bueno analizar la duración de los puntos muertos: Un resumen por hora es muy útil para ayudar a determinar si se limitaron a un período de tiempo específico. También puede ser interesante resumir por tabla para ver si una tabla en particular está frecuentemente involucrada.
¿Qué hacer con el análisis?
Lo primero que debe hacer con lo que encuentre es proporcionar el código SQL a sus desarrolladores. Deben ser capaces de comprender de dónde proviene ese SQL en su aplicación, y deberían poder proponer ideas para reducir el bloqueo.
Recuerde que el interbloqueo, punto muerto o deadlock es un problema de aplicación cuyos síntomas aparecen en la base de datos. Todo lo que puede hacer para reducir el bloqueo a nivel de base de datos es:
- Mantener runstats actualizadas
- Establecer las siguientes variables de registro de db2, SOLO SI SU APLICACIÓN LOS APOYA EXPLÍCITAMENTE:
- DB2_SKIPINSERTED
- DB2_SKIPDELETED
- DB2_EVALUNCOMMITTED
Aumentar LOCKLIST no ayudará con el interbloqueo a menos que también esté viendo escaladas de bloqueo.
References:
Info Center entry on deprecation of detaildeadlock event monitor: http://www.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.wn.doc/doc/i0054715.html
Info Center entry on db2evmon: