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:
