redis
redis
一、Redis简介
Redis是一款开源的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSQL数据库产品。
Redis采用内存(In-Memory)数据集(DataSet) 。
支持多种数据类型。
运行于大多数POSIX系统,如Linux、*BSD、OS X等。
二、redis特性
1.速度快
Redis 所有的数据都存放在内存中
Redis 使用c语言实现
Redis 使用单线程架构/模型简单/减少因为CPU不同核数切换带来的损耗
2.基于键值对的数据结构服务器
5种数据结构:字符串,哈希,列表,集合,有序集合,地理位置
3.丰富的功能
提供了键过期功能,可以实现缓存
提供了发布订阅功能,可以实现消息系统
提供了pipeline功能,客户端可以将一批命令一次性传到 Redis,减少了网络开销
4.简单稳定
源码很少,3.0版本以后5万行左右
使用单线程模型法,使得Redis服务端处理模型变得简单
不依赖操作系统的中的类库
5.客户端语言多
java,PHP,python,C,C++,Nodejs等
6.数据持久化
把所有的数据都存在内存中
RDB和AOF
7.主从复制
8.高可用和分布式
哨兵 redis-sentinel
集群 redis-cluster
9.支持事务
三、企业缓存产品介绍
Memcached:
优点:高性能读写、单一数据类型、支持客户端式分布式集群、一致性hash
多核结构、多线程读写性能高。
缺点:无持久化、节点故障可能出现缓存穿透、分布式需要客户端实现、跨机房数据同步困难、架构扩容复杂度高
Redis: 优点:高性能读写、多数据类型支持、数据持久化、高可用架构、支持自定义虚拟内存、支持分布式分片集群、单线程读写性能极高
缺点:多线程读写较Memcached慢
新浪、京东、直播类平台、网页游戏
memcache与redis在读写性能的对比
memcached 适合,多用户访问,每个用户少量的rw
redis 适合,少用户访问,每个用户大量rw
Tair:
优点:高性能读写、支持三种存储引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、支撑了几乎所有淘宝业务的缓存。
缺点:单机情况下,读写性能较其他两种产品较慢




1.Memcached:多核的缓存服务,更加适合于多用户并发访问次数(访问次数较少的应用场景)。
2.Redis:单核缓存服务,在单节点情况下,更加适合少量用户,多次访问的应用场景。
redis一般在企业中,是单机多实例架构
四、redis应用场景
1.缓存-键过期时间
缓存session会话
缓存用户信息,找不到再去mysql查,查到然后回写到redis
商城优惠卷过期时间
2.排行榜-列表&有序集合
热度排名排行榜
发布时间排行榜
3.计数器应用-天然支持计数器
帖子浏览数
视频播放次数
商品浏览数
点赞/点踩
4.社交网络-集合
踩/赞,粉丝,共同好友/喜好,推送,打标签
5.消息队列系统-发布订阅
配合elk实现日志收集
6.配合关系型数据库做高速缓存
redis作用:查询数据缓存 减轻数据库压力



五、redis安装部署
# 1.目录规划
/data/soft/ #redis下载目录
/opt/redis_{PORT}/{conf,logs,pid} #redis安装目录
/data/redis_{PORT}/redis_{PORT}.rdb #redis数据目录
/root/scripts/redis_shell.sh #redis运维脚本
# 2.安装命令
### 编辑hosts文件
[root@db01 ~]# tail -3 /etc/hosts
10.0.0.51 db01
10.0.0.52 db02
10.0.0.53 db03
### 清除之前目录下不用的东西
[root@db01 ~]# rm -rf /opt/*
[root@db01 ~]# rm -rf /data
[root@db01 ~]# yum install gcc -y
[root@db01 ~]# mkdir -p /data/soft
[root@db01 ~]# mkdir -p /data/redis_6379
[root@db01 ~]# mkdir -p /opt/redis_6379/{conf,pid,logs}
### 下载包 拖上来解压
[root@db01 ~]# tar zxf redis-3.2.9.tar.gz -C /opt/
[root@db01 ~]# ln -s /opt/redis-3.2.9/ /opt/redis
[root@db01 ~]# cd /opt/redis
[root@db01 ~]# make && make install
【make生成东西 make install 把这些东西扔到/usr/bin/local】
# 3.配置文件
[root@db01 ~]# cat >/opt/redis_6379/conf/redis_6379.conf <<EOF
### 以守护进程模式启动
daemonize yes
### 绑定的主机地址
bind 127.0.0.1 10.0.0.51
### 监听端口
port 6379
### pid文件和log文件的保存地址
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
### 本地数据库的目录
dir /data/redis_6379
### 指定本地持久化文件的文件名,默认是dump.rdb
dbfilename redis_6379.rdb
EOF
# 4.启动redis
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
# 5.检查是否启动
[root@db01 ~]# ps -ef|grep redis
[root@db01 ~]# netstat -lntup|grep redis
tcp 0 0 10.0.0.51:6379 0.0.0.0:* LISTEN 4798/redis-server 1
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 4798/redis-server 1
# 6.进入redis
[root@db01 ~]# redis-cli
# 7.测试
127.0.0.1:6379>set k1 v1
127.0.0.1:6379>get k1
"v1"
六、redis安全配置
# redis默认开启了保护模式,只允许本地回环地址登录并访问数据库。
禁止protected-mode
protected-mode yes/no (保护模式,是否只允许本地访问)
(1)Bind :指定IP进行监听
vim /opt/redis_6379/conf/redis_6379.conf
bind 10.0.0.51 127.0.0.1
(2)增加requirepass {password}
vim /opt/redis_6379/conf/redis_6379.conf
requirepass 123456
----------验证-----
方法一:
[root@db01 ~]# redis-cli -a 123456
127.0.0.1:6379> SET k2 2
OK
方法二:
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
[root@db01 ~]# redis-cli
127.0.0.1:6379> SET k1 1
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> SET k1 1
OK
redis在线查看和修改配置
#查看配置文件中的监听地址
127.0.0.1:6379> CONFIG GET bind
1) "bind"
2) "127.0.0.1 10.0.0.51"
#查看dir
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/etc/redis/6379"
#查看所有配置
127.0.0.1:6379> CONFIG GET *
#修改配置,即时生效
127.0.0.1:6379> CONFIG SET requirepass 123
OK
#测试修改后连接
[root@db01 redis]# redis-cli -a 123
127.0.0.1:6379> set age 18
OK
禁用危险命令
配置文件里添加禁用危险命令的参数
1)禁用命令
rename-command KEYS ""
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
2)重命名命令
rename-command KEYS "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
rename-command FLUSHALL "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
rename-command FLUSHDB "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
rename-command CONFIG "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
七、redis操作命令
1.全局操作命令
# 0.写入key
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
# 1.查看所有的key!【线上禁止使用!】
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "k3"
# 2.查看有多少个key,注意,是估值
127.0.0.1:6379> DBSIZE
(integer) 3
# 3.查看是否存在这个KEY
127.0.0.1:6379> EXISTS k1
(integer) 1
127.0.0.1:6379> EXISTS k6
(integer) 0
127.0.0.1:6379> EXISTS k1 k2 k6
(integer) 2
状态码:
0 表示这个key不存在
1 表示这个key存在
N 表示有的N个key存在
# 4.删除key
127.0.0.1:6379> DEL k1
(integer) 1
127.0.0.1:6379> DEL k2 k3
(integer) 2
127.0.0.1:6379> DEL k6
(integer) 0
状态码:
0 表示这个key不存在
1 表示这个key存在,并且删除成功
N 表示有的N个key存在,并且删除N个Key
# 5.键过期
设置过期时间
127.0.0.1:6379> EXPIRE k1 100
(integer) 1
取消过期时间,不修改key原来的值
127.0.0.1:6379> PERSIST k1
状态码:
0: 表示这个key不存在
1: 表示这个key存在,并且设置过期时间成功
查看key是否过期
127.0.0.1:6379> TTL k1
(integer) 94
状态码:
-1 :这个key存在,并且永不过期
-2 :这个key不存在
N :这个key存在,并且在N秒后过期
# 结论:
过期后的key直接会被删除
# 6.#变更key名
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> RENAME k1 k11
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k11"
3) "k3"
# 7.查看key的类型
127.0.0.1:6379> type k2
string
2. 字符串操作string
应用场景:
常规计数:微博数、粉丝数、直播平台
# 1.设置一个key
127.0.0.1:6379> set k1 v1
# 2.查看一个key
127.0.0.1:6379> get k1
"v1"
# 3.设置多个key
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
# 4.查看多个key
127.0.0.1:6379> MGET k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
# 5.天然计数器
加1:
127.0.0.1:6379> SET k1 1
OK
127.0.0.1:6379> INCR k1
(integer) 2
127.0.0.1:6379> get k1
"2"
127.0.0.1:6379>
加N:
127.0.0.1:6379> INCRBY k1 100
(integer) 102
127.0.0.1:6379> GET k1
"102"
减N:
127.0.0.1:6379> INCRBY k1 -50
(integer) 52
127.0.0.1:6379> GET k1
"52"
# 6.浮点增加
127.0.0.1:6379> incrbyfloat float 0.6
"0.6"
127.0.0.1:6379> incrbyfloat float 0.5
"1.1"
3.列表list
应用场景:
消息队列系统
比如sina微博:在redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是做了限制不能超过5000个ID,因此获取ID的函数会一只询问redis。系统不会像传统方式那样“刷新”缓存,redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
# 1.插入列表:
LPUSH:从列表左侧插入数据 【最先插的在最后】
RPUSH:从列表右侧插入数据 【最先插的在最前】
127.0.0.1:6379> LPUSH list1 A
(integer) 1
127.0.0.1:6379> LPUSH list1 B
(integer) 2
127.0.0.1:6379> LPUSH list1 C
(integer) 3
127.0.0.1:6379> LPUSH list1 D
(integer) 4
# 2.查看列表的长度:
127.0.0.1:6379> LLEN list1
(integer) 4
# 3.查看列表的内容:
127.0.0.1:6379> LRANGE list1 0 -1
1) "D"
2) "C"
3) "B"
4) "A"
# 4.右侧插入数据
127.0.0.1:6379> RPUSH list1 E
(integer) 5
127.0.0.1:6379> RPUSH list1 F
(integer) 6
127.0.0.1:6379> RPUSH list1 G
(integer) 7
# 5.查看列表内容
127.0.0.1:6379> LRANGE list1 0 -1
1) "D"
2) "C"
3) "B"
4) "A"
5) "E"
6) "F"
7) "G"
# 6.删除列表元素:
LPOP: 从列表左侧删除
RPOP: 从列表右侧删除
127.0.0.1:6379> LPOP list1
"D"
127.0.0.1:6379> LPOP list1
"C"
127.0.0.1:6379> LRANGE list1 0 -1
1) "B"
2) "A"
3) "E"
4) "F"
5) "G"
127.0.0.1:6379> RPOP list1
"G"
127.0.0.1:6379> RPOP list1
"F"
127.0.0.1:6379> LRANGE list1 0 -1
1) "B"
2) "A"
3) "E"
# 7.删除列表内容:
127.0.0.1:6379> DEL list1
(integer) 1
127.0.0.1:6379> LRANGE list1 0 -1
(empty list or set)
4.哈希类型hash
应用场景:
存储部分变更的数据,如用户信息,商品信息等。
最接近表结构的一种类型。
Hash看起来就像一个hash的样子 由键值对组成
HMSET 指令设置hash中的多个域
HGET 取回单个域
HMGET 取回一系列的值
# 1.生成一个hash类型:
127.0.0.1:6379> HMsET user:1 name msy age 17
127.0.0.1:6379> HMsET user:2 name hh age 100
127.0.0.1:6379> HMsET user:3 name msy age 17
# 2.查看hash里的一个值
127.0.0.1:6379> HMGET user:1 name
1) "msy"
# 3.查看hash里的多个值
127.0.0.1:6379> HMGET user:1 name age
1) "msy"
2) "17"
# 4.查看hash里的所有的值
127.0.0.1:6379> HGETALL user:1
1) "name"
2) "msy"
3) "age"
4) "17"
5.集合、有序集合
集合应用场景:
在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
有序应用场景:
排行榜应用,取TOP N操作
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。
【集合】
# 1.创建集合
127.0.0.1:6379> SADD test1 1 1 2 33 [集合不允许出现重复的值]
(integer) 3
127.0.0.1:6379> SADD test2 1 2 5 6 7 9
(integer) 6
# 2.查看集合的成员:
127.0.0.1:6379> SMEMBERS test1
1) "1"
2) "2"
3) "33"
127.0.0.1:6379> SMEMBERS test2
1) "1"
2) "2"
3) "5"
4) "6"
5) "7"
6) "9"
# 3.查看集合的差集,以前面一个集合为基准对比
127.0.0.1:6379> SDIFF test1 test2
1) "33"
127.0.0.1:6379> SDIFF test2 test1
1) "5"
2) "6"
3) "7"
4) "9"
# 4.查看集合的交集
127.0.0.1:6379> SINTER test1 test2
1) "1"
2) "2"
# 5.查看集合的并集
127.0.0.1:6379> SUNION test1 test2
1) "1"
2) "2"
3) "5"
4) "6"
5) "7"
6) "9"
7) "33"
【有序集合】
# 1.添加成员
127.0.0.1:6379> ZADD linux6 100 msy
(integer) 1
127.0.0.1:6379> ZADD linux6 90 hjm 50 xixi 10 hehe
(integer) 3
# 2.计算成员个数
127.0.0.1:6379> ZCARD linux6
(integer) 4
# 3.计算某个成员分数
127.0.0.1:6379> ZSCORE linux6 msy
"100"
# 4.计算成员排名
降序排行 zrank
升序排行 zrevrank
127.0.0.1:6379> ZRANK linux6 msy
(integer) 3 [底下有3个人]
127.0.0.1:6379> ZREVRANK linux6 hjm
(integer) 1 [上面有1个人]
# 5.增加成员分数
127.0.0.1:6379> ZINCRBY linux6 5 hjm
"95"
127.0.0.1:6379> ZINCRBY linux6 -5 hjm
"90"
# 6.返回指定排名范围的成员
127.0.0.1:6379> ZRANGE linux6 0 2 withscores
1) "hehe"
2) "10"
3) "xixi"
4) "50"
5) "hjm"
6) "90"
127.0.0.1:6379> ZRANGE linux6 0 1 withscores
1) "hehe"
2) "10"
3) "xixi"
4) "50"
127.0.0.1:6379> ZRANGE linux6 0 0 withscores
1) "hehe"
2) "10"
# 7.返回指定分数范围的成员
127.0.0.1:6379> ZRANGEBYSCORE linux6 50 100 withscores
1) "xixi"
2) "50"
3) "hjm"
4) "90"
5) "msy"
6) "100"
# 8.返回指定分数范围成员个数
127.0.0.1:6379> ZCOUNT linux6 100 200
(integer) 1
# 9.删除成员
127.0.0.1:6379> ZREM linux6 hjm
(integer) 1
127.0.0.1:6379> ZCARD linux6
(integer) 3
八、持久化
需要触发机制
1.什么是持久化?
就是将内存中的数据,写入到磁盘上,并且永久存在的
2.RDB 持久化介绍
可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
3.RDB优缺点
RDB持久化优点:
- 1)RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
- 2)RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心。
- 3)RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
- 4)RDB在重启保存了大数据集的实例时比AOF要快。
RDB持久化缺点
- 1)当你需要在Redis停止工作(例如停电)时最小化数据丢失,RDB可能不太好。你可以配置不同的保存点(save point)来保存RDB文件(例如,至少5分钟和对数据集100次写之后,但是你可以有多个保存点)。然而,你通常每隔5分钟或更久创建一个RDB快照,所以一旦Redis因为任何原因没有正确关闭而停止工作,你就得做好最近几分钟数据丢失的准备了。
- 2)RDB需要经常调用fork()子进程来持久化到磁盘。如果数据集很大的话,fork()比较耗时,结果就是,当数据集非常大并且CPU性能不够强大的话,Redis会停止服务客户端几毫秒甚至一秒。AOF也需要fork(),但是你可以调整多久频率重写日志而不会有损(trade-off)持久性(durability)。
RDB持久化优缺点总结
- 优点:速度快,适合于用作备份,主从复制也是基于RDB持久化功能实现的。
- 缺点:会有数据丢失、导致服务停止几秒
4.RDB持久化核心配置参数
#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#持久化数据文件存储位置
dir /etc/redis/6379
#rdb持久化数据文件名
dbfilename dump.rdb
#900秒(15分钟)内有1个更改
save 900 1
#300秒(5分钟)内有10个更改
save 300 10
#60秒(1分钟)内有10000个更改
save 60 10000
5.AOF 持久化介绍
AOF(append only file)只追加文件,记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。[以日志的形式来记录每个写操作]
6.AOF优缺点
AOF持久化优点:
- 1)使用AOF Redis会更具有可持久性(durable):你可以有很多不同的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即便你也就仅仅只损失一秒钟的写数据。
- 2)AOF日志是一个追加文件,所以不需要定位,在断电时也没有损坏问题。即使由于某种原因文件末尾是一个写到一半的命令(磁盘满或者其他原因),redis-check-aof工具也可以很轻易的修复。
- 3)当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,因为Redis继续往旧的文件中追加,使用创建当前数据集所需的最小操作集合来创建一个全新的文件,一旦第二个文件创建完毕,Redis就会切换这两个文件,并开始往新文件追加。
- 4)AOF文件里面包含一个接一个的操作,以易于理解和解析的格式存储。你也可以轻易的导出一个AOF文件。例如,即使你不小心错误地使用FLUSHALL命令清空一切,如果此时并没有执行重写,你仍然可以保存你的数据集,你只要停止服务器,删除最后一条命令,然后重启Redis就可以。
AOF持久化缺点:
- 1)对同样的数据集,AOF文件通常要大于等价的RDB文件。
- 2)AOF可能比RDB慢,这取决于准确的fsync策略。通常fsync设置为每秒一次的话性能仍然很高,如果关闭fsync,即使在很高的负载下也和RDB一样的快。不过,即使在很大的写负载情况下,RDB还是能提供能好的最大延迟保证。
- 3)在过去,我们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,导致在数据加载时无法恢复到保存时的样子。这些bug很罕见,我们也在测试套件中进行了测试,自动随机创造复杂的数据集,然后加载它们以检查一切是否正常,但是,这类bug几乎不可能出现在RDB持久化中。为了说得更清楚一点:Redis AOF是通过递增地更新一个已经存在的状态,像MySQL或者MongoDB一样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。但是,1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。2)我们还没有收到一份用户在真实世界中检测到崩溃的报告。
AOF持久化优缺点总结
- 优点:可以最大程度保证数据不丢失
- 缺点:日志记录量级比较大
7.AOF持久化核心配置参数
#修改配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#是否打开AOF日志功能
appendonly yes/no
#每一条命令都立即同步到AOF
appendfsync always
#每秒写一次
appendfsync everysec
#写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到AOF
appendfsync no
8.RDB 和 AOF ,我应该用哪一个
1)一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
2)如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
3)有很多用户单独使用AOF,但是我们并不鼓励这样,因为时常进行RDB快照非常方便于数据库备份,启动速度也较之快,还避免了AOF引擎的bug。
4)个人感触:在企业中,通常都使用RDB来做持久化,因为一般redis是在做MySQL的缓存,就算缓存数据丢失,真实的数据还是在MySQL中,之所以用缓存是为了速度,性能而考虑,所以还是建议使用RDB持久化,相对来说会好一些,除非专门用redis来做一个key:value的数据库,而且数据很重要,那么可以考虑使用AOF。
9.RDB快照的工作方式
1)默认情况下,Redis保存数据集快照到磁盘,名为dump.rdb的二进制文件。你可以设置让Redis在N秒内至少有M次数据集改动时保存数据集,或者你也可以手动调用SAVE或者BGSAVE命令。
2)在上文中我们已经在配置文件中做过对应的配置:
例如,这个配置会让Redis在每个60秒内至少有1000次键改动时自动转储数据集到磁盘:
save 60 1000
3)当 Redis 需要保存 dump.rdb 文件时,服务器执行以下操作:
- Redis 调用 fork() ,同时拥有父进程和子进程。
- 子进程将数据集写入到一个临时的 RDB 文件中。当子进程完成对新 RDB 文件的写入时, Redis 用新RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
4)这种方式使得 Redis 可以从写时复制机制中获益。
10.AOF重写功能介绍
1)因为 AOF 的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加, AOF 文件的体积也变得越来越大。举个例子,如果你对一个计数器调用了 100 次 INCR ,那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录。然而在实际上,只使用一条 SET 命令已经足以保存计数器的当前值了,其余 99 条记录实际上都是多余的。
2)为了处理这种情况, Redis 支持一种有趣的特性:可以在不断服务客户端的情况下,对 AOF 文件进行重建。执行 BGREWRITEAOF 命令, Redis 将生产一个新的 AOF 文件,这个文件包含重建当前数据集所需的最少命令。【就是把前99条都删了】
3)系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,如果Redis的AOF当前大小>=
base_size+base_size*100%
(默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。
11.AOF有多持久
你可以配置 Redis 多久才将数据 fsync 到磁盘一次。
有三个选项:
- 每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。
- 每秒 fsync 一次:足够快(和使用 RDB 持久化差不多,)并且在故障时只会丢失1秒钟的数据。
- 从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。
推荐(并且也是默认)的措施为每秒 fsync 一次,这种 fsync 策略可以兼顾速度和安全性。
总是 fsync 的策略在实际使用中非常慢,即使在 Redis2.0 对相关的程序进行了改进之后仍是如此。频繁调用 fsync 注定了这种策略不可能快得起来。
12.如果 AOF 文件出错了,怎么办
服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成了AOF文件出错,那么 Redis 在重启时会拒绝载入这个 AOF 文件,从而确保数据的一致性不会被破坏。
当发生 AOF 文件出错时,可以用以下方法来修复出错的 AOF 文件:
- 1、为现有的 AOF 文件创建一个备份。
- 2、使用 Redis 附带的 redis-check-aof 程序,对原来的AOF 文件进行修复。redis-check-aof --fix
- 3、使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
- 4、重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。
13.RDB 和 AOF 之间的相互作用
- 1)在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中,不可以执行 BGRWRITEAOF 。 反过来说,在 BGRWRITEAOF 执行的过程中,也不可以执行 BGSAVE 。
- 2)这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。如果 BGSAVE 正在执行,并且用户显示地调用 BGRWRITEAOF 命令,那么服务器将向用户回复一个 OK 状态,并告知用户, BGRWRITEAOF 已经被预定执行; 一旦 BGSAVE 执行完毕, BGRWRITEAOF 就会正式开始。
- 3)当 Redis 启动时,如果 RDB 持久化和 AOF 持久化都被打开了,那么程序会优先使用 AOF 文件来恢复数据集,因为 AOF 文件所保存的数据通常是最完整的。
14.备份 Redis 数据
1)Redis 对于数据备份是非常友好的,因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建,就不会进行任何修改。
2)当服务器要创建一个新的 RDB 文件时,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕时,程序才使用临时文件替换原来的 RDB 文件。
3)这也就是说,无论何时, 复制 RDB 文件都是绝对安全的。
以下是我们的建议:
1)创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
2)确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
3)至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。
15.RDB持久化高级配置
#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#后台备份进程出错时,主进程停不停止写入? 主进程不停止容易造成数据不一致
stop-writes-on-bgsave-error yes
#导出的rdb文件是否压缩 如果rdb的大小很大的话建议这么做
rdbcompression yes
#导入rbd恢复时数据时,要不要检验rdb的完整性 验证版本是不是一致
rdbchecksum yes
16.AOF持久化高级配置
#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#正在导出rdb快照的过程中,要不要停止同步aof
no-appendfsync-on-rewrite yes/no
#aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次
auto-aof-rewrite-percentage 100
#aof文件,至少超过64M时,重写
auto-aof-rewrite-min-size 64mb
17.关于AOF的两个疑惑:
- AOF为什么直接采用文本协议格式?可能的理由如下:
文本协议具有很好的兼容性
开启AOF后,所有写入命令都可以包含追加操作,直接采用协议格式,避免了二次处理开销.
文本协议具有可读性,方便直接修改和处理.
2)AOF为什么把命令追加到aof_buf中?
Redis使用单线程响应命令,如果每次写入AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载.先写入缓冲区aof_buf中,还有另一个好处,Redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡.
18.操作
1.RDB配置
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
[root@db01 ~]# pkill redis
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
[root@db01 ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
[root@db01 ~]# cat /opt/redis_6379/conf/redis_6379.conf
### 以守护进程模式启动
daemonize yes
### 绑定的主机地址
bind 127.0.0.1 10.0.0.51
### 监听端口
port 6379
### pid文件和log文件的保存地址
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
### 本地数据库的目录
dir /data/redis_6379
### 指定本地持久化文件的文件名,默认是dump.rdb
dbfilename redis_6379.rdb
【配置文件里没有配置触发条件】
save 900 1
save 300 10
save 60 10000
# 加上之后
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
[root@db01 ~]# pkill redis
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
[root@db01 ~]# redis-cli
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
[root@db01 ~]# ll /data/redis_6379/
-rw-r--r-- 1 root root 95 Dec 27 09:21 redis_6379.rdb
反复测试之后得出结论
结论:
1.执行shutdown的时候,内部会自动执行bgsave,然后再执行shutdown
2.pkill kill killall 都类似于执行shutdown命令.会触发bgsave持久化
3.恢复的时候,rdb文件名称要和配置文件里写的一样
4.如果没有配置save参数,执行shutdown不会自动bgsave持久化
5.如果没有配置save参数,可以手动执行bgsave触发持久化保存
2.AOF配置
[root@db01 ~]# vim /opt/redis_6379/conf/redis_6379.conf
appendfilename "redis_6379.aof"
appendonly yes
appendfsync everysec
127.0.0.1:6379> set k5 v5
[root@db01 ~]# pkill redis
[root@db01 ~]# ll /data/redis_6379/
-rw-r--r-- 1 root root 52 Dec 27 09:26 redis_6379.aof
-rw-r--r-- 1 root root 88 Dec 27 09:27 redis_6379.rdb
19.实验
如果aof和rdb文件同时存在,redis会如何读取?
实验步骤:
1.插入一条数据 k1 k2 k3
2.手动bgsave
3.生成RDB k1 k2 k3
4.将rdb文件移走
5.rm -rf /data/redis_6379/*
6.启动redis 插入 k3 k5 k4
7.生成AOF文件 K4 K5 K3
8.移走AOF文件
9.pkill redis
10.rm -rf /data/redis_6379/*
11.移回两个文件
12.启动redis
13.测试,如果是k4 k5 k3就表示读取的是aof,如果是k1 k2 k3就表示读取的是rdb
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
[root@db01 ~]# redis-cli
127.0.0.1:6379> SET k1 v1
127.0.0.1:6379> SET k2 v2
127.0.0.1:6379> SET k3 v3
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> bgsave
[root@db01 ~]# ll /data/redis_6379/
-rw-r--r-- 1 root root 110 Dec 27 09:37 redis_6379.aof
-rw-r--r-- 1 root root 102 Dec 27 09:38 redis_6379.rdb
[root@db01 ~]# mv /data/redis_6379/redis_6379.rdb /tmp
[root@db01 ~]# rm -rf /data/redis_6379/*
[root@db01 ~]# pkill redis
[root@db01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
[root@db01 ~]# redis-cli
127.0.0.1:6379> SET k3 v3
127.0.0.1:6379> SET k4 v4
127.0.0.1:6379> SET k5 v5
[root@db01 ~]# ll /data/redis_6379/
-rw-r--r-- 1 root root 110 Dec 27 09:40 redis_6379.aof
-rw-r--r-- 1 root root 102 Dec 27 09:39 redis_6379.rdb
[root@db01 ~]# mv /data/redis_6379/redis_6379.aof /tmp
[root@db01 ~]# rm -rf /data/redis_6379/*
[root@db01 ~]# mv /tmp/redis_6379.rdb /data/redis_6379/
[root@db01 ~]# mv /tmp/redis_6379.aof /data/redis_6379/
[root@db01 ~]# redis-cli
127.0.0.1:6379> keys *
1) "k5"
2) "k4"
3) "k3"
实验结论:
如果2种数据格式都存在,优先读取aof

浙公网安备 33010602011771号