¡Un crítico desde lo más profundo del alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Supongamos que existe un negocio de este tipo ahora. Algunos datos obtenidos por los usuarios provienen de la información de la interfaz de terceros. Para evitar solicitudes frecuentes de interfaces de terceros, a menudo agregamos una capa de caché. La caché debe ser sensible al tiempo. Suponiendo que la estructura que queremos almacenar es hash (No hay operación atómica como 'SET anotherkey' expirará en un minuto 'EX 60' de String), tenemos que ponerlo en la caché por lotes, y también asegurarnos de que cada clave se agregue con un tiempo de expiración (en caso de que la clave nunca expire ), esta vez la operación de transacción es una mejor opción.

Para garantizar la atomicidad de múltiples operaciones consecutivas, todas nuestras bases de datos de uso común tendrán soporte para transacciones, y Redis no es una excepción. Pero no es lo mismo que una base de datos relacional.

Cada operación de transacción tiene inicio, confirmación y reversión, comenzar indica el comienzo de la transacción, confirmación indica la confirmación de la transacción y reversión indica la reversión de la transacción. Su forma aproximada es la siguiente

 

begin();try {    command1();    command2();    ....    commit();} catch(Exception e) {    rollback();}

Redis tiene una forma similar, dividida en tres etapas

  1. Transacción abierta (múltiple)
  2. Cola de comandos (operación comercial)
  3. Ejecutar transacción (ejecutivo) o cancelar transacción (descartar)

 

> multiOK> incr starQUEUED> incr starQUEUED> exec(integer) 1(integer) 2

La instrucción anterior demuestra un proceso de transacción completo. Todas las instrucciones no se ejecutan antes de la ejecución, sino que se almacenan en la memoria caché en una cola de transacciones del servidor. Una vez que el servidor recibe la instrucción ejecutiva, toda la cola de transacciones se desensamblará y ejecutará, y una vez ejecutada Devuelve los resultados de todas las instrucciones.

Las transacciones de Redis pueden ejecutar varios comandos a la vez y son esencialmente una colección de comandos. Todos los comandos de una transacción se serializarán, serializarán y ejecutarán en orden sin ser insertados por otros comandos, y no se permiten interferencias.

Puede garantizar que una serie de comandos se ejecuten de una manera única, secuencial y exclusiva en una cola (la función principal de las transacciones de Redis es en realidad encadenar múltiples comandos para evitar que otros comandos salten en la cola)

El documento oficial lo dice

Una transacción puede ejecutar varios comandos a la vez, con las siguientes dos importantes garantías:

La transacción es una operación aislada separada: todos los comandos de la transacción se serializan y ejecutan secuencialmente. Durante la ejecución de la transacción, no será interrumpida por solicitudes de comando enviadas por otros clientes. Una transacción es una operación atómica: todos los comandos de la transacción se ejecutan o no se ejecutan

Esta operación atómica no es lo mismo que la atomicidad de la base de datos relacional, no puede garantizar completamente la atomicidad, que será introducida más adelante.

Varios comandos para transacciones de Redis

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

El comando MULTI se usa para iniciar una transacción y siempre devuelve OK.

Después de ejecutar MULTI, el cliente puede continuar enviando cualquier número de comandos al servidor. Estos comandos no se ejecutarán inmediatamente, sino que se colocarán en una cola. Cuando se llame al comando EXEC, se ejecutarán todos los comandos en la cola.

Por otro lado, al llamar a DISCARD, el cliente puede borrar la cola de transacciones y dejar de ejecutar la transacción.

No digas demasiadas tonterías, es mejor entender los resultados directamente al operarlo ~

Viento en popa

Ejecución normal (el procesamiento por lotes es posible, muy bueno, cada operación tomará lo que necesita si tiene éxito, sin afectarse entre sí)

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Abandonar la transacción (descartar la operación significa abandonar la transacción, las operaciones anteriores no cuentan)

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Considere una pregunta: suponga que tenemos una clave con un tiempo de vencimiento y la clave falla durante las operaciones de transacción, ¿tendrá éxito al ejecutar exec?

Error en la transacción

Las operaciones regulares anteriores se ven bastante bien, pero las transacciones se proponen para resolver operaciones de seguridad de datos.Cuando usamos transacciones de Redis, podemos encontrar los siguientes dos errores:

  • Antes de que la transacción ejecute EXEC, el comando en cola puede ser incorrecto. Por ejemplo, el comando puede generar errores de sintaxis (número incorrecto de parámetros, nombres de parámetros incorrectos, etc.) u otros errores más graves, como memoria insuficiente (si el servidor usa maxmemory para establecer el límite máximo de memoria).
  • El comando puede fallar después de llamar a EXEC. Por ejemplo, el comando en la transacción puede manejar el tipo incorrecto de clave, como usar el comando list en la clave de cadena, y así sucesivamente.

Redis adopta diferentes estrategias de procesamiento para los dos errores anteriores. Para los errores que ocurren antes de la ejecución de EXEC, el servidor registrará la falla del comando en cola, y cuando el cliente llame al comando EXEC, se negará a ejecutar y abandonará automáticamente la transacción. (El método anterior a Redis 2.6.5 era verificar el valor de retorno del comando poner en cola: si el comando devuelve QUEUED cuando se pone en cola, entonces la puesta en cola es exitosa; de lo contrario, la puesta en cola falla)

Para aquellos errores que se generan después de la ejecución del comando EXEC, no se les da un tratamiento especial: incluso si ocurre un error durante la ejecución de un comando determinado / determinado en la transacción, otros comandos en la transacción continuarán ejecutándose.

Todos se sientan en una fila (si se informa un error en un registro de operación, todas las operaciones posteriores a la ejecución no tendrán éxito)

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

El acusador (en el ejemplo, k1 se establece en el tipo String, decr k1 se puede colocar en la cola de operaciones, porque solo cuando se ejecuta se puede juzgar que la declaración es incorrecta y otras correctas se ejecutarán normalmente)

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

¿Por qué Redis no admite la reversión?

Si tiene experiencia con bases de datos relacionales, la práctica de "Redis no se revierte cuando falla la transacción, pero continúa ejecutando los comandos restantes" puede hacerle sentir un poco extraño.

El siguiente es el alarde oficial :

Los comandos de Redis solo fallarán debido a una sintaxis incorrecta (y estos problemas no se pueden encontrar al poner en cola), o el comando se usa en el tipo de clave incorrecto: es decir, desde un punto de vista práctico, el comando fallido Es causado por errores de programación y estos errores deben encontrarse en el proceso de desarrollo y no deben aparecer en el entorno de producción. Debido a que no es necesario admitir reversiones, los componentes internos de Redis se pueden mantener simples y rápidos.

Existe la opinión de que las prácticas de procesamiento de transacciones de Redis producirán errores, sin embargo, debe tenerse en cuenta que, en circunstancias normales, las reversiones no pueden resolver los problemas causados ​​por errores de programación. Por ejemplo, si originalmente deseaba agregar 1 al valor de la clave mediante el comando INCR, pero accidentalmente agregó 2, o ejecutó INCR para el tipo de clave incorrecto, no hay forma de manejar estas situaciones con reversión.

En vista del hecho de que no existe un mecanismo para evitar errores causados ​​por los propios programadores, y tales errores generalmente no aparecen en el entorno de producción, Redis eligió una forma más simple y rápida de manejar las transacciones sin reversión.

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Transacción con Watch

El comando WATCH se usa para monitorear cualquier número de claves antes de que comience la transacción: Cuando se llama al comando EXEC para ejecutar la transacción, si cualquier clave monitoreada ha sido modificada por otros clientes, toda la transacción será interrumpida y ya no se ejecutará, directamente. Devolución fallida.

El comando WATCH se puede llamar varias veces. La monitorización de las claves tendrá efecto después de que se ejecute WATCH, hasta que se llame a EXEC.

Los usuarios también pueden monitorear cualquier número de claves en un solo comando WATCH, como este:

 

redis> WATCH key1 key2 key3 OK 

Cuando se llama a EXEC, la supervisión de todas las claves se cancelará independientemente de si la transacción se ejecuta correctamente . Además, cuando el cliente se desconecte, también se cancelará el seguimiento de las claves por parte del cliente.

Veamos un ejemplo simple, use el reloj para controlar el saldo de mi cuenta (tengo 100 dinero de bolsillo a la semana) y gaste normalmente

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Pero esta tarjeta también está vinculada a Alipay de mi nuera. ¿Qué pasa si ella también consume mientras yo consumo?

Con sueño, bajé al 711 para comprar un paquete de cigarrillos y una botella de agua. En ese momento, mi nuera cepillaba 100 en el supermercado. En ese momento, todavía estaba recogiendo chicle cuando el saldo era insuficiente.

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

En este momento, fui a la caja y descubrí que la tarjeta de crédito falló (transacción interrumpida), un lote incómodo

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Es posible que no entiendas el uso del reloj. Veámoslo de nuevo. Si sigue siendo el mismo escenario, no tenemos saldo del reloj, la transacción no fallará y la tarjeta de ahorro se vuelve negativa. ¿No es adecuado para los negocios?

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

Utilice el comando UNWATCH sin parámetros para cancelar manualmente la supervisión de todas las claves. Para algunas transacciones que necesitan cambiar varias claves, a veces el programa necesita bloquear varias claves al mismo tiempo y luego verificar si los valores actuales de estas claves cumplen con los requisitos del programa. Cuando el valor no cumple con los requisitos, puede usar el comando UNWATCH para cancelar el monitoreo actual de la clave, abandonar la transacción a la mitad y esperar el siguiente intento de la transacción.

La instrucción de observación es similar al bloqueo optimista . Cuando se confirma la transacción, si el valor de la clave ha sido cambiado por otro cliente, por ejemplo, otro cliente ha empujado / desplegado una lista, no se ejecutará toda la cola de transacciones. (Por supuesto, Redis también se puede usar para implementar bloqueos distribuidos para garantizar la seguridad, que es un bloqueo pesimista)

Se monitorean varias claves antes de que se ejecute la transacción a través del comando watch. Si algún valor de clave cambia después de la observación, la transacción ejecutada por el comando exec se abandonará y se devolverá una respuesta nula para notificar a la persona que llama que la transacción falló.

Bloqueo pesimista

Pessimistic Lock, como su nombre indica, es muy pesimista. Cada vez que obtienes datos, piensas que otros los modificarán, por lo que cada vez que obtengas los datos, los bloquearás, de modo que si alguien quiere obtener los datos, los bloqueará hasta que los obtenga. A la cerradura. Muchos de estos mecanismos de bloqueo se utilizan en bases de datos relacionales tradicionales, como bloqueos de filas, bloqueos de tablas, etc., bloqueos de lectura, bloqueos de escritura, etc., todos los cuales se bloquean antes de realizar operaciones.

Bloqueo de **** optimista

Optimistic Lock (Optimistic Lock), como su nombre indica, es muy optimista. Cada vez que obtengo los datos, creo que otros no los modificarán, por lo que no se bloqueará, pero al actualizar, juzgará si otros lo han actualizado durante este período. Para los datos, se pueden utilizar mecanismos como los números de versión. El bloqueo optimista es adecuado para tipos de aplicaciones de lectura múltiple, lo que puede mejorar el rendimiento. Estrategia de bloqueo optimista: la versión enviada debe ser mayor que la versión actual del registro para realizar la actualización

El principio de realización del comando WATCH

En el tipo de estructura server.h / redisDb que representa la base de datos, se almacena un diccionariowatch_keys. La clave del diccionario es la clave monitoreada de la base de datos y el valor del diccionario es una lista vinculada. La lista vinculada almacena todos los clientes que monitorean esta clave. ,Como se muestra abajo.

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

 

typedef struct redisDb {    dict *dict;                 /* The keyspace for this DB */    dict *expires;              /* Timeout of keys with a timeout set */    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/    dict *ready_keys;           /* Blocked keys that received a PUSH */    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */    int id;                     /* Database ID */    long long avg_ttl;          /* Average TTL, just for stats */    unsigned long expires_cursor; /* Cursor of the active expire cycle. */    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */} redisDb;list *watched_keys;     /* Keys WATCHED for MULTI/EXEC CAS */

La función del comando WATCH es asociar el cliente actual con la clave a monitorear en watch_keys.

Por ejemplo, si el cliente actual es client99, entonces, cuando el cliente ejecute WATCH key2 key3, las watch_keys que se muestran arriba se modificarán para tener este aspecto:

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

A través del diccionariowatch_keys, si el programa quiere verificar si una clave está monitoreada, solo necesita verificar si la clave existe en el diccionario; si el programa quiere obtener todos los clientes que monitorean una clave, entonces simplemente saque el valor de la clave (una lista vinculada). ) y luego recorra la lista vinculada.

Después de que cualquier comando para modificar el espacio clave de la base de datos se ejecute con éxito (como FLUSHDB, SET, DEL, LPUSH, SADD, etc.), se llamará a la función multi.c / touchWatchedKey; irá al diccionariowatch_keys, consulte ¿Existe un cliente monitoreando la clave que ha sido modificada por el comando? Si es así, el programa activa la opción REDIS_DIRTY_CAS de todos los clientes que monitorean esta / estas claves modificadas:

Golpe de alma! ¿Las transacciones de Redis que no admiten la atomicidad también se denominan transacciones?

 

void multiCommand(client *c) {    // 不能在事务中嵌套事务    if (c->flags & CLIENT_MULTI) {        addReplyError(c,"MULTI calls can not be nested");        return;    }    // 打开事务 FLAG    c->flags |= CLIENT_MULTI;    addReply(c,shared.ok);}/* "Touch" a key, so that if this key is being WATCHed by some client the * next EXEC will fail. */void touchWatchedKey(redisDb *db, robj *key) {    list *clients;    listIter li;    listNode *ln;    // 字典为空,没有任何键被监视    if (dictSize(db->watched_keys) == 0) return;    // 获取所有监视这个键的客户端    clients = dictFetchValue(db->watched_keys, key);    if (!clients) return;    // 遍历所有客户端,打开他们的 CLIENT_DIRTY_CAS 标识    listRewind(clients,&li);    while((ln = listNext(&li))) {        client *c = listNodeValue(ln);        c->flags |= CLIENT_DIRTY_CAS;    }}

Cuando el cliente envía un comando EXEC para desencadenar la ejecución de la transacción, el servidor verifica el estado del cliente:

  • Si se ha activado la opción CLIENT_DIRTY_CAS del cliente, significa que se ha modificado al menos una clave supervisada por el cliente y se ha destruido la seguridad de la transacción. El servidor abandonará la ejecución de esta transacción y devolverá directamente una respuesta vacía al cliente, indicando que la ejecución de la transacción ha fallado.
  • Si la opción CLIENT_DIRTY_CAS no está activada, entonces todas las claves de monitoreo están seguras y el servidor ejecuta oficialmente la transacción.

Pequeño resumen:

3 etapas

  • Abrir: iniciar una transacción con MULTI
  • Poner en cola: poner en cola varios comandos en la transacción. Estos comandos no se ejecutarán inmediatamente después de recibirlos, sino que se colocarán en la cola de transacciones a la espera de ser ejecutados.
  • Ejecución: la transacción se activa mediante el comando EXEC

3 funciones

  • Operación de aislamiento separada: todos los comandos de la transacción se serializarán y ejecutarán en orden. Durante la ejecución de la transacción, no será interrumpida por solicitudes de comando enviadas por otros clientes.
  • No existe un concepto de nivel de aislamiento : los comandos en la cola no se ejecutarán realmente antes de que se envíen, porque las instrucciones no se ejecutarán realmente antes de que se envíe la transacción, y no hay una "consulta dentro de la transacción para ver la actualización en la transacción". , La consulta no se puede ver fuera de la transacción "este es un problema muy doloroso
  • La atomicidad no está garantizada: si un comando no se ejecuta en la misma transacción en Redis, los comandos subsiguientes se ejecutarán sin retroceso

En las bases de datos relacionales tradicionales, las propiedades ACID se utilizan a menudo para probar la seguridad de las funciones de transacción. Las transacciones de Redis garantizan la coherencia (C) y el aislamiento (I), pero no garantizan la atomicidad (A) y la durabilidad (D).

Al final

Las transacciones de Redis deben pasar por una lectura y escritura de red al enviar cada instrucción a la cola de caché de transacciones.Cuando hay muchas instrucciones en una transacción, el tiempo de E / S de red requerido también aumentará linealmente. Por lo tanto, por lo general, los clientes de Redis se utilizarán junto con las canalizaciones al ejecutar transacciones, de modo que se puedan comprimir varias operaciones de IO en una sola operación de IO.

 

Supongo que te gusta

Origin blog.csdn.net/yunduo1/article/details/108714884
Recomendado
Clasificación