Skip to content Skip to navigation

OpenStax_CNX

You are here: Home » Content » Control de concurrencia en bases de datos relacionales

Navigation

Recently Viewed

This feature requires Javascript to be enabled.
 

Control de concurrencia en bases de datos relacionales

Module by: Miguel-Angel Sicilia. E-mail the author

Summary: Se introduce el problema de las operaciones concurrentes en bases de datos relacionales, y el uso de bloqueos para evitar esos problemas. Se introduce el problema del interbloqueo y las técnicas de concurrencia multi-versión como alternativa.

Control de concurrencia en bases de datos relacionales

La mayoría de las bases de datos se utilizan en entornos multi-usuario, en los que muchos clientes utilizando la misma aplicación, o muchas aplicaciones cada una con uno o muchos clientes acceden a la misma base de datos. Cada una de esas aplicaciones enviará consultas al gestor, y normalmente cada hilo de ejecución será una transacción diferente.

En la mayoría de los sistemas operativos actuales, las diferentes tareas o hilos se ejecutan de forma intercalada (incluso en el caso de máquinas con varios procesadores). Es decir, el sistema operativo decide por su cuenta cuando suspender una de las tareas y darle un poco de tiempo de ejecución a otra. Si hay tareas simultáneas o concurrentes sobre la misma base de datos, esta intercalación puede resultar en que las lecturas y escrituras de las diferentes tareas o aplicaciones en el medio físico se realicen en cualquier orden y secuencia.

El acceso simultáneo descrito puede dar como resultados información inconsistente o simplemente incorrecta, dependiendo de la mala o buena suerte que tengamos en la intercalación de las lecturas y escrituras simultáneas. Esta problemática ha llevado a diseñar e implementar diferentes estrategias de control de concurrencia, que se encargan de evitar todos esos problemas, de modo que los desarrolladores de las aplicaciones pueden “olvidarse” de ellos al escribir su código.

Por ejemplo, si tenemos una estructura de tablas relacional que incluye las siguientes:

PEDIDO(id, num-cliente, id-prod, cantidad, precio)

PRODUCTO(id-prod, nombre, ..., stock)

...

Pueden ocurrir diferentes problemas relacionados con la escritura simultánea con otras escrituras o lecturas, incluyendo los siguientes:

  1. Dos sentencias UPDATE que actualicen un mismo producto decrementando el stock del mismo en una unidad podrían terminar en que una de ellas no se realizase. Si pensamos en un UPDATE como una secuencia de una lectura y una escritura, puede que ambos UPDATE hagan la lectura, por ejemplo, de un stock de 10, y después las escrituras, decrementan ese dato, quedando el resultado en 9, mientras que lo correcto era un resultado de 8.
  2. Supongamos una sentencia que primero comprueba que hay stock del producto P, y después inserta un nuevo PEDIDO de diez unidades del producto P, que tiene un stock de 10, seguido de un UPDATE al stock por esa cantidad. Puede que otra inserción de un pedido se ejecute antes del UPDATE pero después de la comprobación, haciendo quedar el stock del producto en negativo.

Existen varias técnicas para controlar la concurrencia. Los bloqueos son los más conocidos, aunque también se utiliza el control multi-versión y otras técnicas como las marcas de tiempo.

Los bloqueos como solución al problema de la concurrencia

Una forma de controlar la concurrencia es hacer que cada transacción deba adquirir un derecho de acceso exclusivo a cada fragmento de datos que necesite modificar. A estos “derechos” se les denomina bloqueos.

Bloqueos binarios

La forma más simple de bloquear es utilizar bloqueos binarios. En un bloqueo binario, cada transacción debe solicitar el bloqueo de cada fragmento de datos A que vaya a utilizar antes de acceder a él (sea para leerlo o escribirlo), mediante una operación bloquear(A). Deberá liberar todos los bloqueos, mediante una operación desbloquear(A) de modo que otras tareas puedan tomarlos.

Este sistema de bloqueos tiene una implementación muy simple, ya que solo requiere mantener una tabla que indica qué partes de los datos está bloqueada y por qué transacción.

Bloqueos de lectura/escritura

El sistema de bloqueos binarios es simple pero demasiado restrictivo, ya que no permite que dos transacciones que van a leer el mismo fragmento de datos A lo hagan simultáneamente, cuando en realidad, no puede haber problemas en varios lectores simultáneos. Los bloqueos de lectura/escritura hacen más débil la restricción permitiendo la siguiente compatibilidad de bloqueos.

Tabla 1
  LECTURA ESCRITURA
LECTURA Compatible Incompatible
ESCRITURA Incompatible Incompatible

En este caso, las operaciones que las transacciones deben realizar son tres: desbloquear(A) y bloquear_para_lectura(A) o bloquear_para_escritura(A).

Nótese que esas llamadas se implementan de diferentes formas en diferentes gestores de bases de datos. Por ejemplo, en MySQL, tanto las solicitudes de bloqueos como las liberaciones se realizan mediante una sola llamada del API de los gestores de almacenamiento:

store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)

Cada llamada a store_lock utiliza el manejador de una tabla thd concreta, y se indica la información de los datos a bloquear mediante la variable to, y el tipo de bloqueo mediante lock_type (el número de tipos definidos en MySQL es muy grande, ya que cubre todos los tipos de bloqueo que implementan los múltiples gestores de almacenamiento disponibles).

Serialización de los bloqueos de lectura/escritura

La serialización de las operaciones de lectura y escritura consiste en ordenar esas operaciones para un conjunto de transacciones concurrentes de modo que los resultados de las operaciones sean correctos. Por ejemplo, si tenemos las siguientes transacciones X e Y, puede darse la siguiente situación.

Figura 1
Figura 1 (graphics1.png)

En esa situación, la ejecución de TX y TY hace que el dato original sólo se haya incrementado una vez, cuando tenía que haberse incrementado dos veces. Sin embargo, si hubiésemos tenido suerte y todas las operaciones de TX se hubiesen realizado antes que las de TY, el resultado habría sido correcto.

La conclusión es que el mero mecanismo de los bloqueos garantiza el acceso exclusivo a un dato o fragmento de información (evitando ciertos problemas), pero los problemas asociados a la intercalación de las operaciones compuestas aún pueden darse.

Por lo tanto, hace falta alguna política o mecanismo de adquisición y liberación de bloqueos que permita hacer las operaciones serializables.

El bloqueo en dos fases permite la serialización

El protocolo de bloqueo en dos fases fuerza a las transacciones cuando todas las operaciones de adquisición de bloqueos (bloquear_lectura, bloquear_escritura) preceden a la primera operación de desbloqueo (desbloquear). Dicho de otro modo, primero hay que adquirir todos los bloqueos, y después se pueden liberar.

Cuando se utiliza el protocolo de bloqueo en dos fases, puede demostrarse que la ejecución será serializable.

Inconvenientes de los bloqueos y la serialización

Un problema del protocolo de bloqueo en dos fases es que puede llevar a situaciones de interbloqueo. La siguiente es una secuencia de operaciones que lleva al interbloqueo pero cumple perfectamente l protocolo de bloqueo en dos fases.

Figura 2
Figura 2 (graphics2.png)

El inconveniente está en que puede que en la fase de adquisición de bloqueos (fase de expansión), más de una transacción esté interesada en los mismos dos fragmentos de datos, y la mala suerte nos lleve a una situación en la que ambos quedan suspendidos, sin posibilidad de avanzar.

¿Bloqueos más grandes o más pequeños?

Un aspecto que aún no se ha tratado en la discusión anterior es cuán “grandes” son los elementos de datos que se deben bloquear. Una opción posible es bloquear tablas enteras. Esto hace que la gestión de los bloqueos sea simple y tenga poca sobrecarga (solo hay que guardar el estado de bloqueo de las N tablas). No obstante, esto impide que dos transacciones que van a manipular filas diferentes de una tabla puedan progresar en paralelo.

Una segunda opción es utilizar bloqueos al nivel de las filas. En este caso, se hacen mayores las posibilidades de concurrencia, pero por otro lado, hay que mantener mucha más información sobre los bloqueos (ya que el número de filas es en general muy grande respecto al número de tablas), y el servidor se sobrecarga más con la gestión de los bloqueos.

Hay gestores de bases de datos que permiten seleccionar el tipo de bloqueo que queremos para nuestra base de datos. Por ejemplo, en MySQL hay gestores de almacenamiento que ofrecen bloqueo a nivel de fila, y otros bloqueo a nivel de tabla.

No obstante lo anterior, hay sentencias que siempre producirán un bloqueo de tabla, como por ejemplo una sentencia ALTER TABLE.

Guardando “instantáneas” de los datos: el Control Multi-versión

El protocolo de bloqueo en dos fases limita considerablemente las posibilidades de concurrencia. Si observamos los problemas que causan los bloqueos no serializados, veremos que muchos de los problemas están en que una transacción lee un cierto dato y antes de escribir el resultado, otra transacción lee el dato “antiguo”. En ese momento, cada transacción trabaja con un estado de información inconsistente.

Para paliar esos problemas, pero permitir la mayor concurrencia posible, se han diseñado los protocolos de control multi-versión. La idea básica es que cuando una transacción modifica un dato, se crea una nueva versión del mismo, pero se guarda la anterior. De este modo, al acabar la ejecución de las transacciones, se puede utilizar para cada una de ellas la versión de los datos “que hace la ejecución correcta”, es decir, que hace la ejecución serializable.

Lógicamente, estas técnicas requieren más espacio de almacenamiento para guardar las diferentes versiones.

Content actions

Download module as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks