文章目录
- Redis 是什么
- NoSql 比较
- Redis 特性
- Redis 可以做什么
- 在 Linux 上安装Redis
- 准备工作
- 安装 Redis6.0+ 版
- 启动Redis
- 默认配置:redis-server
- 运行启动
- 配置文件启动
- Redis 命令行客户端
- 第一种:交互式方式
- 第二种是命令方式
- 停止Redis服务
- Redis 的线程模型
- Redis 是单线程为什么还能这么快
- Redis数据结构
- 字符串
- 常用命令
- 使用场景
- 哈希
- 命令
- 列表
- 命令
- 使用场景
- 集合
- 命令
- 使用场景
- 有序集合
- 命令
- 使用场景
- 慢查询分析
- 慢查询的两个配置参数
- Redis Shell
- redis-cli
- redis-server
- redis-benchmark
- Redis 如何管理 Lua 脚本
- 发布订阅
- 持久化
- RDB
- 流程说明
- 优缺点
- RDB 配置
- AOF
- AOF 配置
- 重写机制
Redis 是什么
Redis 是一种基于键值对(key-value)的NoSQL数据库。
与很多键值对数据库不同的是,它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。
NoSql 比较
NOSQL 数据库名称 | 优点 | 缺点 |
Ehcache | java开发,单机缓存; 基于JVM 的缓存 ;简单、轻巧和方便 (hibernate 和 mybatis 都有集成) | 不支持集群;不支持分布式 |
Memcache | 简单的key-value存储 (只支持字符串) ;内存使用率比较高;多核 | 无法容灾;无法持久化 |
Redis | 丰富的数据结构;持久化;主从同步、故障转移;内存数据库 | 单线程; 单核 |
Redis 特性
速度快
原因:
- Redis的所有数据都是存放在内存中的;
- Redis是用C语言实现的,一般来说C语言实现的程序“距离”操作系统更
近,执行速度相对会更快。 - Redis使用了单线程架构,预防了多线程可能产生的竞争问题。
基于键值对的数据结构服务器
与其他键值对数据库不同的是,redis 支持的数据结构多样(开篇有提到)。
功能丰富
- 提供了键过期功能,可以用来实现缓存。
- 提供了发布订阅功能,可以用来实现消息系统。
- 支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
- 提供了简单的事务功能,能在一定程度上保证事务特性。
- 提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到Redis,减少了网络的开销。
持久化
Redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存的数据保存到硬盘中(如图1-1所示),这样就保证了数据的可持久性。
主从复制、高可用和分布式
Redis 可以做什么
缓存
排行榜
例如按照热度排名的排行榜,按照发布时间的排行榜,按照各种复杂维度计算出的排行榜,Redis提供了列表和有序集合数据结构,合理地使用这些数据结构可以很方便地构建各种排行榜系统。
计数器
社交网络
赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适合保存这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。
在 Linux 上安装Redis
准备工作
升级gcc到 9.3+
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
-- 需要注意的是scl命令启用只是临时的,退出shell或重启就会恢复原系统gcc版本。如果要长期使用gcc 9.3的话:
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
在此鸣谢 http://www.vpser.net/manage/centos-6-upgrade-gcc.html 的作者,感谢这位作者的认真写作和分享,使得安装 GCC 如此简单快捷。
安装 Redis6.0+ 版
https://redis.io/ 官网下载安装包,上传到服务器,放在 /usr/local/bin 目录。
# 或直接官网下载,再解压
$ wget http://download.redis.io/releases/redis-6.2.4.tar.gz
$ tar xzf redis-6.2.4.tar.gz
$ mv redis-6.2.4 redis
$ cd redis
$ make
$ make install
将Redis的相关运行文件放到/usr/local/bin/下,这样就可以在任意目录下执行Redis的命令
到 Redis目录下,修改 vi redis.conf 文件
启动Redis
有三种方法启动redis:默认配置、运行配置和配置文件启动。
默认配置:redis-server
运行启动
redis-server加上要修改配置名和值(可以是多对),没有设置的配置将使用默认配置。
语法:
redis-server --configKey1 configValue1 --configKey2 configValue2
例如,如果要用6380作为端口启动Redis:
redis-server --port 6380
配置文件启动
将配置写到指定文件里,例如以我自己的为例,我的配置文件路径:/usr/local/bin/redis/redis.conf,那么只需要执行如下命令即可启动Redis:
redis-server /usr/local/bin/redis/redis.conf
Redis 的基础配置
配置名 | 配置说明 |
port | 端口 |
logfile | 日志文件 |
dir | Redis 工作目录(存放持久化文件和日志文件) |
daemonize | 是否以守护进程的方式启动Redis |
Redis 命令行客户端
第一种:交互式方式
通过 redis-cli -h {host} -p {port} 的方式连接到 Redis服务。
端口号可以省略
例如:执行 reids-cli -p 6379 也是可以的。
第二种是命令方式
用 redis-cli -h {host} -p {port} {command}
例如: redis-cli -h 127.0.0.1 -p 6379 get hello
注意:
如果没有-h参数,那么默认连接127.0.0.1;如果没有-p,那么默认6379端口,也就是说如果-h和-p都没写就是连接 127.0.0.1:6379 这个Redis实例。
Redis目录下都会有一个redis.conf配置文件,里面就是Redis的默认配置,通常来讲我们会在一台机器上启动多个Redis,并且将配置集中管理在指定目录下,而且配置不是完全手写的,而是将redis.conf作为模板进行修改。显然通过配置文件启动的方式提供了更大的灵活性,所以大部分生产环境会使用这种方式启动Redis。
停止Redis服务
redis-cli shutdown
有三点需要注意一下:
1)Redis关闭的过程:断开与客户端的连接、持久化文件生成,是一种相对优雅的关闭方式。
2)除了可以通过shutdown命令关闭Redis服务以外,还可以通过kill进程号的方式关闭掉Redis,但是不要粗暴地使用kill-9强制杀死Redis服务,不但不会做持久化操作,还会造成缓冲区等资源不能被优雅关闭,极端情况会造成AOF和复制丢失数据的情况。
3)shutdown还有一个参数,代表是否在关闭Redis前,生成持久化文件:redis-cli shutdown nosave|save
基本命令可以上Redis中文网学习,这里不再赘述。
举例:
Redis 的线程模型
Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。所有执行的命令都会进入Redis的一个处理队列中,所以不会产生并发问题,这就是Redis单线程基本模型。这里多路指的是多个网络的连接,复用指的是复用同一个线程
Redis 是单线程为什么还能这么快
原因有三点:
第一,纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
第二,非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
第三,单线程避免了线程切换和竞态产生的消耗。
单线程能带来几个好处:第一,单线程可以简化数据结构和算法的实现。如果对高级编程语言熟悉的读者应该了解并发数据结构实现不但困难而且开发测试比较麻烦。第二,单线程避免了线程切换和竞态产生的消耗,对于服务端开发来说,锁和线程切换通常是性能杀手。
Redis数据结构
字符串
字符串类型是Redis最基础的数据结构。
常用命令
名称 | 语法 | 例子 | 备注 |
set | set key value | set hello world | |
setex | setex key seconds value | setex brid 50 cuckoo | 为键设置秒级过期 |
setnx | setnx key seconds value | setnx brid phoenix | 加锁,键必须不存在,用于添加。设置失效时间:expire key seconds |
set xx | setex key value xx | setex brid cuckoo xx | 键必须存在,用于更新。与 nx 作用一样 |
mset | mset key value [key value …] | mset brid phoenix animal dragon | 批量增加key |
get | get key | get brid | |
mget | mget key [key …] | mget brid animal | 批量获取key |
incr | incr key | incr score | 自增 |
decr | decr key | decr score | 自减 |
注意:1000次get和1次get对比表
使用批量操作,有助于提高业务处理效率,但是要注意的是每次批量操作所发送的命令数不是无节制的,如果数量过多可能造成Redis阻塞或者网络拥塞。
使用场景
1)缓存功能,伪代码示例如下:
UserInfo getUserInfo(long id){
// 定义键
userRedisKey = "user:info:" + id
// 从Redis获取值
value = redis.get(userRedisKey);
UserInfo userInfo;
if (value != null) {
// 将值进行反序列化为UserInfo并返回结果
userInfo = deserialize(value);
} else {
userInfo = mysql.get(id);
if (userInfo != null)
redis.setex(userRedisKey, 3600, serialize(userInfo));
}
return userInfo;
}
2)计数
3)共享 session
一个分布式Web服务将用户的Session信息(例如用户登录信息)保存在各自服务器中,这样会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录,这个问题是用户无法容忍的。
如图:Session分散管理
为了解决这个问题,可以使用Redis将用户的Session进行集中管理。如图:
4)限速
很多应用出于安全的考虑,会在每次进行登录时,让用户输入手机验证码,从而确定是否是用户本人。但是为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率,例如一分钟不能超过5次
phoneNum = "138xxxxxxxx";
key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
isExists = redis.set(key,1,"EX 60","NX");
if(isExists != null || redis.incr(key) <=5){
// 通过
}else{
// 限速
}
哈希
在Redis中,哈希类型是指键值本身又是一个键值对结构,形如value={{field1,value1},…{fieldN,valueN}}
注意
哈希类型中的映射关系叫作field-value,注意这里的value是指field对应的值,不是键对应的值,请注意value在不同上下文的作用。
命令
名称 | 语法 | 例子 | 备注 |
hset | hset key field value | hset user name 路人甲 | |
hget | hset key field | hget user name | |
hdel | hdel key field [field …] | hdel user name | 删除 |
hlen | hlen key | hlen user | 计算field个数 |
hmget | hmget key field [field …] | hlen user | 计算field个数 |
hmset | hmset key field value [field value …] | hlen user | 计算field个数 |
hexists | hexists key field | hexists user name | 判断field是否存在 |
列表
列表(list)类型是用来存储多个有序的字符串。
列表类型有两个特点:
第一、列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表;
第二、列表中的元素可以是重复的。
命令
使用场景
- 消息队列
Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。 - 文章列表
每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。
集合
集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。
命令
使用场景
(1)给用户添加标签;
sadd user:1:tags tag1 tag2 tag5
(2)给标签添加用户
sadd tag1:users user:1 user:3
(3)删除用户下的标签
srem user:1:tags tag1 tag5
有序集合
有序集合相对于哈希、列表、集合来说会有一点点陌生,但既然叫有序集合,那么它和集合必然有着联系,它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。
命令
使用场景
(1)添加用户赞数
例如用户mike上传了一个视频,并获得了3个赞,可以使用有序集合的zadd和zincrby功能:
zadd user:ranking:2016_03_15 mike 3
如果之后再获得一个赞,可以使用zincrby:
zincrby user:ranking:2016_03_15 mike 1
(2)取消用户赞数由于各种原因(例如用户注销、用户作弊)需要将用户删除,此时需要
将用户从榜单中删除掉,可以使用zrem。例如删除成员tom:
zrem user:ranking:2016_03_15 mike
(3)展示获取赞数最多的十个用户
此功能使用 zrevrange 命令实现:
zrevrangebyrank user:ranking:2016_03_15 0 9
(4)展示用户信息以及用户分数此功能将用户名作为键后缀,将用户信息保存在哈希类型中,至于用户的分数和排名可以使用zscore和zrank两个功能:
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike
慢查询分析
许多存储系统(例如MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。
所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似的功能。
如图3-1所示,Redis客户端执行一条命令分为如下4个部分:
慢查询的两个配置参数
对于慢查询功能,需要明确两件事:
预设阀值怎么设置?
慢查询记录存放在哪?
Redis提供了slowlog-log-slower-than和slowlog-max-len配置来解决这两个问题。从字面意思就可以看出,slowlog-log-slower-than就是那个预设阀值,它的单位是微秒(1秒=1000毫秒=1000000微秒),默认值是10000,假如执行了一条“很慢”的命令(例如keys*),如果它的执行时间超过了10000微秒,那么它将被记录在慢查询日志中。
如果slowlog-log-slower-than=0会记录所有的命令,slowlog-log-slowerthan<0对于任何命令都不会进行记录。
slowlog-max-len只是说明了慢查询日志最多存储多少条,并没有说明存放在哪里?实际上Redis使用了一个列表来存储慢查询日志,slowlog-max-len就是列表的最大长度。
一个新的命令满足慢查询条件时被插入到这个列表中,当慢查询日志列表已处于其最大长度时,最早插入的一个命令将从列表中移出,例如slowlog-max-len设置为5,当有第6条慢查询插入的话,那么队头的第一条数据就出列,第6条慢查询就会入列。
在Redis中有两种修改配置的方法,一种是修改配置文件,另一种是使用config set命令动态修改。例如下面使用config set命令将slowlog-log-slowerthan设置为20000微秒,slowlog-max-len设置为1000:
config set slowlog-log-slower-than 20000
config set slowlog-max-len 1000
config rewrite
虽然慢查询日志是存放在Redis内存列表中的,但是Redis并没有暴露这个列表的键,而是通过一组命令来实现对慢查询日志的访问和管理。下面介绍这几个命令。
(1)获取慢查询日志
slowlog get [n]
下面操作返回当前Redis的慢查询,参数n可以指定条数:
127.0.0.1:6379> slowlog get
1) 1) (integer) 666
2) (integer) 1456786500
3) (integer) 11615
4) 1) "BGREWRITEAOF"
2) 1) (integer) 665
2) (integer) 1456718400
3) (integer) 12006
4) 1) "SETEX"
2) "video_info_200"
3) "300"
4) "2"
可以看到每个慢查询日志有4个属性组成,分别是慢查询日志的标识id、发生时间戳、命令耗时、执行命令和参数,慢查询列表如图所示:
(2)获取慢查询日志列表当前的长度
slowlog len
例如,当前Redis中有45条慢查询:
127.0.0.1:6379> slowlog len
(integer) 45
(3)慢查询日志重置
slowlog reset
实际是对列表做清理操作,例如:
127.0.0.1:6379> slowlog len
(integer) 45
127.0.0.1:6379> slowlog reset
OK
127.0.0.1:6379> slowlog len
(integer)
Redis Shell
redis-cli
redis-cli-help
redis-server
redis-server除了启动Redis外,还有一个–test-memory选项。redis-server–test-memory可以用来检测当前操作系统能否稳定地分配指定容量的内存给Redis,通过这种检测可以有效避免因为内存问题造成Redis崩溃,例如下面操作检测当前操作系统能否提供1G的内存给Redis:
redis-server --test-memory 1024
当输出passed this test时说明内存检测完毕,最后会提示–test-memory只是简单检测,如果有质疑可以使用更加专业的内存检测工具:
通常无需每次开启Redis实例时都执行–test-memory选项,该功能更偏向于调试和测试。
redis-benchmark
redis-benchmark可以为Redis做基准性能测试,它提供了很多选项帮助开发和运维人员测试Redis的相关性能。
1)-c
-c(clients)选项代表客户端的并发数量(默认是50)。
2)-n
-n(num)选项代表客户端请求总量(默认是100000)。
例如:
redis-benchmark -c 100 -n 20000 -q
代表100各个客户端同时请求Redis,一共执行20000次。redis-benchmark会对各类数据结构的命令进行测试,并给出性能指标
如果想向Redis插入更多的键,可以执行使用-r(random)选项,可以向Redis插入更多随机的键。
redis-benchmark -c 100 -n 20000 -r 10000
Redis 如何管理 Lua 脚本
1)script load
script load script
将Lua脚本加载到Redis内存中
- script exists
scripts exists sha1 [sha1 …]
# 例如
script exists a5260dd66ce02462c5b5231c727b3f7772c0bcc5
于判断sha1是否已经加载到Redis内存中
3)script flush
# 例如
script exists a5260dd66ce02462c5b5231c727b3f7772c0bcc5
清除Redis内存已经加载的所有Lua脚本
4)script kill
杀掉正在执行的Lua脚本
发布订阅
1)发布消息
publish channel message
# 例如
publish channel:sports "Tim won the championship"
- 订阅消息
subscribe channel [channel ...]
# 例如
subscribe channel:sports
和很多专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,例如无法实现消息堆积和回溯
- 取消订阅
unsubscribe [channel [channel ...]]
# 例如
unsubscribe channel:sports
4)查询订阅
pubsub channels [pattern]
# 例如
pubsub channels
持久化
Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。
RDB
RDB持久化是每隔一段时间,把当前进程数据生成快照保存到硬盘的过程。
手动触发分别对应 save 和 bgsave:
1)save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。
2)bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。
显然bgsave命令是针对save阻塞问题做的优化。因此Redis内部所有的涉及RDB的操作都采用bgsave的方式,而save命令已经废弃。
流程说明
1)执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。
2)父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒。
3)父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
5)进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence下的rdb_*相关选项。
优缺点
优点:
1)每隔一段时间,自动全量备份。
2)灾备简单,只需要远程传输即可。
3)RDB备份时通过一个子进程来进行备份(fork一个新进程)所有的都是以fork这个新进程的时点为分界线,只复制这个时点前的镜像数据,对主进程是不影响的。
缺点:
1)发生故障时,一定会丢失一部分备份后的数据。
2)由于fork的新进程会复制所有数据,所以主机的内存会在备份的一瞬间膨胀两倍。
3)无法做到数据实时备份。
RDB 配置
在 redis.conf 配置里修改如下内容
# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化)
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化)
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
save 900 1
save 300 10
save 60 10000
# 设置RDB存放的目录,注意你一定要在这个配置一个工作目录,而不是文件名称
dir ./
# 设置RDB存放的名称
dbfilename dump.rdb
# yes:如果save过程中出错,则停止写入操作
# no:无论是否写入成功都不停止写入操作
stop-writes-on-bgsave-error yes
# 是否启用压缩
rdbcompression yes
# 是否开启数据校验,有一定的性能损耗
rdbchecksum yes
# 导出数据库的文件名称
dbfilename dump.rdb
QFA:如何使用 RDB 恢复数据?
将 dump.db 拷贝到 redis 的安装目录 dir (上文配置提到的目录) 下面,Redis 会自动进行数据恢复。
AOF
开启AOF功能需要设置配置:appendonly yes,默认不开启。AOF文件名通过appendfilename配置设置,默认文件名是appendonly.aof。
AOF特点
1)以日志的形式来记录用户的所有请求,读请求不会记录,只要写操作才会记录
2)文件是以追加的方式的来记录而不是修改的方式,所有的写入命令会追加到 aof_buf(缓冲区)中。
3)当Redis服务器重启时,可以加载AOF文件进行数据恢复。Redis的AOF恢复方式其实就是把所有追加的文件从开始到结束全部执行一遍。
4)随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
优点
- AOF更加耐用,可以以秒为单位进行备份,如果发生问题只丢失最后一秒的数据
- 以log的日志形式进行追加,如果磁盘满了,会执行redis-check-aof工具
- 当日志文件数据量太大的时候redis会在后台重写AOF文件,重写的过程也是fork新的进程进行操作
- AOF日志包含所有的写操作,会便于redis的解析恢复
劣势
- 相同的数据,同一份对比,AOF一定比RDB大
- 在同步情况下AOF的操作会比RDB慢
AOF 配置
同样在 redis.conf 配置文件进行修改
# AOF默认是关闭的,可用设置成yes
appendonly yes
# aof的文件名
appendfilename "appendonly.aof"
# no: 写入aof文件,不等待磁盘同步
# everysec: 每秒备份,推荐使用
# always: 每次操作都会备份,数据最完整的,但性能差
appendfsync everysec
# 重写的时候是否要同步,yes是不同步,会导致数据不一致
# no同步阻塞,相当于重写过程中数据无法写入
no-appendfsync-on-rewrite no
# 重写机制:避免文件越来越大,自动优化文件大小,会fork一个新的进程去完成重写日志的操作
# 当AOF文件的大小比上次多了100%相当于两倍
# 文件大小达到了64mb
# 两个条件同时满足则触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
重写机制
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入AOF重写机制压缩文件体积。
FQA
重写后的AOF文件为什么可以变小?【了解】
1)进程内已经超时的数据不再写入文件。
2)旧的AOF文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。
3)多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush listc可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。
AOF重写降低了文件占用空间,除此之外,另一个目的是:更小的AOF文件可以更快地被Redis加载。
AOF重写过程可以手动触发和自动触发:
手动触发:直接调用bgrewriteaof命令。
自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。
auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB。
auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。
当触发AOF重写时,内部做了哪些事呢?【了解】
流程说明:
1)执行AOF重写请求。
如果当前进程正在执行AOF重写,请求不执行并返回如下响应:
ERR Background append only file rewriting already in progress
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行,返回如下响应:
Background append only file rewriting scheduled
2)父进程执行fork创建子进程,开销等同于bgsave过程。
3.1)主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区并根据appendfsync策略同步到硬盘,保证原有AOF机制正确性。
3.2)由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,Redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
4)子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞。
5.1)新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见info persistence下的aof_*相关统计。
5.2)父进程把AOF重写缓冲区的数据写入到新的AOF文件。
5.3)使用新AOF文件替换老文件,完成AOF重写。
** 两个都是全量数据,redis 到底用的是哪一个?**
在RDB 和 AOF 两者同时开启时使用的是 AOF
如何在已经运行的Redis上开启AOF并不影响历史数据?
# 首先在redis的命令行,动态开启AOF命令
config set appendonly yes
# 然后再到redis.conf里去打开配置
appendonly yes