redis事物详解

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: redis事物详解 Redis 通过 MULTI 、 DISCARD 、 EXEC 和 WATCH 四个命令来实现事务功能, 本章首先讨论使用 MULTI 、 DISCARD 和 EXEC 三个命令实现的一般事务, 然后再来讨论带有 WATCH 的事务的实现。

redis事物详解

Redis 通过 MULTI 、 DISCARD 、 EXEC 和 WATCH 四个命令来实现事务功能, 本章首先讨论使用 MULTI 、 DISCARD 和 EXEC 三个命令实现的一般事务, 然后再来讨论带有 WATCH 的事务的实现。

因为事务的安全性也非常重要, 所以本章最后通过常见的 ACID 性质对 Redis 事务的安全性进行了说明。

事务

事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。

以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

redis> MULTI
OK

redis> SET book-name "Mastering C++ in 21 days"
QUEUED

redis> GET book-name
QUEUED

redis> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis> SMEMBERS tag
QUEUED

redis> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

一个事务从开始到执行会经历以下三个阶段:

  1. 开始事务。
  2. 命令入队。
  3. 执行事务。

下文将分别介绍事务的这三个阶段。

开始事务

MULTI 命令的执行标记着事务的开始:

redis> MULTI
OK

这个命令唯一做的就是, 将客户端的 REDIS_MULTI 选项打开, 让客户端从非事务状态切换到事务状态。

digraph normal_to_transaction {      rankdir = LR;      node [shape = circle, style = filled];      edge [style = bold];      label = "客户端状态的切换";      normal [label = "非事务状态", fillcolor = "#FADCAD"];      transaction [label = "事务状态", fillcolor = "#A8E270"];      normal -> transaction [label = "打开选项\nREDIS_MULTI"]; }

命令入队

当客户端处于非事务状态下时, 所有发送给服务器端的命令都会立即被服务器执行:

redis> SET msg "hello moto"
OK

redis> GET msg
"hello moto"

但是, 当客户端进入事务状态之后, 服务器在收到来自客户端的命令时, 不会立即执行命令, 而是将这些命令全部放进一个事务队列里, 然后返回 QUEUED , 表示命令已入队:

redis> MULTI
OK

redis> SET msg "hello moto"
QUEUED

redis> GET msg
QUEUED

以下流程图展示了这一行为:

digraph enqueue {      node [shape = plaintext, style = filled];      edge [style = bold];      command_in [label = "服务器接到来自客户端的命令"];      in_transaction_or_not [label = "客户端是否正处于事务状态?", shape = diamond, fillcolor = "#95BBE3"];      enqueu_command [label = "将命令放进事务队列里", fillcolor = "#A8E270"];      return_enqueued [label = "向客户端返回 QUEUED 字符串\n表示命令已入队", fillcolor = "#A8E270"];      exec_command [label = "执行命令", fillcolor = "#FADCAD"];      return_command_result [label = "向客户端返回命令的执行结果", fillcolor = "#FADCAD"];      //       command_in -> in_transaction_or_not;      in_transaction_or_not -> enqueu_command [label = "是"];      in_transaction_or_not -> exec_command [label = "否"];      exec_command -> return_command_result;      enqueu_command -> return_enqueued; }

事务队列是一个数组, 每个数组项是都包含三个属性:

  1. 要执行的命令(cmd)。
  2. 命令的参数(argv)。
  3. 参数的个数(argc)。

举个例子, 如果客户端执行以下命令:

redis> MULTI
OK

redis> SET book-name "Mastering C++ in 21 days"
QUEUED

redis> GET book-name
QUEUED

redis> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis> SMEMBERS tag
QUEUED

那么程序将为客户端创建以下事务队列:

数组索引 cmd argv argc
0 SET ["book-name", "Mastering C++ in 21 days"] 2
1 GET ["book-name"] 1
2 SADD ["tag", "C++", "Programming", "Mastering Series"] 4
3 SMEMBERS ["tag"] 1

执行事务

前面说到, 当客户端进入事务状态之后, 客户端发送的命令就会被放进事务队列里。

但其实并不是所有的命令都会被放进事务队列, 其中的例外就是 EXEC 、 DISCARD 、 MULTI 和 WATCH 这四个命令 —— 当这四个命令从客户端发送到服务器时, 它们会像客户端处于非事务状态一样, 直接被服务器执行:

digraph not_enque_command {      node [shape = plaintext, style = filled];      edge [style = bold];      command_in [label = "服务器接到来自客户端的命令"];      in_transaction_or_not [label = "客户端是否正处于事务状态?", shape = diamond, fillcolor = "#95BBE3"];      not_exec_and_discard [label = "命令是否\nEXEC 、 DISCARD 、\nMULTI 或 WATCH ?", shape = diamond, fillcolor = "#FFC1C1"];      enqueu_command [label = "将命令放进事务队列里", fillcolor = "#A8E270"];      return_enqueued [label = "向客户端返回 QUEUED 字符串\n表示命令已入队", fillcolor = "#A8E270"];      exec_command [label = "执行命令", fillcolor = "#FADCAD"];      return_command_result [label = "向客户端返回命令的执行结果", fillcolor = "#FADCAD"];      //       command_in -> in_transaction_or_not;      in_transaction_or_not -> not_exec_and_discard [label = "是"];      not_exec_and_discard -> enqueu_command [label = "否"];      not_exec_and_discard -> exec_command [label = "是"];      in_transaction_or_not -> exec_command [label = "否"];      exec_command -> return_command_result;      enqueu_command -> return_enqueued; }

如果客户端正处于事务状态, 那么当 EXEC 命令执行时, 服务器根据客户端所保存的事务队列, 以先进先出(FIFO)的方式执行事务队列中的命令: 最先入队的命令最先执行, 而最后入队的命令最后执行。

比如说,对于以下事务队列:

数组索引 cmd argv argc
0 SET ["book-name", "Mastering C++ in 21 days"] 2
1 GET ["book-name"] 1
2 SADD ["tag", "C++", "Programming", "Mastering Series"] 4
3 SMEMBERS ["tag"] 1

程序会首先执行 SET 命令, 然后执行 GET 命令, 再然后执行 SADD 命令, 最后执行 SMEMBERS 命令。

执行事务中的命令所得的结果会以 FIFO 的顺序保存到一个回复队列中。

比如说,对于上面给出的事务队列,程序将为队列中的命令创建如下回复队列:

数组索引 回复类型 回复内容
0 status code reply OK
1 bulk reply "Mastering C++ in 21 days"
2 integer reply 3
3 multi-bulk reply ["Mastering Series", "C++", "Programming"]

当事务队列里的所有命令被执行完之后, EXEC 命令会将回复队列作为自己的执行结果返回给客户端, 客户端从事务状态返回到非事务状态, 至此, 事务执行完毕。

事务的整个执行过程可以用以下伪代码表示:

def execute_transaction():

    # 创建空白的回复队列
    reply_queue = []

    # 取出事务队列里的所有命令、参数和参数数量
    for cmd, argv, argc in client.transaction_queue:

        # 执行命令,并取得命令的返回值
        reply = execute_redis_command(cmd, argv, argc)

        # 将返回值追加到回复队列末尾
        reply_queue.append(reply)

    # 清除客户端的事务状态
    clear_transaction_state(client)

    # 清空事务队列
    clear_transaction_queue(client)

    # 将事务的执行结果返回给客户端
    send_reply_to_client(client, reply_queue)

在事务和非事务状态下执行命令

无论在事务状态下, 还是在非事务状态下, Redis 命令都由同一个函数执行, 所以它们共享很多服务器的一般设置, 比如 AOF 的配置、RDB 的配置,以及内存限制,等等。

不过事务中的命令和普通命令在执行上还是有一点区别的,其中最重要的两点是:

  1. 非事务状态下的命令以单个命令为单位执行,前一个命令和后一个命令的客户端不一定是同一个;

    而事务状态则是以一个事务为单位,执行事务队列中的所有命令:除非当前事务执行完毕,否则服务器不会中断事务,也不会执行其他客户端的其他命令。

  2. 在非事务状态下,执行命令所得的结果会立即被返回给客户端;

    而事务则是将所有命令的结果集合到回复队列,再作为 EXEC 命令的结果返回给客户端。

事务状态下的 DISCARD 、 MULTI 和 WATCH 命令

除了 EXEC 之外, 服务器在客户端处于事务状态时, 不加入到事务队列而直接执行的另外三个命令是 DISCARD 、 MULTI 和 WATCH 。

DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消。

Redis 的事务是不可嵌套的, 当客户端已经处于事务状态, 而客户端又再向服务器发送 MULTI 时, 服务器只是简单地向客户端发送一个错误, 然后继续等待其他命令的入队。 MULTI 命令的发送不会造成整个事务失败, 也不会修改事务队列中已有的数据。

WATCH 只能在客户端进入事务状态之前执行, 在事务状态下发送 WATCH 命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据(和前面处理 MULTI 的情况一样)。

带 WATCH 的事务

WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。

以下示例展示了一个执行失败的事务例子:

redis> WATCH name
OK

redis> MULTI
OK

redis> SET name peter
QUEUED

redis> EXEC
(nil)

以下执行序列展示了上面的例子是如何失败的:

时间 客户端 A 客户端 B
T1 WATCH name  
T2 MULTI  
T3 SET name peter  
T4   SET name john
T5 EXEC  

在时间 T4 ,客户端 B 修改了 name 键的值, 当客户端 A 在 T5 执行 EXEC 时,Redis 会发现 name 这个被监视的键已经被修改, 因此客户端 A 的事务不会被执行,而是直接返回失败。

下文就来介绍 WATCH 的实现机制,并且看看事务系统是如何检查某个被监视的键是否被修改,从而保证事务的安全性的。

WATCH 命令的实现

在每个代表数据库的 redis.h/redisDb 结构类型中, 都保存了一个 watched_keys 字典, 字典的键是这个数据库被监视的键, 而字典的值则是一个链表, 链表中保存了所有监视这个键的客户端。

比如说,以下字典就展示了一个 watched_keys 字典的例子:

digraph watched_keys {      rankdir = LR;      node [shape = record, style = filled];      edge [style = bold];      // keys      watched_keys [label = "watched_keys |<key1> key1 |<key2> key2 |<key3> key3 | ... |<keyN> keyN", fillcolor = "#A8E270"];      // clients blocking for key1     client1 [label = "client1", fillcolor = "#95BBE3"];     client5 [label = "client5", fillcolor = "#95BBE3"];     client2 [label = "client2", fillcolor = "#95BBE3"];     null_1 [label = "NULL", shape = plaintext];          watched_keys:key1 -> client2;     client2 -> client5;     client5 -> client1;     client1 -> null_1;      // clients blocking for key2     client7 [label = "client7", fillcolor = "#95BBE3"];     null_2 [label = "NULL", shape = plaintext];      watched_keys:key2 -> client7;     client7 -> null_2;      // key3      client3 [label = "client3", fillcolor = "#95BBE3"];     client4 [label = "client4", fillcolor = "#95BBE3"];     client6 [label = "client6", fillcolor = "#95BBE3"];     null_3 [label = "NULL", shape = plaintext];      watched_keys:key3 -> client3;     client3 -> client4;     client4 -> client6;     client6 -> null_3; }

其中, 键 key1 正在被 client2 、 client5 和 client1 三个客户端监视, 其他一些键也分别被其他别的客户端监视着。

WATCH 命令的作用, 就是将当前客户端和要监视的键在 watched_keys 中进行关联。

举个例子, 如果当前客户端为 client10086 , 那么当客户端执行 WATCH key1 key2 时, 前面展示的 watched_keys 将被修改成这个样子:

digraph new_watched_keys {      rankdir = LR;      node [shape = record, style = filled];      edge [style = bold];      // keys      watched_keys [label = "watched_keys |<key1> key1 |<key2> key2 |<key3> key3 | ... |<keyN> keyN", fillcolor = "#A8E270"];      // clients blocking for key1     client1 [label = "client1", fillcolor = "#95BBE3"];     client5 [label = "client5", fillcolor = "#95BBE3"];     client2 [label = "client2", fillcolor = "#95BBE3"];     client10086 [label = "client10086", fillcolor = "#FFC1C1"];     null_1 [label = "NULL", shape = plaintext];          watched_keys:key1 -> client2;     client2 -> client5;     client5 -> client1;     client1 -> client10086;     client10086 -> null_1;      // clients blocking for key2     client7 [label = "client7", fillcolor = "#95BBE3"];     client10086_2 [label = "client10086", fillcolor = "#FFC1C1"];     null_2 [label = "NULL", shape = plaintext];      watched_keys:key2 -> client7;     client7 -> client10086_2;     client10086_2 -> null_2;      // key3      client3 [label = "client3", fillcolor = "#95BBE3"];     client4 [label = "client4", fillcolor = "#95BBE3"];     client6 [label = "client6", fillcolor = "#95BBE3"];     null_3 [label = "NULL", shape = plaintext];      watched_keys:key3 -> client3;     client3 -> client4;     client4 -> client6;     client6 -> null_3; }

通过 watched_keys 字典, 如果程序想检查某个键是否被监视, 那么它只要检查字典中是否存在这个键即可; 如果程序要获取监视某个键的所有客户端, 那么只要取出键的值(一个链表), 然后对链表进行遍历即可。

WATCH 的触发

在任何对数据库键空间(key space)进行修改的命令成功执行之后 (比如 FLUSHDB 、 SET 、 DEL 、 LPUSH 、 SADD 、 ZREM ,诸如此类), multi.c/touchWatchedKey 函数都会被调用 —— 它检查数据库的 watched_keys 字典, 看是否有客户端在监视已经被命令修改的键, 如果有的话, 程序将所有监视这个/这些被修改键的客户端的 REDIS_DIRTY_CAS 选项打开:

digraph dirty_cas {      rankdir = LR;      node [shape = circle, style = filled];      edge [style = bold];      label = "客户端状态的切换";      normal [label = "非事务状态", fillcolor = "#FADCAD"];      transaction [label = "事务状态", fillcolor = "#A8E270"];      dirty_cas [label = "事务安全性\n已被破坏", fillcolor = "#B22222"];      normal -> transaction [label = "打开选项\nREDIS_MULTI"];      transaction -> dirty_cas [label = "打开选项\nREDIS_DIRTY_CAS"]; }

当客户端发送 EXEC 命令、触发事务执行时, 服务器会对客户端的状态进行检查:

  • 如果客户端的 REDIS_DIRTY_CAS 选项已经被打开,那么说明被客户端监视的键至少有一个已经被修改了,事务的安全性已经被破坏。服务器会放弃执行这个事务,直接向客户端返回空回复,表示事务执行失败。
  • 如果 REDIS_DIRTY_CAS 选项没有被打开,那么说明所有监视键都安全,服务器正式执行事务。

可以用一段伪代码来表示这个检查:

def check_safety_before_execute_trasaction():

    if client.state & REDIS_DIRTY_CAS:
        # 安全性已破坏,清除事务状态
        clear_transaction_state(client)
        # 清空事务队列
        clear_transaction_queue(client)
        # 返回空回复给客户端
        send_empty_reply(client)
    else:
        # 安全性完好,执行事务
        execute_transaction()

举个例子,假设数据库的 watched_keys 字典如下图所示:

digraph watched_keys {      rankdir = LR;      node [shape = record, style = filled];      edge [style = bold];      // keys      watched_keys [label = "watched_keys |<key1> key1 |<key2> key2 |<key3> key3 | ... |<keyN> keyN", fillcolor = "#A8E270"];      // clients blocking for key1     client1 [label = "client1", fillcolor = "#95BBE3"];     client5 [label = "client5", fillcolor = "#95BBE3"];     client2 [label = "client2", fillcolor = "#95BBE3"];     null_1 [label = "NULL", shape = plaintext];          watched_keys:key1 -> client2;     client2 -> client5;     client5 -> client1;     client1 -> null_1;      // clients blocking for key2     client7 [label = "client7", fillcolor = "#95BBE3"];     null_2 [label = "NULL", shape = plaintext];      watched_keys:key2 -> client7;     client7 -> null_2;      // key3      client3 [label = "client3", fillcolor = "#95BBE3"];     client4 [label = "client4", fillcolor = "#95BBE3"];     client6 [label = "client6", fillcolor = "#95BBE3"];     null_3 [label = "NULL", shape = plaintext];      watched_keys:key3 -> client3;     client3 -> client4;     client4 -> client6;     client6 -> null_3; }

如果某个客户端对 key1 进行了修改(比如执行 DEL key1 ), 那么所有监视 key1 的客户端, 包括 client2 、 client5 和 client1 的 REDIS_DIRTY_CAS 选项都会被打开, 当客户端 client2 、 client5 和 client1 执行 EXEC 的时候, 它们的事务都会以失败告终。

最后,当一个客户端结束它的事务时,无论事务是成功执行,还是失败, watched_keys 字典中和这个客户端相关的资料都会被清除。

事务的 ACID 性质

勘误:Redis 的事务是保证原子性的,本节的内容将原子性和回滚功能混淆了,等待修复中。 —— 2013.6.23

在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的安全性。

Redis 事务保证了其中的一致性(C)和隔离性(I),但并不保证原子性(A)和持久性(D)。

以下四小节是关于这四个性质的详细讨论。

原子性(Atomicity)

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

如果一个事务队列中的所有命令都被成功地执行,那么称这个事务执行成功。

另一方面,如果 Redis 服务器进程在执行事务的过程中被停止 —— 比如接到 KILL 信号、宿主机器停机,等等,那么事务执行失败。

当事务失败时,Redis 也不会进行任何的重试或者回滚动作。

一致性(Consistency)

Redis 的一致性问题可以分为三部分来讨论:入队错误、执行错误、Redis 进程被终结。

入队错误

在命令入队的过程中,如果客户端向服务器发送了错误的命令,比如命令的参数数量不对,等等, 那么服务器将向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC 。

当客户端执行 EXEC 命令时, Redis 会拒绝执行状态为 REDIS_DIRTY_EXEC 的事务, 并返回失败信息。

redis 127.0.0.1:6379> MULTI
OK

redis 127.0.0.1:6379> set key
(error) ERR wrong number of arguments for 'set' command

redis 127.0.0.1:6379> EXISTS key
QUEUED

redis 127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

因此,带有不正确入队命令的事务不会被执行,也不会影响数据库的一致性。

执行错误

如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响。

Redis 进程被终结

如果 Redis 服务器进程在执行事务的过程中被其他进程终结,或者被管理员强制杀死,那么根据 Redis 所使用的持久化模式,可能有以下情况出现:

  • 内存模式:如果 Redis 没有采取任何持久化机制,那么重启之后的数据库总是空白的,所以数据总是一致的。

  • RDB 模式:在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。所以当 RDB 模式下的 Redis 服务器进程在事务中途被杀死时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB 文件里。恢复数据库需要使用现有的 RDB 文件,而这个 RDB 文件的数据保存的是最近一次的数据库快照(snapshot),所以它的数据可能不是最新的,但只要 RDB 文件本身没有因为其他问题而出错,那么还原后的数据库就是一致的。

  • AOF 模式:因为保存 AOF 文件的工作在后台线程进行,所以即使是在事务执行的中途,保存 AOF 文件的工作也可以继续进行,因此,根据事务语句是否被写入并保存到 AOF 文件,有以下两种情况发生:

    1)如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘,那么当进程被杀死之后,Redis 可以根据最近一次成功保存到磁盘的 AOF 文件来还原数据库,只要 AOF 文件本身没有因为其他问题而出错,那么还原后的数据库总是一致的,但其中的数据不一定是最新的。

    2)如果事务的部分语句被写入到 AOF 文件,并且 AOF 文件被成功保存,那么不完整的事务执行信息就会遗留在 AOF 文件里,当重启 Redis 时,程序会检测到 AOF 文件并不完整,Redis 会退出,并报告错误。需要使用 redis-check-aof 工具将部分成功的事务命令移除之后,才能再次启动服务器。还原之后的数据总是一致的,而且数据也是最新的(直到事务执行之前为止)。

隔离性(Isolation)

Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。

持久性(Durability)

因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定:

  • 在单纯的内存模式下,事务肯定是不持久的。

  • 在 RDB 模式下,服务器可能在事务执行之后、RDB 文件更新之前的这段时间失败,所以 RDB 模式下的 Redis 事务也是不持久的。

  • 在 AOF 的“总是 SYNC ”模式下,事务的每条命令在执行成功之后,都会立即调用 fsync 或 fdatasync 将事务数据写入到 AOF 文件。但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的。

    其他 AOF 模式也和“总是 SYNC ”模式类似,所以它们都是不持久的。

小结

  • 事务提供了一种将多个命令打包,然后一次性、有序地执行的机制。
  • 事务在执行过程中不会被中断,所有事务命令执行完之后,事务才能结束。
  • 多个命令会被入队到事务队列中,然后按先进先出(FIFO)的顺序执行。
  • 带 WATCH 命令的事务会将客户端和被监视的键在数据库的 watched_keys 字典中进行关联,当键被修改时,程序会将所有监视被修改键的客户端的 REDIS_DIRTY_CAS 选项打开。
  • 只有在客户端的 REDIS_DIRTY_CAS 选项未被打开时,才能执行事务,否则事务直接返回失败。
  • Redis 的事务保证了 ACID 中的一致性(C)和隔离性(I),但并不保证原子性(A)和持久性(D)。
原文地址https://blog.csdn.net/yanshuanche3765/article/details/81271208
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
NoSQL Redis
redis 事物
1正常执行 127.0.0.1:6379> multi     开启事物OK #然后进行相关操作127.0.0.1:6379> set key4 v4QUEUED127.0.0.1:6379> get key2QUEUED #提交127.
780 0
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
103 1
|
4天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
118 85
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
53 2
数据的存储--Redis缓存存储(二)
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
80 6
|
1天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
1月前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
1月前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
265 22
|
1月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
40 5