Redis-事务与持久化

2023-11-15

事务

Redis提供了将多个命令请求打包,然后一次性,按顺序的执行多个命令的机制,这种机制叫事务,并且在事务执行的过程中,服务器不会中断事务去执行其他客户端的请求,而是将事务的所有命令都执行完毕在去执行其他客户端请求

事务命令

  • multi:开启事务
  • exec:执行事务
  • discard:取消事务
  • watch:监视

事务的实现

一个事务会经历以下三个阶段:

  • 事务开始
  • 命令入队
  • 事务执行
事务的开始

Redis中multi命令标志着事务的开始

myRedis:0>multi
"OK"

multi命令将执行的客户端从非事务状态切换到事务的状态,通过客户端的flags属性中打开REDIS_MULTI标识来完成切换

命令入队

客户端在非事务状态下,客户端发送的命令会被立即执行,而在事务状态下,客户端会判断不同的命令执行不同的操作

  • 如果命令是multi,exec,discard,watch服务器会立即执行
  • 如果命令不是multi,exec,discard,watch服务器不会立即执行,是把发送的命令放到一个事务队列里,然后返回queued回复
事务队列

每个Redis客户端都有自己的事务状态,状态保存在mstate属性中,事务状态包含事务的队列和已入命令的计数器(事务队列的长度)

typedef struct multiState {
    //存储命令的FIFO队列
    multiCmd *commands;
    //队列长度
    int count;
} multiState;

事务队列是一个multiCmd类型的数组,数组中每个元素都保存了一个入队命令相关的信息,结构如下

typedef struct multiCmd {
    //参数数组
    robj **argv;
    //参数数量
    int argc;
    //命令的指针
    struct redisCommand *cmd;
} multiCmd;

事务队列multiCmd ,以先进先出的方式(FIFO)保存入队命令

图解分析

myRedis:0>multi
"OK"

myRedis:0>set name guohu
"QUEUED"

myRedis:0>set age 28
"QUEUED"

myRedis:0>get name
"QUEUED"

myRedis:0>get age
"QUEUED"

在这里插入图片描述

执行事务

客户端处于事务状态时,向服务器发送exec命令,此时exec命令会被立即执行,并且服务器会遍历客户端的事务队列,执行队列中所有的命令,并将所有队列命令执行的结果返回给客户端(注意:命令是按顺序执行的,先进先出规则)

myRedis:0>exec
 1)  "OK"
 2)  "OK"
 3)  "guohu"
 4)  "28"

WATCH命令

watch命令是一个乐观锁,它可以在exec命令执行之前,监视任意数量的数据库键,并在exec命令执行时,检查是否至少有一个被修改过,如果监视到有修改,则拒绝执行事务,并想客户端发送事务执行失败的回复

执行时间 客户端A 客户端B
time1 watch “name”
time2 multi
time3 set age 28
time4 set 29
time5 exec
不监视的情况下

客户端A

myRedis:0>multi
"OK"

myRedis:0>set age 28
"QUEUED"

myRedis:0>get age
"QUEUED"

新起一个客户端B

myRedis:0>set age 29
"OK"

myRedis:0>get age
"29"

回到客户端A,执行事务提交

myRedis:0>exec
 1)  "OK"
 2)  "28"

按道理事务里面提交的set时29,但是当执行exec的时候,会发现数据被覆盖了

监视的情况下

客户端A执行命令

myRedis:0>flushdb
"OK"

myRedis:0>watch age
"OK"

myRedis:0>multi
"OK"

myRedis:0>set age 28
"QUEUED"

myRedis:0>set name guohu
"QUEUED"

myRedis:0>set address yinshanhu
"QUEUED"

myRedis:0>get name
"QUEUED"

myRedis:0>get address
"QUEUED"

另起一个客户端B执行

myRedis:0>set age 18
"OK"

myRedis:0>get age 
"18"

再次回到客户端A执行事务提交

myRedis:0>exec
(nil)

myRedis:0>get age
"18"

myRedis:0>get name
null

myRedis:0>get address
null

监视到age发生变化,整个事务拒绝执行name和address都没有保存

事务的ACID特性

A-原子性

事务中的原子性是指多个操作被打包成一个整体执行,要么全部执行,要么都不执行,就Redis性质来说,符合原子性的描述,事务里面的命令会被一起执行
但是Redis不支持事务回滚,如果其中有命令出错了,其他命令还会继续执行直到队列命令执行完毕

myRedis:0>multi
"OK"

myRedis:0>set name guohu
"QUEUED"

myRedis:0>incr name
"QUEUED"

myRedis:0>get name
"QUEUED"

myRedis:0>exec
 1)  "OK"
 2)  "ERR value is not an integer or out of range"
 3)  "guohu"
C-一致性

一致性指是指数据库在执行事务之前数据是一致的,在执行事务之后无论事务是否成功数据也是一致的,这符合数据库本身的定义和要求

I-隔离性

隔离性指的是,即使有多个事务并发的执行,各个事务之间页不会相互影响,并且在并发状态下执行的事务和串行执行的事务产生的结果完全相同,而在Redis中事务的所有命令都会按顺序执行,在执行Redis事务的过程中,另一个客户端发出的请求不会被处理,这保证了命令是作为单独的独立操作执行的

D-持久性

数据库持久性是指当一个事务执行完毕之后,所得到的结果已经被保存到永久性的存储介质中(例如:硬盘),事务执行完毕之后即使数据库宕机,也不会影响事务执行的结果,不过Redis中的持久性依赖其持久化机制和是否被开启持久化,如果没开启持久化就是纯内存运行,重启后数据会丢失,而Redis的持久化有两种模式RDB和AOF,下面会介绍具体的持久化机制

持久化

Redis是数据是存在内存里面的,同时Redis也提供了两种持久化机制RDB和AOF,将内存的数据刷到硬盘上,避免数据的意外丢失

RDB持久化(Redis DataBase)

RDB记录的是数据
RDB持久化既可以手动执行,也可以根据服务器的配置来定期执行,RDB文件时一个压缩的二进制文件(dump.rdb),通过RDB文件可以还原生成RDB时间节点的数据库状态,服务在重启的时候会自动加载RDB文件进行数据恢复,RDB文件时保存再硬盘上的,所以即使redis服务关闭了,仍然可以还原数据库恢复数据
在这里插入图片描述

手动执行命令
  • save
    • 会阻塞redis进程,直到RDB文件生成完毕,再生成期间服务不能处理任何请求
  • bgsave
    • 会派生出一个子进程,然后由子进程创建RDB文件,父进程继续处理请求
  • shutdown
    • 正常关机也会出发生成RDB文件
  • flushall
    • 注意flushdb不会触发RDB的生成
    • 不过flushall本身就是清除数据库的命令,生成的文件也是空的,没什么意义

在Redis服务启动时会自动检测是否存在RDB文件,如果存在则自动载入

自动间隔性保存

刚介绍了手动执行的两个命令,save和bgsave,由于bgsave可以不阻塞进程,Redis允许用户设置每隔一段时间自动执行bgsave的命令:

  • save 900 1 : 900秒内对数据库进行1次修改
  • save 300 10:300秒内对数据库进行10次修改
  • save 60 10000:60秒内对数据库进行了10000次修改
    满足以上三个条件其中一个,bgsave就会被执行,并且针对不同的类型,RDB会使用不同的方式存储(这里不做扩展了,不然这页博客就太细太长了)
RDB的优缺点分析

优点:

  • RDB时一个压缩文件,保存了不同时间点的状态,非常适合做灾备
  • RDB的bgsave可以派生子进程保存文件,不影响父级进程的处理,提高了Redis性能
  • 灾备恢复速度快

缺点:

  • 无法做到试试备份,只能间歇性保存RDB文件,如果非正常关机可能会丢失上次备份到宕机的数据
  • 创建子进程,通常父进程来执行fork操作,频繁的fork操作,严重者会导致父进程短时间不可用

AOF持久化(Append Only File)

与RDB不同的是,AOF持久化机制记录的是写命令
开启AOF之后,AOF是采用日志方式将写命令记录到文件中
在这里插入图片描述
需要注意的是,AOF默认是关闭的,如果同时使用AOF和RDB,Redis会优先使用AOF作为持久化模式

开启AOF配置

appendonly no  //默认是no表示关闭,修改为yes则表示开启
appendfilename "appendonly.aof"  //文件名

还可以通过appendfsync参数来控制是否实时写入磁盘

  • always:写入缓存的同时进行刷盘操作
  • everysec:先写入缓存,然后每秒进行一次刷盘操作(极限状态可能会丢失1s的数据)
  • no:只写入缓存,至于刷盘?随缘吧!看操作系统心情

AOF文件重写

AOF文件里包含了所有Redis的写命令,所以只要服务器读到所有命令并重新执行一遍即可还原数据库状态

虽然可以用命令还原数据库状态,但是此时暴漏了一个缺点,假设写命令很多,那文件岂不是越来越大,又或者针对一个key执行了N次操作,实际上有效操作只有最后一次,为了解决这个问题,Redis提供了AOF文件重写功能

重写条件
  • 自动触发,(配置控制,可修改)
    • auto-aof-rewrite-percentag :文件大小超过上次AOF重写之后的文件的百分比,默认100%(超过,是2倍)
    • auto-aof-rewrite-min-size:重写的最小AOF文件大小,默认64M
  • 手动触发:bgrewriteaof 命令
重写机制
  • 再执行重写文件的过程中,Redis会分析现有的键值对,然后聚合成一条命令记录
  • 如果是集合,列表,hash的话在超过元素数量(64个)也会用多条命令记录

备注:说是重写,但实际上是根据现有的键值对分析出写命令,与原文件没有操作关系

重写缓冲区

写文件一般都是子进程 ,此时父继承是不阻塞的,还可以继续接受处理请求,当AOF重写过程中,父进程又有新的请求,这时就需要保证数据的一致性了,在执行AOF重写的操作时,有个AOF 重写缓冲区的概念,如果在重写期间有新的命令进入,会同时写入AOF缓冲区和AOF重写缓冲区

假设子进程完成了文件重写,会向父进程发送一个信号量,父进程紧接着会进行阻塞,并完成重写的以下剩余工作,之后就可以正常处理请求了

  • 将 AOF重写缓冲区的内容刷新到AOF文件上
  • 将写好的AOF文件替换掉旧的AOF文件

AOF优缺点分析

优点

  • 可以通过修改配置自定义刷盘策略
  • 有重写机制,可以防止AOF文件过大的问题
  • 追加的方式记录操作日志,在非正常关机的情况下也可以实现数据库灾备
    缺点
  • RDB是压缩二进制,AOF是写操作日志,相对而言AOF文件更大
  • RDB是基于数据的,AOF是基于命令的如果遇到写操作的错误情况,AOF有可能出现不能完全还原数据库状态,RDB是快照的方式,还原方式更加严谨
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis-事务与持久化 的相关文章

  • 是否可以使用带有 FUSE 文件系统的 Linux VFS 缓存?

    默认情况下 Linux VFS 缓存似乎不适用于 FUSE 文件系统 例如 read 调用似乎被系统地转发到 FUSE 文件系统 我在 FUSE 特定的远程文件系统上工作 我需要一个非常积极的缓存 我需要实现自己的页面缓存吗 或者是否可以为
  • 使用 sidekiq 处理两个独立的 Redis 实例?

    下午好 我有两个独立但相关的应用程序 他们都应该有自己的后台队列 阅读 单独的 Sidekiq 和 Redis 进程 然而 我希望偶尔能够将工作推给app2的队列来自app1 从简单的队列 推送的角度来看 如果app1没有现有的 Sidek
  • 使用brew在MacOSx上安装Redis JSON

    如何使用brew 在 macOSx 上安装 RedisJSON 如何在不编译redis的情况下启用redis上的模块 我不想使用 docker 客户端 Redis Stack 可能是最简单的方法 它不仅仅是 RedisJSON 还包括 Re
  • Spring RedisTemplate:8次调用后方法键挂起

    我使用 Spring RedisTemplate spring data redis 1 7 1 与 Redis 进行通信 我需要通过正则表达式获取然后删除键 例如 context user1 我用的方法 RedisTemplate key
  • Redis 块推送直到列表有空位

    我正在寻找类似的东西BLPUSH该命令将阻塞 直到列表的长度低于指定值max size 目的是防止生产者运行速度快于消费者时列表无限增长 功能与 python 非常相似Queue put https docs python org 3 li
  • Stackexchange.redis 缺乏“WAIT”支持

    我在客户端应用程序正在使用的负载均衡器后面有 3 个 Web API 服务器 我正在使用这个库来访问具有一个主服务器和几个从服务器的 Redis 集群 目前不支持 WAIT 操作 我需要此功能来存储新创建的用户会话并等待它复制到所有从属服务
  • 使用 AWS ElastiCache 请求中的 Airflow CROSSSLOT 密钥未散列到同一插槽错误

    我在 AWS ECS 上运行 apache airflow 1 8 1 并且有一个 AWS ElastiCache 集群 redis 3 2 4 运行 2 个分片 2 个启用多可用区的节点 集群 Redis 引擎 我已经验证气流可以毫无问题
  • 如何在多个Lua State(多线程)之间传递数据?

    我在中启动Redis连接池redis lua 通过从 C 调用 我得到了redis lua state 此 Lua 状态全局启动一次 仅在其他线程中启动get从中 当有一个 HTTP 请求 工作线程 时 我需要从redis lua stat
  • 如何让客户端下载动态生成的非常大的文件

    我有一个导出功能 可以读取整个数据库并创建一个包含所有记录的 xls 文件 然后文件被发送到客户端 当然 导出完整数据库的时间需要大量时间 并且请求很快就会以超时错误结束 处理这种情况的最佳解决方案是什么 例如 我听说过使用 Redis 创
  • Redis键空间事件不触发

    我有两个 Redis 客户端 在一个文件中我有一个简单的脚本设置并删除了 Redis 键 var redis require redis var client redis createClient 6379 127 0 0 1 client
  • Docker-compose Predis 不通过 PHP 连接

    我正在尝试使用 docker compose 将 PHP 与 redis 连接 docker compose yml version 2 services redis image redis 3 2 2 php image company
  • Redis hash写入速度非常慢

    我面临一个非常奇怪的问题 使用 Redis 时 我的写入速度非常糟糕 在理想的情况下 写入速度应该接近 RAM 上的写入速度 这是我的基准 package redisbenchmark import redis clients jedis
  • 如果另一个键中的计数器低于零,则从集合中原子删除一个项目?

    雷迪斯2 0 3 在我的 Redis DB 中 我有一组项目 每个项目都有一个与其关联的计数器 MULTI SADD items set foo INCRBY items foo 10000 EXEC 新项目会以随机间隔添加到集合中 当用户
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • 在 aws-elasticache 上使用 memcached 或 Redis

    我正在 AWS 上开发一个应用程序 并使用 AWS elasticache 进行缓存 我对使用 memcached 或 redis 感到困惑 我阅读了有关 redis 3 0 2 更新以及它现在如何等同于 memchached 的文章 ht
  • Redis SYNC 套接字上的错误情况:连接被拒绝

    在我的 django 应用程序中使用 celery 和 redis 一切都工作正常 直到我遇到了问题 redis 文件的位置已更改 redis 无法访问它们 经过查找 原来这是由于网络随机攻击造成的 需要添加confg 我添加文件后 一段时
  • socket.io 广播功能 & Redis pub/sub 架构

    如果有人能帮助我解决一个小疑问 我将不胜感激 使用socket io广播功能和在Redis上使用pub sub设计架构有什么区别 例如 在另一个示例中 node js 服务器正在侦听 socket io 针对 键 模型 todo 和值 数据
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • Redis是如何实现高吞吐量和高性能的?

    我知道这是一个非常普遍的问题 但是 我想了解允许 Redis 或 MemCached Cassandra 等缓存 以惊人的性能极限工作的主要架构决策是什么 如何维持连接 连接是 TCP 还是 HTTP 我知道它完全是用C写的 内存是如何管理
  • 想要在后台不间断地运行redis-server

    我已经下载了 redis 2 6 16 tar gz 文件并安装成功 安装后我运行 src redis server 它工作正常 但我不想每次都手动运行 src redis server 而是希望 redis server 作为后台进程持续

随机推荐

  • hibernate之关于Hibernate的一级、二级缓冲

    Hibernate 一级 二级缓冲 Hibernate缓冲按级别共分为两种 一级缓冲 Session 和二级缓冲 SessionFactory 有的也说是三种 还有一种是查询缓冲 当然 查询缓冲是依托于二级缓冲 ok 什么是缓冲 在内存里开
  • 【全网最细PAT题解】【PAT乙】1044 火星数字(测试点2,测试点4详细解释)

    题目链接 1044 火星数字 题目描述 火星人是以 13 进制计数的 地球人的 0 被火星人称为 tret 地球人数字 1 到 12 的火星文分别为 jan feb mar apr may jun jly aug sep oct nov d
  • Bigdata1234.cn Java 课堂测试

    Java源文件中有一个公共类名称为Test 则该源文件名必须是 Test java Java中的基本数据类型共有8个 byte short int long float double char boolean Eclipse中内容补全的快捷
  • String的基本操作函数

    string类的构造函数 string const char s 用c字符串s初始化 string int n char c 用n个字符c初始化 此外 string类还支持默认构造函数和复制构造函数 如string s1 string s2
  • 错误解决:liquibase.exception.LockException

    今天发现个错误liquibase exception LockException 网上解决方法 url http forum liquibase org topic lock is not released if nocount is on
  • 全网最全C盘清理指南,无需安装清理软件,值得收藏

    最近电脑运行卡顿 打开一看 原来C盘爆红了 找了一个b站的清理教程 此篇来做一个总结 会讲哪些能删哪些不能删 以及原因 无需安装如360 腾讯电脑管家之类的清理软件 原视频链接 up主 小宇Boihttps www bilibili com
  • 决策树模型

    决策树模型是机器学习的各种算法模型中比较好理解的一种模型 它的基本原理是通过对一系列问题进行if else的推导 最终实现相关决策 下图所示为一个典型的决策树模型 员工离职预测模型的简单演示 该决策树首先判断员工满意度是否小于5 若答案为
  • TCL命令

    目录 list命令 concat命令 lindex命令 llength命令 linsert命令 lreplace命令 lrange命令 lappend命令 lsearch命令 lsort命令 split命令 join命令 list命令 li
  • JSP webshell免杀——JSP的基础

    唉 每次开启JSP都要好一会儿 话说我也不知道为啥 我的每次开启条件一次比一次苛刻 一开始必应就可以打开 再后来只能由谷歌打开 现在可好了得开着代理用谷歌才能进去 一个JSP页面可由5种元素组合而成 1 普通的HTML标记和JavaScri
  • 梳理半月有余,精心准备了17张知识思维导图,这次要讲清统计学

    想要学好数据分析 统计学是必学的基础课程 统计学看似简单 实则知识多而繁杂 对于初学小白来说更是不知所措 理不清知识架构体系 为了让大家对统计学有更加清晰地认识 我总结了17 张 统计学知识思维导图 今天分享给大家 图片上传后会自动压缩 如
  • Nuxt3打包部署到Linux(node+pm2详细安装运行步骤)

    小聊 最近写了一个项目 需要打包部署 过程还是比较繁琐的 因为需要先配置运行环境 准备采用 pm2 管理项目运行 需要在服务器安装 pm2 而安装 pm2 的话用 npm 命令最方便 所以还要下载 node 环境 那么 就让我们一步步的完成
  • Nmap扫描原理与用法

    Nmap扫描原理与用法 2012年6月16日 1 Nmap介绍 Nmap扫描原理与用法PDF 下载地址 Nmap是一款开源免费的网络发现 Network Discovery 和安全审计 Security Auditing 工具 软件名字Nm
  • ‘mvn‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件——解决方法(详解,亲测有效)

    错误原因 配置Maven环境变量出现问题 解决方法 以windows 10为例子 步骤一 此电脑 属性 高级系统设置 环境变量 系统变量 新建 变量名 M2 HOME 变量值 D install maven apache maven 3 5
  • jq和vue的区别

    1 从jquery到vue的转变是一个思想想的转变 就是将原有的直接操作dom的思想转变到操作数据上去 2 传统前端开发模式中是以jq为核心的 而vue是现在一个兴起的前端js库 是一个精简的MVVM 3 jQuery是使用选择器 选取DO
  • spring boot定时任务方式

    一 定时任务实现的几种方式 Timer jdk util自带的Timer类 可以调度一个java util TimerTask任务 只能设定任务按照某个频度执行 但不能按设定时间运行 ScheduledExecutorService jdk
  • 使用Python进行测试驱动开发

    作者 Jason Diamond 译者 吴海燕 原文发表日期 12 02 2004 翻译日期 2 17 2005 原文件位置 http www onlamp com pub a python 2004 12 02 tdd pyunit ht
  • 微信小程序使用npm引入三方包详解

    目录 1 前言 2 微信小程序npm环境搭建 2 1 创建package json文件 2 2 修改 project config json 2 3 修改project private config json配置 2 4 构建 npm 包
  • sharepoint 2010 列表数据分页控件介绍 pagination UserControl

    这里主要是介绍下最近开发的一个sharepoint列表或者文档库的分页控件 并且把它包装成一个可以支持自定义列表 Custom list 文档库 Document library 讨论板 Discussion 资源库 Assets libr
  • 创建vue项目-vue2&vue3

    1 安装node 网址 下载 Node js 中文网 可以下载最新版本 也可以点击下方按钮下载其他版本 安装时全部选择默认 点击下一步 完成之后打开cmd命令窗口 检查node js是否安装成功 再查看npm是否安装成功 2 安装vue脚手
  • Redis-事务与持久化

    目录 事务 事务命令 事务的实现 事务的开始 命令入队 事务队列 执行事务 WATCH命令 不监视的情况下 监视的情况下 事务的ACID特性 A 原子性 C 一致性 I 隔离性 D 持久性 持久化 RDB持久化 Redis DataBase