Bloqueo optimista versus pesimista

572

Entiendo las diferencias entre el bloqueo optimista y pesimista. ¿Podría alguien explicarme cuándo usaría cualquiera de ellos en general?

¿Y la respuesta a esta pregunta cambia dependiendo de si estoy usando o no un procedimiento almacenado para realizar la consulta?

Pero solo para verificar, optimista significa "no bloquear la mesa mientras lee" y pesimista significa "bloquear la mesa mientras lee".

Jason Baker
fuente
1
blog.couchbase.com/…
Frank Myat jue
1
Esa es una buena pregunta, particularmente porque leí en serializabilidadAt any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts .
Little Alien
1
Aquí puede encontrar una buena explicación, aquí en SO, sobre cuál es el concepto raíz de Optimistic Locking .
Diego Mazzaro

Respuestas:

812

El bloqueo optimista es una estrategia en la que lee un registro, toma nota de un número de versión (otros métodos para hacerlo incluyen fechas, marcas de tiempo o sumas de verificación / hashes) y comprueba que la versión no ha cambiado antes de volver a escribir el registro. Cuando vuelve a escribir el registro, filtra la actualización en la versión para asegurarse de que sea atómica. (es decir, no se ha actualizado entre cuando verifica la versión y escribe el registro en el disco) y actualiza la versión de un solo golpe.

Si el registro está sucio (es decir, una versión diferente a la suya), cancela la transacción y el usuario puede reiniciarla.

Esta estrategia es más aplicable a sistemas de alto volumen y arquitecturas de tres niveles en los que no necesariamente mantiene una conexión a la base de datos para su sesión. En esta situación, el cliente no puede mantener los bloqueos de la base de datos ya que las conexiones se toman de un grupo y es posible que no esté utilizando la misma conexión de un acceso a otro.

El bloqueo pesimista es cuando bloquea el registro para su uso exclusivo hasta que haya terminado con él. Tiene una integridad mucho mejor que el bloqueo optimista, pero requiere que tenga cuidado con el diseño de su aplicación para evitar puntos muertos . Para usar el bloqueo pesimista, necesita una conexión directa a la base de datos (como suele ser el caso en una aplicación de servidor de cliente de dos niveles ) o un ID de transacción disponible externamente que se pueda usar independientemente de la conexión.

En el último caso, abre la transacción con el TxID y luego se vuelve a conectar con esa ID. El DBMS mantiene los bloqueos y le permite recuperar la sesión a través del TxID. Así es como funcionan las transacciones distribuidas que utilizan protocolos de confirmación de dos fases (como XA o COM + Transacciones ).

Preocupado por TunbridgeWells
fuente
148
El bloqueo optimista no necesariamente usa un número de versión. Otras estrategias incluyen el uso de (a) una marca de tiempo o (b) todo el estado de la fila. La última estrategia es fea, pero evita la necesidad de una columna de versión dedicada, en los casos en que no puede modificar el esquema.
Andrew Swan
2
@geek: los protocolos de transacciones distribuidas, como XA, permiten reticular un identificador de transacción separado en uno o más sistemas. Este tipo de protocolo permite el uso de bloqueos a través de conexiones agrupadas, ya que el identificador de la transacción se desacopla de las sesiones y se proporciona explícitamente. Sin embargo, esto genera algunos gastos generales y es propenso a fugas de bloqueos e identificadores de transacciones si su aplicación no es escrupulosa al realizar un seguimiento de ellos. Es una solución mucho más pesada.
Preocupado por
22
@supercat: no acepte que el bloqueo optimista es menos del 100% preciso, siempre que verifique todos los registros de entrada para la transacción que no se modifique durante el tiempo, es tan preciso como el bloqueo pesimista (seleccione el estilo de actualización) en esos mismos registros La principal diferencia es que el bloqueo optimista incurre en gastos generales solo si hay un conflicto, mientras que el bloqueo pesimista ha reducido los gastos generales en el conflicto. Tan optimista es mejor en el caso de que la mayoría de las transacciones no entren en conflicto, lo que espero sea el caso para la mayoría de las aplicaciones.
RichVel
2
@Legends: el uso del bloqueo optimsitic sin duda sería una estrategia adecuada para una aplicación web.
ConcernedOfTunbridgeWells
2
Debe mencionar que la elección depende también de la relación lectura / escritura: si su aplicación es principalmente una aplicación de solo lectura por muchos usuarios, y algunas veces usted escribe datos, entonces elija un bloqueo optimista. StackOverflow, por ejemplo, tiene mucha gente leyendo páginas, y a veces alguien edita una: en un bloqueo pesimista, ¿quién obtendría el bloqueo? ¿el primero? En el bloqueo optimista, la persona que desea editar la página puede hacerlo siempre que tenga la última versión de la misma.
jehon
177

El bloqueo optimista se utiliza cuando no se esperan muchas colisiones. Hacer una operación normal cuesta menos, pero si se produce la colisión, pagaría un precio más alto para resolverla a medida que se anula la transacción.

El bloqueo pesimista se usa cuando se anticipa una colisión. Las transacciones que violarían la sincronización simplemente están bloqueadas.

Para seleccionar el mecanismo de bloqueo adecuado, debe estimar la cantidad de lecturas y escrituras y planificar en consecuencia.

Ilya Kochetov
fuente
En el caso normal, la declaración es perfecta, pero en casos especiales en los que podría administrar la operación CAS permitiendo la inexactitud como @skaffman mencionó en la respuesta, diría que eso realmente depende.
Hearen
75

Optimistic asume que nada va a cambiar mientras lo estás leyendo.

Pesimista asume que algo lo hará y así lo bloquea.

Si no es esencial que los datos se lean perfectamente, utilice optimista. Es posible que obtenga una lectura 'sucia' extraña, pero es mucho menos probable que produzca puntos muertos y similares.

La mayoría de las aplicaciones web están bien con lecturas sucias: en la rara ocasión los datos no coinciden exactamente con la próxima recarga.

Para operaciones de datos exactas (como en muchas transacciones financieras) use pesimista. Es esencial que los datos se lean con precisión, sin cambios no mostrados; la sobrecarga de bloqueo adicional lo vale.

Ah, y el servidor Microsoft SQL predeterminado es el bloqueo de página, básicamente la fila que está leyendo y algunas a cada lado. El bloqueo de fila es más preciso pero mucho más lento. A menudo vale la pena configurar sus transacciones para lectura comprometida o sin bloqueo para evitar puntos muertos mientras lee.

Keith
fuente
JPA Optimistic Locking le permite garantizar la consistencia de lectura.
Gili
44
La coherencia de lectura es una preocupación diferente: con PostgreSQL, Oracle y muchas otras bases de datos, obtendrá una vista coherente de los datos, independientemente de las actualizaciones que aún no se hayan confirmado, y que no se vean afectadas incluso por bloqueos de filas exclusivos.
RichVel
Tengo que estar de acuerdo con @RichVel. Por un lado, puedo ver cómo el bloqueo pesimista podría evitar lecturas sucias si su nivel de aislamiento de transacción se LEE SIN COMPROMISO. Pero es engañoso decir que el bloqueo optimista es susceptible a lecturas sucias sin mencionar que la mayoría de las bases de datos (incluido aparentemente el Servidor MS SQL) tienen un nivel de aislamiento predeterminado de "LEER COMPROMETIDO", que evita las lecturas sucias y hace que el bloqueo optimista sea tan preciso como pesimista.
antinome
Eric Brower dice que los banqueros, a diferencia de otros, prefieren las operaciones sucias. Tus gurús parecen absolutamente sin carros.
Little Alien
1
Eric Brewer es el gurú que dio el teorema de CAP dice sobre la consistencia en la banca . Es lo opuesto a lo que honras.
Little Alien
50

Además de lo que ya se ha dicho:

  • Debe decirse que el optimisticbloqueo tiende a mejorar la concurrencia a expensas de la previsibilidad.
  • Pessimisticel bloqueo tiende a reducir la concurrencia, pero es más predecible. Usted paga su dinero, etc.
skaffman
fuente
3
No veo cómo se mejora la previsibilidad (como quiera que la defina) con el bloqueo pesimista: si quiere decir 'la transacción puede completarse una vez que se toman los bloqueos', tiene razón, pero hasta que la transacción tenga todos los bloqueos requeridos, podría enfrentar un retraso para obtener bloqueos restantes, y de hecho podría ser abortado debido a la lógica de detección + resolución de punto muerto del DB. Las aplicaciones que usan bloqueo pesimista pueden tener tiempos de ejecución altamente impredecibles: el ejemplo clásico es que alguien bloquea un registro X y luego va a almorzar, luego un usuario bloquea el registro X e Y, luego otro Y y Z, y así hasta que la mayoría de los usuarios estén bloqueados. ..
RichVel
40

Cuando se trata de conflictos, tiene dos opciones:

  • Puede intentar evitar el conflicto, y eso es lo que hace el bloqueo pesimista.
  • O bien, puede permitir que ocurra el conflicto, pero debe detectarlo al confirmar sus transacciones, y eso es lo que hace Optimistic Locking.

Ahora, consideremos la siguiente anomalía de actualización perdida :

Actualización perdida

La anomalía de la actualización perdida puede ocurrir en el nivel de aislamiento de lectura comprometida .

En el diagrama de arriba podemos ver que Alice cree que puede retirar 40 de ella, accountpero no se da cuenta de que Bob acaba de cambiar el saldo de la cuenta, y ahora solo quedan 20 en esta cuenta.

Bloqueo pesimista

El bloqueo pesimista logra este objetivo al tomar un bloqueo compartido o de lectura en la cuenta para evitar que Bob cambie la cuenta.

Bloqueo pesimista de actualización perdida

En el diagrama anterior, tanto Alice como Bob adquirirán un bloqueo de lectura en la accountfila de la tabla que ambos usuarios han leído. La base de datos adquiere estos bloqueos en SQL Server cuando utiliza lectura repetible o serializable.

Debido a que tanto Alice como Bob han leído el accountcon el valor PK de 1, ninguno de ellos puede cambiarlo hasta que un usuario libere el bloqueo de lectura. Esto se debe a que una operación de escritura requiere una adquisición de bloqueo de escritura / exclusiva, y los bloqueos compartidos / leídos evitan bloqueos de escritura / exclusivos.

Solo después de que Alice haya comprometido su transacción y se haya liberado el bloqueo de lectura en la accountfila, Bob UPDATEreanudará y aplicará el cambio. Hasta que Alice libere el bloqueo de lectura, la ACTUALIZACIÓN de Bob se bloquea.

Para obtener más detalles sobre cómo los marcos de acceso a datos utilizan el soporte de bloqueo pesimista de la base de datos subyacente, consulte este artículo .

Bloqueo optimista

El bloqueo optimista permite que ocurra el conflicto, pero lo detecta al aplicar la ACTUALIZACIÓN de Alice a medida que la versión ha cambiado.

Transacciones a nivel de aplicación

Esta vez, tenemos una versioncolumna adicional . La versioncolumna se incrementa cada vez que se ejecuta UPDATE o DELETE, y también se usa en la cláusula WHERE de las declaraciones UPDATE y DELETE. Para que esto funcione, necesitamos emitir SELECT y leer el actual versionantes de ejecutar UPDATE o DELETE, de lo contrario, no sabríamos qué valor de versión pasar a la cláusula WHERE o incrementar.

Para obtener más detalles sobre cómo los marcos de acceso a datos implementan un bloqueo optimista, consulte este artículo .

Transacciones a nivel de aplicación

Los sistemas de bases de datos relacionales han surgido a fines de los años 70 y principios de los 80, cuando un cliente, típicamente, se conectaba a una unidad central a través de un terminal. Es por eso que todavía vemos que los sistemas de bases de datos definen términos como la configuración de SESIÓN.

Hoy en día, a través de Internet, ya no ejecutamos lecturas y escrituras en el contexto de la misma transacción de base de datos, y ACID ya no es suficiente.

Por ejemplo, considere el siguiente caso de uso:

ingrese la descripción de la imagen aquí

Sin un bloqueo optimista, no hay forma de que esta actualización perdida se haya detectado incluso si las transacciones de la base de datos utilizaran Serializable. Esto se debe a que las lecturas y escrituras se ejecutan en solicitudes HTTP separadas, por lo tanto, en diferentes transacciones de la base de datos.

Por lo tanto, el bloqueo optimista puede ayudarlo a evitar Actualizaciones Perdidas incluso cuando utiliza transacciones a nivel de aplicación que también incorporan el tiempo de reflexión del usuario.

Para obtener más detalles sobre las transacciones lógicas o de nivel de aplicación, consulte este artículo .

Conclusión

El bloqueo optimista es una técnica muy útil, y funciona bien incluso cuando se usan niveles de aislamiento menos estrictos, como lectura confirmada, o cuando las lecturas y escrituras se ejecutan en transacciones de bases de datos posteriores.

La desventaja del bloqueo optimista es que el marco de acceso a datos desencadenará una reversión al capturar una OptimisticLockException, por lo tanto, perderá todo el trabajo que hemos realizado anteriormente en la transacción que se está ejecutando actualmente.

A mayor contención, más conflictos y mayores posibilidades de abortar las transacciones. Las reversiones pueden ser costosas para el sistema de base de datos, ya que necesita revertir todos los cambios pendientes actuales que pueden involucrar tanto las filas de la tabla como los registros de índice.

Por esta razón, el bloqueo pesimista puede ser más adecuado cuando los conflictos ocurren con frecuencia, ya que reduce la posibilidad de revertir las transacciones.

Vlad Mihalcea
fuente
¿Para qué escenarios sugeriría elegir OptimisticLocking y PessimisticLocking? ¿Depende de con qué frecuencia se produce una OptimisticLockException?
Stimpson Cat
1
Depende del caso de uso. A veces, el bloqueo optimista es la única solución (p. Ej., Transacciones de solicitudes múltiples). Otras veces, el bloqueo pesimista es la única solución (por ejemplo, bloqueos de aviso de PostgreSQL ). A veces, tienes que combinarlos, como es el caso PESSIMISTIC_FORCE_INCREMENT.
Vlad Mihalcea
22

Pensaría en un caso más cuando el bloqueo pesimista sería una mejor opción.

Para un bloqueo optimista, cada participante en la modificación de datos debe estar de acuerdo en usar este tipo de bloqueo. Pero si alguien modifica los datos sin preocuparse por la columna de versión, esto arruinará toda la idea del bloqueo optimista.

Nikolay
fuente
Las personas que intentan usar un bloqueo optimista y pesimista también pueden pisar los pies de los demás, por así decirlo. Imagine un escenario en el que una sesión optimista lee un registro y hace algunos cálculos mientras una sesión pesimista actualiza el registro, luego la sesión optimista regresa y actualiza el mismo registro sin notar ningún cambio realizado. Seleccione ... para la actualización solo funciona si cada sesión usa esa misma sintaxis.
lusional
Buena explicación, dame tu voto
Dulaj Kulathunga
15

Básicamente hay dos respuestas más populares. El primero básicamente dice

Optimistic necesita arquitecturas de tres niveles en las que no necesariamente mantenga una conexión a la base de datos para su sesión, mientras que el bloqueo pesimista es cuando bloquea el registro para su uso exclusivo hasta que haya terminado con él. Tiene una integridad mucho mejor que el bloqueo optimista, necesita una conexión directa a la base de datos.

Otra respuesta es

optimista (versionado) es más rápido debido a que no tiene bloqueo, pero el bloqueo (pesimista) funciona mejor cuando la contención es alta y es mejor evitar el trabajo en lugar de descartarlo y comenzar de nuevo.

o

El bloqueo optimista funciona mejor cuando tienes colisiones raras

Como se pone en esta página.

Creé mi respuesta para explicar cómo se relaciona "mantener conexión" con "colisiones bajas".

Para comprender qué estrategia es mejor para usted, no piense en las transacciones por segundo que tiene su base de datos, sino en la duración de una sola transacción. Normalmente, usted abre la operación de trasnación, performa y cierra la transacción. Esta es una transacción corta y clásica que ANSI tenía en mente y bien para salirse con la suya. Pero, ¿cómo implementa un sistema de reserva de boletos donde muchos clientes reserven las mismas habitaciones / asientos al mismo tiempo?

Explore las ofertas, complete el formulario con muchas opciones disponibles y precios actuales. Lleva mucho tiempo y las opciones pueden volverse obsoletas, todos los precios no válidos entre usted comenzaron a llenar el formulario y presionaron el botón "Acepto" porque no había ningún bloqueo en los datos a los que accedieron y alguien más, más ágil, intervino cambiando todos los precios y necesita reiniciar con nuevos precios.

En su lugar, puede bloquear todas las opciones a medida que las lee. Este es un escenario pesimista. Ya ves por qué apesta. Su sistema puede ser derribado por un solo payaso que simplemente inicia una reserva y deja de fumar. Nadie puede reservar nada antes de que termine. Su flujo de caja cae a cero. Por eso, las reservas optimistas se utilizan en la realidad. Aquellos que se demoran demasiado tienen que reiniciar su reserva a precios más altos.

En este enfoque optimista, debe registrar todos los datos que lee (como en la lectura repetida mía ) y llegar al punto de confirmación con su versión de datos (quiero comprar acciones al precio que mostró en esta cotización, no al precio actual ) En este punto, se crea la transacción ANSI, que bloquea la base de datos, verifica si no se ha cambiado nada y confirma / cancela su operación. En mi opinión, esta es una emulación efectiva de MVCC , que también está asociada con Optimistic CC y también supone que su transacción se reinicia en caso de cancelación, es decir, hará una nueva reserva. Una transacción aquí implica decisiones de un usuario humano.

Estoy lejos de comprender cómo implementar el MVCC manualmente, pero creo que las transacciones de larga duración con opción de reinicio son la clave para comprender el tema. Corrígeme si me equivoco en alguna parte. Mi respuesta fue motivada por este capítulo de Alex Kuznecov .

Pequeño alien
fuente
12

En la mayoría de los casos, el bloqueo optimista es más eficiente y ofrece un mayor rendimiento. Al elegir entre un bloqueo pesimista y optimista, tenga en cuenta lo siguiente:

  • El bloqueo pesimista es útil si hay muchas actualizaciones y posibilidades relativamente altas de que los usuarios intenten actualizar los datos al mismo tiempo. Por ejemplo, si cada operación puede actualizar una gran cantidad de registros a la vez (el banco puede agregar ganancias de intereses a cada cuenta al final de cada mes), y dos aplicaciones ejecutan tales operaciones al mismo tiempo, tendrán conflictos .

  • El bloqueo pesimista también es más apropiado en aplicaciones que contienen tablas pequeñas que se actualizan con frecuencia. En el caso de estos llamados puntos calientes, los conflictos son tan probables que el bloqueo optimista desperdicia el esfuerzo en revertir las transacciones en conflicto.

  • El bloqueo optimista es útil si la posibilidad de conflictos es muy baja: hay muchos registros pero relativamente pocos usuarios, o muy pocas actualizaciones y principalmente operaciones de tipo lectura.

Koenigsegg
fuente
3

Un caso de uso para el bloqueo optimista es hacer que su aplicación use la base de datos para permitir que uno de sus hilos / hosts 'reclame' una tarea. Esta es una técnica que me ha sido útil regularmente.

El mejor ejemplo que se me ocurre es para una cola de tareas implementada usando una base de datos, con múltiples hilos que reclaman tareas simultáneamente. Si una tarea tiene el estado 'Disponible', 'Reclamado', 'Completado', una consulta de base de datos puede decir algo como "Establecer estado = 'Reclamado' donde estado = 'Disponible'. Si varios hilos intentan cambiar el estado de esta manera, todos menos el primer hilo fallarán debido a datos sucios.

Tenga en cuenta que este es un caso de uso que implica solo un bloqueo optimista. Entonces, como alternativa a decir "El bloqueo optimista se usa cuando no se esperan muchas colisiones", también se puede usar donde se esperan colisiones pero se desea que una transacción tenga éxito.

Campamento de Charlie
fuente
3

Se han dicho muchas cosas buenas sobre el bloqueo optimista y pesimista. Un punto importante a considerar es el siguiente:

Cuando se utiliza el bloqueo optimista, debemos tener cuidado con el hecho de que la aplicación se recuperará de estas fallas.

Especialmente en arquitecturas controladas por mensajes asíncronos, esto puede conducir a un procesamiento de mensajes fuera de servicio o actualizaciones perdidas.

Los escenarios de fallas deben ser pensados.

Abhishek Shinde
fuente