La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Transacciones, Recuperación y Control de Concurrencia

Presentaciones similares


Presentación del tema: "Transacciones, Recuperación y Control de Concurrencia"— Transcripción de la presentación:

1 Transacciones, Recuperación y Control de Concurrencia

2 Ejemplo motivador: transferencia bancaria
Transacciones Transacción: colección de operaciones que forman una única unidad lógica de trabajo en una BD Control concurrencia Sistemas multiusuario: ejecución intercalada Recuperación Para cuando una transacción falla Vida de una transacción Inicio Lecturas/escrituras de elementos de la BD Final (pueden hacer falta algunas verificaciones) Confirmación (COMMIT) o anular (ROLLBACK) Ejemplo motivador: transferencia bancaria Comienzo de transacción. update cuentas set saldo=saldo where num=17 update cuentas set saldo=saldo where num=20 Fin de transacción Queremos que se ejecuten las 2 operaciones con la BD a la vez ya que si sólo se ejecutara la primera el titular de la cuenta 17 perdería ptas. que no pasarían a la cuenta 20. Si después de ejecutarse el primer update se produce un fallo (se apaga el ordenador) y por tanto la transacción FALLA queremos que al iniciarse de nuevo el sistema se deshaga automáticamente el primer cambio. Después ya se ejecutará la transacción de nuevo (el sistema no lo hará de manera automática). A la entidad bancaria tampoco le gustaría que se ejecutara solamente el segundo update. Las causas de posibles fallos pueden ser muchas: el saldo del primero es menor que (el programador debe controlarlo ya que suponemos que eso no sería un estado consistente en la BD), ocurre una operación incorrecta (overflow en la cuenta 20 !!, o en general divisiones por cero, etc.), hay problemas porque otra transacción ha leído a la vez el valor del saldo de la cuenta 20 y al actualizar ambas entonces se pierde una de las actualizaciones, ocurren fallos de disco al leer/escribir, o aún peor, catástrofes naturales (fuego), sabotajes, robos, etc. En realidad esto último lo deberían garantizar las medidas de seguridad informática adoptadas por la empresa (backups, discos RAID (Redundant Array of Inexpensive/Independent Disks), etc). La seguridad total no existe sino que depende de cuánto dinero/recursos nos gastemos en ella.

3 Transacciones Toda transacción debe cumplir el principio ACID
Atómica: se ejecuta todo (commit) o nada (rollback) Debe garantizarlo el método de recuperación del SGBD Consistente: pasa de un estado consistente a otro Debe garantizarlo el programador y el SGBD (restr. int.) aIslada: no lee resultados intermedios de otras transacciones que no han terminado Debe garantizarlo el método de control de concurrencia y el programador (ej: usando protocolo bloqueo en 2 fases). Duradera: si se termina con éxito (commit), los cambios en la BD son estables aunque luego falle otra Debe garantizarlo el método de recuperación.

4 Recuperación Caídas del sistema durante una transacción
Errores de ejecución: overflow, división por 0... Errores lógicos que violan alguna regla de integridad (definida explícitamente o no) y que dejan inconsistente la BD -> programador/ABD Problemas de concurrencia de transacciones Fallos de lectura/escritura en disco Problemas físicos y catástrofes: fuego, robos, sabotajes, fallos “humanos”,... --> medidas de seguridad informática en la empresa. Respecto a los errores lógicos, es responsabilidad de los programadores de BDs y/o del administrador el definir las reglas de integridad (cuya violación haría que el sistema automáticamente invalidara la transacción) y el realizar las comprobaciones correspondientes en los programas y escribir los ROLLBACK que sean necesarios. Por supuesto hay que indicar DÓNDE EMPIEZAN Y TERMINAN LAS TRANSACCIONES !!! El resto de problemas (excepto los dos últimos) son solucionados por el método de recuperación del SGBD.

5 Recuperación Para que el sistema se pueda recuperar ante fallos se necesita grabar cada operación con la BD en un fichero LOG (bitácora). Checkpoints. se escribe en el fichero LOG antes que en la BD el fichero LOG debe estar en memoria estable Por cada operación se escribe un reg. en LOG <comienza-transacción, numt> <escritura, numt, id_dato, val_viejo, val_nuevo> <lectura, numt, id_dato, valor> <termina_transacción_con_éxito, numt> <punto_comprobación, numt, numc> Comienzo de transacción. update cuentas set saldo=saldo where num=17 update cuentas set saldo=saldo where num=20 Fin de transacción. En el fichero de LOG se han podido grabar los siguientes registros: <comienza-transacción, t1> <lectura, t1, <nom_bd,cuentas,saldo,row_id=1.0.5>, > <escritura, t1, <nom_bd,cuentas,saldo,row_id=1.0.5>, , > Supongamos que aquí se cae el sistema. Al reinicializarse y analizarse el fichero de LOG se puede ver que la transacción t1 ha empezado pero no terminado por lo que deben deshacerse los cambios (basta con poner los valores viejos de las escrituras comenzando por el final). Supongamos que no se ha caído el sistema. <lectura, t1, <nom_bd,cuentas,saldo,row_id=1.0.8>, > <escritura, t1, <nom_bd,cuentas,saldo,row_id=1.0.8>, , > <termina-transacción-con-éxito, t1> Entonces ya tenemos almacenada toda la información que nos permitiría rehacer esta transacción t1 si fuera necesario a partir de un backup anterior de la BD y el fichero de LOG. Los checkpoints permiten, en caso de ciertos problemas, no deshacer toda la transacción, sino solamente hasta el último checkpoint.

6 Problemas de concurrencia
La ejecución concurrente de transacciones puede dar lugar a problemas: Problema de la actualización perdida Problema de leer una actualización temporal (lectura sucia) Problema del resumen incorrecto Problema de la lectura no repetible Problema de la actualización perdida: update cuentas (T1) update cuentas (T2) set saldo=saldo set saldo=saldo+2000 where num=17 where num=17 Secuencia: T1 lee saldo=5000, T2 lee saldo=5000, T1 escribe 6000, T2 escr (machaca el 6000). Sin embargo el resultado final debería ser 8000 !!! Problema de la actualización temporal: Usando las mismas transacciones. Secuencia: T1 lee saldo=5000, T1 escribe 6000, T2 lee saldo=6000, T1 falla y hace un ROLLBACK y deshace los cambios, T2 escribe Debería. ser 7000 !!!! Problema del resumen incorrecto: select sum(saldo) (T3) update cuentas (T4) from cuentas set saldo=saldo+1000 where num=17 update cuentas set saldo=saldo-1000 where num=25 Secuencia: T3 lee el saldo de la cuenta 17 después de que T4 incremente pero lee el de la cuenta 25 antes de decrementar. Por tanto la suma da 1000 ptas. más !!! Si se ejecutan todas las transacciones en exclusión mutua no hay problemas. Problema de la lectura no repetible: update cuentas (T5) update cuentas (T6) set saldo=saldo+1000 set saldo=0 where num=17 where num=17 update cuentas where num=17 Secuencia: T5 lee el saldo de la cuenta 17 dos veces pero si T6 se ejecuta en medio, no lee dos veces el mismo valor !!!

7 Problemas de Concurrencia
Sol. trivial: cada transacción se ejecuta en exclusión mutua. ¿Cuál sería la granularidad? ¿BD? ¿Tabla? ¿Tupla? ¿Atributo? La solución trivial no es válida: muy restrictiva Se supone que las BDs se pensaron para que varios usuarios/aplicaciones accedieran a la vez Hay que intercalar acciones pero que el resultado sea como en exclusión mutua

8 Control de concurrencia: planes serializables
Dadas las transacciones T1, T2, ... Tn, T1 compuesto por operaciones O11,O12,..O1 m1 T2 compuesto por operaciones O21,O22,..O2 m2 ... Tn compuesto por operaciones On1, On2..On mn Un plan de ejecución concurrente de las transacciones sería: Ej: O11, O21, On1, On2, O12, O22, …, O1 m1, O2 m2, …, On mn Una intercalación de todas las operaciones Oij donde para todo i, Oi1 se ejecuta antes que Oi2 ... antes que Oi mi Un plan es serializable si su resultado es el mismo que el producido por alguno de los posibles planes seriales de T1, T2,...Tn Ej:opers. de T2, opers. T1, opers. Tn, ...., opers. de T3 T1: select * from personas where color_pelo=‘RUBIO’ T2: update personas set salario=salario*1.1 T3: update personas set salario=0 where color_pelo=‘RUBIO’ update personas set salario=20000 where color_pelo=‘NEGRO’ Tabla personas (DNI, SALARIO,COLOR_PELO) RUBIO MORENO RUBIO NEGRO Planes SERIALES (los únicos válidos) y después únicos resultados válidos: T1, T2, T3 T1, T3, T2 T2, T1, T3 T2, T3, T1 T3, T1, T2 T3, T2, T1 (DNI, SALARIO,COLOR_PELO) (DNI, SALARIO,COLOR_PELO) RUBIO RUBIO MORENO MORENO RUBIO RUBIO NEGRO NEGRO Todo plan SERIALIZABLE deberá dejar la tabla de personas con una de las dos extensiones anteriores (y además la transacción T1 devolverá las tuplas de personas de pelo RUBIO correspondientes a una de las 3 extensiones posibles: la inicial, una de las 2 finales o una de las 2 intermedias (tras hacer solamente T2 o T3). Ejemplo de plan serializable: T1 lee tupla 1, T2 escribe tuplas 1 y 2, T3 escribe tupla 1, T1 lee tupla 3, T2 escribe tuplas 3 y 4, T3 escribe 3 y 4 Ejemplo de plan no serializable: T1 lee la tupla 1, T2 escribe tuplas 1, 2 y 3, T1 lee 2 !!

9 Serializabilidad Aparte de ACID, queremos que las transacciones sean serializables. Determinar si un determinado plan es serializable es un problema NP-completo. Solución: Imponer restricciones a la libre intercalación de operaciones entre transacciones Técnicas pesimistas: se impide realizar ciertas operaciones si son sospechosas de producir planes no serializables: BLOQUEOS (lock) y MARCAS DE TIEMPO (time-stamping) Técnicas optimistas: no imponen restricciones pero después se comprueba si ha habido interferencias NOTA: Vendría bien que el problema no fuera NP-completo ya que en ese caso sería posible recibir las N transacciones a ejecutar y encontrar un plan (que además fuera serializable, claro) y que optimizara las N. Se trataría de optimizar la ejecución de N pregunta en vez de optimizar sólo una pregunta cada vez.

10 Técnicas de bloqueo (lock)
A cada elemento de datos o gránulo X de la BD se le asocia una variable operación lock_exclusivo(X): deja bloqueado al que lo pide si otro ya tiene cualquier lock sobre X operación lock_compartido(X): deja bloqueado al que lo pide si otro ya tiene un lock exclusivo sobre X operación unlock(X): libera su lock sobre X Antes de leer X  lock_compartido(X) Antes de escribir (leer) X  lock_exclusivo(X) Si no se va a leer o escribir más  unlock(X) Dadas las dos transacciones siguientes: T1 T2 lock_compartido(Y) X=20, Y=30 lock_compartido(X) read(Y) | read(X) unlock(Y) | unlock(X) lock_exclusivo(X) | lock_exclusivo(Y) read(X) | read(Y) X:=X+Y X=50, Y=50 Y:=Y+X write(X) | write(Y) unlock(X) !!!!!!!! unlock(Y) Resultados válido: si T1 se ejecuta antes que T2 entonces X=50, Y=80. Si T2 se ejecuta antes que T1 entonces X=70, Y=50 Sin embargo: Puede ocurrir que ambos dejen X=50 y Y=50 debido a que cada uno de ellos hace unlock(Y) y unlock(X) permitiendo al otro conseguir el lock_exclusivo de ambas variables. Si vamos alternando las operaciones de T1 y T2, PLAN NO SERIALIZABLE !!! El problema estriba en hacer UNLOCK antes de tiempo. El protocolo de bloqueo en dos fases impide hacer UNLOCK si todavía faltan LOCKs por hacer. Ese protocolo garantiza la serializabilidad.

11 Protocolo de Bloqueo en dos fases
Una transacción sigue el protocolo de bloqueo en dos fases si nunca hace un lock después de haber hecho algún unlock. Fase de crecimiento: se solicitan locks Fase de devolución: se realizan unlocks Solamente este protocolo de bloqueo garantiza la serializabilidad de transacciones Sin embargo, existe riesgo de deadlock !! Prevención de deadlocks Detección y recuperación de deadlocks El protocolo de bloqueo en dos fases GARANTIZA la serializabilidad PERO IMPIDE ALGUNO DE LOS PLANES SERIALIZABLES. Ya dijimos que era restrictivo y que impedía algunas de las operaciones sospechosas de hacer no serializable el plan. Qué se le va a hacer ! T1 T2 T3 read(X) X:=5 read(X) X:=X+1 write(X) X:=X+5 write(X) write(X) Inic: X=10 T1 (X=11) T2 (X=5) T3 (X=10) (****) T2 (X=5) T1 (X=6) T3 (X=11) T1 (X=11) T3 (X=16) T2 (X=5) (igual que T3 T1 T2) T2 (X=5) T3 (X=10) T1 (X=11) T3 (X=15) T2 (X=5) T1 (X=6) Sin embargo el siguiente plan es serializable pero no es permitido por el protocolo de bloqueo en dos fases: 1.- T1 hace read(X) X=10 (Suponemos que las X donde se hace X:=X+1, X:=5, ... son locales a cada transacción). 2.- T2 hace write(X) escribe X=5 (NO SERÍA POSIBLE. Se necesitaría haber obtenido el lock_exclusivo(X) !!) 3.- T3 hace read (X) y lee X=5 4.- T1 hace write(X) y escribe X=11 5.- T3 hace write(X) y escribe X=10 (SERIALIZABLE !!!! igual a ****)

12 Deadlocks Prevención de deadlocks
Deadlock (o abrazo mortal o interbloqueo): cuando una transacción T1 está bloqueada esperando a que otra T2 libere un lock, la cual también está bloqueada esperando a que T1 libere uno de sus lock. Se puede generalizar para N transacciones. Prevención de deadlocks Cada transacción obtiene todos los locks al principio y si no puede entonces no obtiene ninguno. Problema de livelock (inanición de algunas transacciones que pueden no obtener todos los que necesiten) Los elementos de la BD están ordenados de alguna manera y los lock hay que obtenerlos en dicho orden. Los programadores deben controlarlo !! Detección y recuperación de deadlocks. A medida que se piden y conceden los lock se construye un grafo de las transacciones que están esperando a otras. Si existe un ciclo en dicho grafo: deadlock. Hay que proceder a abortar a alguna de las transacciones. Problema de livelock si se aborta siempre a la misma! Prevención de deadlocks: A) lock_exclusivo(X,Y,...) OBTIENE TODOS O NINGUNO !! B) Ejemplo de pedir los lock en un orden: siempre pedir X antes que Y. El programador debe controlarlo. Demasiado pedir a los programadores !! lock_exclusivo(X) lock_exclusivo(X) lock_exclusivo(Y) lock_exclusivo(Y) read(X); read(Y); read(X); read(Y),… Detección de deadlocks: lock_exclusivo(X) lock_exclusivo(Y) lock_exclusivo(Y) lock_exclusivo(X) T1 consigue el lock exclusivo para X. T2 consigue el lock exclusivo para Y. Luego T2 solicita el lock exclusivo para X. Como lo tiene T1 entonces se añade arista al grafo: T > T1 (T2 está esperando a T1) Luego T1 solicita el lock exclusivo para Y. Como lo tiene T2 entonces se añade arista al grafo: T > T2 En ese momento se puede comprobar que en el grafo HAY UN CICLO !!! (detectar un ciclo en un grafo de N nodos ---> O(N*N) ) ORACLE proporciona DETECCIÓN AUTOMÁTICA DE INTERBLOQUEOS (deadlocks) y lo resuelve abortando a algunos de los procesos. El programador por tanto no debe controlarlo.

13 Técnicas de marcas de tiempo (time-stamping)
Un timestamp es un identificador asignado a cada transacción TS(T). Indica la hora de comienzo de la transacción T. A cada elemento X de la BD se le asigna el timestamp de la última transacción que lo ha leído (TS_lect(X)) y escrito (TS_escr(X)) Si una transacción T quiere escribir en X si TS_lect(X) > TS(T) entonces abortar si TS_escr(X) > TS(T) entonces no escribir y seguir en otro caso escribir y TS_escr(X):=TS(T) Una transacción T quiere leer de X si TS_escr(X) > TS(T) entonces abortar si TS_escr(X) <= TS(T) entonces leer de X y TS_lect(X):=máximo(TS(T),TS_lect(X)) Garantiza serializabilidad y ausencia de deadlocks. Puede haber livelock (si se aborta siempre a la misma transacción) Como el protocolo en 2 fases: hay planes que son serializables pero que ni las técnicas de time-stampìng ni el protocolo de bloqueo en 2 fases los permiten.

14 Técnicas optimistas No se realizan comprobaciones ANTES de ejecutar las operaciones (pedir locks, comprobar timestamps), sino al acabar toda la transacción (fase validación) Durante la ejecución de la transacción se trabaja con copias Hay tres fases en un protocolo optimista: Fase de lectura Fase de validación Fase de escritura Es bueno cuando no hay muchas interferencias entre transacciones (por eso son “optimistas”) Fase de lectura: ejecución de la transacción. Se leen los valores y se escriben en copias locales. Fase de validación: antes de que Ti haga commit se comprueba si hay interferencias. No las hay en cualquiera de los casos siguientes Tj ha terminado su fase de escritura antes de que Ti haya comenzado su fase de lectura. Ti comienza su fase de escritura después de que Tj complete su fase de escritura y Ti no lee elementos escritos por Tj. No hay elementos en común entre los que lee y escribe Ti con los que escribe Tj, y Tj ha terminado su fase de lectura antes de que Ti termine su fase de lectura. Fase de escritura: si ha habido problemas se hace rollback y si no, se escriben todos los cambios en la BD (commit).

15 Recuperación en Oracle
Redo logs (cíclicos) Archive logs (consolidación de redo logs) Backups Mirrors Export: Incremental, acumulativo (colección de incrementales), total Recuperación basada en cambios, tiempo, paso-a-paso (basado en archive logs), completa

16 Control de concurrencia en ORACLE (1)
Lectura consistente: garantiza que se lean los datos tal y como estaban al inicio de la transacción, sin impedir que otras transacciones los cambien. Implícitamente con SELECT .. FROM T,R ... (lo garantiza sobre las tuplas de T,R,...) Explícitamente con SET TRANSACTION READ ONLY; (lo garantiza sobre las tuplas de todas las tablas hasta el fin de transacción.) Debe ser la primera instrucción de la transacción No permitirá hacer ningún INSERT, DELETE o UPDATE en dicha transacción ORACLE garantiza que ninguna instrucción SELECT de una transacción LEE RESULTADOS DE ACTUALIZACIÓN DE OTRAS TRANSACCIONES sobre las que no se ha hecho COMMIT. Con la lectura consistente es posible no ver dichos cambios incluso después de que hayan hecho COMMIT. Ej: Si se quiere conocer el número de billetes libres en total (suponiendo que se encuentran en dos tablas distintas), entonces hay que hacer: set transaction read only; select count(*) from billetes_iberia where estado=‘Libre’; from billetes_aviaco commit; Así se asegura que podemos saber el número de billetes libres justo en el momento de iniciarse la transacción. No hay que olvidar que mientras se ejecuta es posible que alguno de los billetes de cualquiera de las tablas pase de ‘Libre’ a ‘Reservado’ o de ‘Reservado’ a ‘Libre’ (pero esto no cambia los datos manejados por la transacción).

17 Control de concurrencia en ORACLE (2)
LOCKs Explícitamente con LOCK TABLE T IN x MODE x indica si sobre todas/algunas tuplas de T en modo compartido/exclusivo) Implícitamente con cada operación (según cláusula WHERE) UPDATE, DELETE, INSERT. Se bloquean las tuplas insertadas, borradas o actualizadas (al ser una transacción no finalizada) SELECT...FROM T FOR UPDATE OF atr. Se bloquean las tuplas seleccionadas Si se quiere reservar un billete antes hay que ver cuáles son los billetes que están libres. Por lo tanto, antes de ESCRIBIR hay que LEER. Para estar seguros de que lo que se está leyendo NO SE CAMBIA concurrentemente por alguna transacción, entonces según el protocolo de bloqueo en dos fases, hay que hacer: select * from billetes where estado=‘Libre’ for update of estado /* Necesario para conseguir el lock exclusivo sobre billetes libres */ /* Se ven los libres. Supongamos que el num 17 lo está.*/ update billetes set estado=‘Reservado’ where num=17 commit Si no, podría suceder que mientras se ejecuta el primer SELECT, alguna otra transacción reservara a la vez el num 17. Otra posible solución si no se pone FOR UPDATE OF estado: update billetes set estado=‘Reservado’ where num=17 and estado=‘Libre’ En ese caso, si lo han reservado mientras tanto, dirá que ninguna cumplía las condiciones (num=17 and estado=‘Libre’).

18 Control de concurrencia en ORACLE (y 3)
No hay UNLOCK explícitos en ORACLE!! Se realiza un UNLOCK implícito de todos los LOCK con cada COMMIT o ROLLBACK (implícitos o explícitos) Pregunta: ¿Cómo conseguir que las transacciones en ORACLE sigan el protocolo en dos fases, o lo que es lo mismo, sean serializables? En principio en ORACLE no se puede pedir un LOCK después de hacer un UNLOCK dentro de una transacción, ya que se hace UNLOCK SIEMPRE DESPUÉS DE TERMINAR LAS TRANSACCIONES (con commit o rollback) Con cualquier operación de escritura: INSERT, UPDATE o DELETE, se nos asegura que ORACLE obtiene LOCKs exclusivos. La única pega es con las operaciones de lectura, ya que ORACLE no obtiene LOCKS compartidos. Es posible leer a la vez que otra transacción está escribiendo en la tabla/s que estamos leyendo. En algunos casos de lectura será necesario colocar: 1) SELECT ...FOR UPDATE OF … cuando antes de escribir queramos leer para ver si se puede o no escribir en las tuplas seleccionadas. Esta operación espera a obtener un LOCK EXCLUSIVO sobre la columna indicada.. 2) SET TRANSACTION READ ONLY que nos asegura que esta transacción lee los valores de todas las tablas en el momento inicial de la transacción. Habrá que ponerla si vamos a leer de dos tablas: select * from A where ... select * from B where ... y no queremos ver los valores que otra transacción haya hecho (con commit) sobre B mientras leíamos A.


Descargar ppt "Transacciones, Recuperación y Control de Concurrencia"

Presentaciones similares


Anuncios Google