Redis 运维 - 从零开始学习
Posted serendipity_cat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 运维 - 从零开始学习相关的知识,希望对你有一定的参考价值。
Redis 运维 - 从零开始学习
一、Redis简介
Redis是一个基于C语言为底层代码开发的开源SQL数据库,Redis基于内存运行并持久化,采用key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环
Redis 的优点
- 具有极高的数据读写速度:数据读取的速度最高可达到 110000次/s,数据写入速度最高可达到 81000次/s
- 支持丰富的数据类型:支持 key-value、Strings、Lists、Hashes、Sets 及 Ordered Sets
等数据类型操作 - 支持数据的持久化:可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
- 原子性:Redis 所有操作都是原子性的
- 支持数据备份:即 master-salve 模式的数据备份
二、Redis 与 Memcached 的区别
Memcached | Redis | |
---|---|---|
类型 Key-value | 数据库 | Key-value 数据库 |
过期策略 | 支持 | 支持 |
数据类型 | 单一数据类型 | 五大数据类型 |
持久化 | 不支持 | 支持 |
主从复制 | 不支持 | 支持 |
虚拟内存 | 不支持 | 支持 |
三、Redis部署
1. 下载编译及安装
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
yum -y install gcc gcc-c++ make
cd /opt
wget -P /opt http://download.redis.io/releases/redis-6.2.2.tar.gz
tar -zxvf redis-6.2.2.tar.gz
cd redis-6.2.2
make && make PREFIX=/usr/local/redis install
#Redis源码包中直接提供了makefile文件 直接执行make与make install命令进行安装
cd /opt/redis-6.2.2/utils/
./install_server.sh
执行./install_server.sh后全部回车直到
Please select the redis executable path []后输入内容/usr/local/redis/bin/redis-server
2. 配置环境
#修改配置
ln -s /usr/local/redis/bin/* /usr/local/bin/
#创建软连接
/etc/init.d/redis_6379 start
#开启服务
netstat -natp | grep 6379
#查看端口服务是否起得来
四、Redis 常用工具
1.Redis 命令工具
命令行 | 解释 |
---|---|
redis-server | 用于启动Redis 的工具 |
redis- benchmark | 用于检测Redis 在本机的运行效率 |
redis-check-aof | 修复AOF持久化文件 |
redis-check-rdb | 修复RDB 持久化文件 |
redis-cli | Redis 命令行工具 |
2.Redis-cli 命令行工具
语法:
redis-cli -h host -p port -a password
例:
redis-cli -h 192.168.0.10 -p 6379
常用选项 | 解释 |
---|---|
-h | 指定远程主机 |
-p | 指定 Redis 服务的端口号 |
-a | 指定密码,未设置数据库密码可以省略此选项 |
3.Redis-benchmark 测试工具
redis-benchmark 是官方自带的 Redis 性能测试工具,可以有效的测试 Redis 服务的性能
基本的测试语法:
redis-benchmark [选项] [选项值]
常用选项 | 解释 |
---|---|
-h | 指定服务器主机名 |
-p | 指定服务器端口 |
-s | 指定服务器 socket |
-c | 指定并发连接数 |
-n | 指定请求数 |
-d | 以字节的形式指定 SET/GET 值的数据大小 |
-k | 1=keep alive,0=reconnect |
-r | SET/GET/INCR,使用随机 key,SADD 使用随机值 |
-p | 通过管道传输请求 |
-q | 强制退出 redis,仅显示 query/sec 值 |
–csv | 以 CSV 格式输出 |
-l | 生成循环,永久执行测试 |
-t | 仅运行以逗号分隔的测试命令列表 |
-I | Idle 模式,仅打开 N 个 idle 连接并等待 |
redis-benchmark -h 192.168.0.10 -p 6379 -c 100 -n 100000
向 IP 地址为 192.168.0.10,端口为 6379 的 Redis 服务器发送 100 个并发连接与 100000 个请求以测试性能
redis-benchmark -h 192.168.0.10 -p 6379 -q -d 100
测试存取大小为 100 字节的数据包的性能
redis-benchmark -t set,lpush -n 100000 -q
测试本机上 Redis 服务在进行 set 与 lpush 操作时的性能
五、常用指令
1. 数据的存放和获取
set存放数据,命令格式为 set key value
get获取数据,命令格式为 get key
redis-cli
set cathome cat
get cathome
2. 查询数据
可以筛选数据 和正则类似
keys | 命令可以取符合规则的键值列表,通常情况可以结合*、?等选项来使用 |
---|---|
keys * | 查看当前数据库中所有的数据 |
keys c* | 查看当前数据库中以v开头的数据 |
keys c? | 查看当前数据库中以v开头后面包含任意一位的数据 |
keys c?? | 查看当前数据库中以v开头后面包含任意两位的数据 |
3. 键值的判断
用来判断一个键值存不存在
exists
命令可以判断键值是否存在
exitsts 键值
del
命令可以删除当前数据库的指定 key
del 键值
type
命令可以获取 key
对应的 value
值类型
type 键值
4. 覆盖键值
对一个已有的键值进行覆盖 数据也会被覆盖 所以在覆盖时要检查原来的键值 以免数据丢失
rename 源key 目标key
renamenx
命令是对已有 key
进行重命名,并检测新名是否存在,如果目标 key
存在则不进行重命名。(不覆盖原来的数据)
renamenx 源key 目标key
dbsize
命令的作用是查看当前数据库中 key
的数目
dbsize
5. 密码验证
用于安全 必须要验证密码通过 否则操作无法执行
config set requirepass 密码
#设置一个密码
auth 密码
#验证密码提升权限
config get requirepass
#查看当前数据库的密码
config set requirepass ''
#删除密码
修改密码后查看受阻
验证密码
6. 多数据库操作
Redis
支持多数据库,Redis
默认情况下包含 16
个数据库,数据库名称采用数字 0-15
来依次命名的。多数据库相互独立,互不干扰。
在登录redis
时 默认使用的是0
号库
select 库的序号
#切换到其他的库
move 键 库号
#移动一个键值到其他的库
get 键
#获取键值
7. 清除数据库内数据
FLUSHDB:清空当前数据库数据
FLUSHALL:清空所有数据库的数据,慎用!
六、五大数据类型
1. String 数据类型(字符串)
String 是 redis 最基本的类型(可以理解为一个 key 对应一个 value),最大能存储 512MB 的数据
String 类型是二进制安全的,可以存储任何数据(比如数字、图片、序列化对象等)
1.1 SET/GET/APPEND/STRLEN
1.1.1 APPEND
APPEND key value追加键值,并返回追加后的长度(若键不存在,则相当于创建)
exists home
#判断该键是否存在,存在返回1,否则返回0
append home "cat"
#该键并不存在,因此append命令返回当前Value的长度
append home " dog"
#该键已经存在,因此返回追加后Value的长度
get home
#通过get命令获取该键,以判断append的结果
1.1.2 SET/STRLEN
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]:设置键-值对
STRLEN key:统计指定key的字符长度
set t1 "how are you"
#通过set命令为键设置新值,并覆盖原有值。
get t1
strlen t1
#获取指定Key的字符长度。
1.2 INCR/ DECR/INCRBY/DECRBY
1.2.1 INCR/ DECR
INCR key:key值递增加1(key值必须为整数)
DECR key:key值递增减1(key值必须为整数)
set home 20
#设置Key的值为20
set home 10
incr home
#该Key的值递增1
decr home
#该Key的值递减1
del home
#删除已有键。
get home
decr home
#对空值执行递减操作,其原值被设定为0,递减后的值为-1
1.2.2 INCRBY/DECRBY
INCRBY key increment:key值增加指定的整数
DECRBY key decrement:key值减少指定的整数
set home 10
decrby home 20
#减少指定值
incrby home 20
#增加指定值
1.3 GETSET
GETSET key value:获取key值并返回,同时给key设置新值
set home 10
getset home 20
#先获取值再设定值
get home
1.4 SETEX
setex key seconds value:设置指定key的过期时间为seconds
setex home 5 "no way"
#设置home只有5秒的生命周期
ttl home
#检查生命周期
get home
ttl home
1.5 SETNX
SETNX key value:不存在键的话执行set操作,存在的话不执行
del home
setnx home "cat"
#当key不存在时创建
setnx home “dog”
#nx有检测的作用所有不会修改已有的值
get home
1.6 MSET/MGET/MSETNX
MSET key value [key value …]:批量设置键-值对
MGET key [key …]:批量获取键值对
MSETNX key value [key value …]:批量设置键-值对,都不存在就执行并返回1;只要有一个存在就不执行并返回0
mset 1 "oh" 2 "yes!"
#批量创建键和值
mget 1 2
#批量获取值
msetnx 2 "no" 3 "way"
mget 1 2 3
2. List数据类型
概述:列表的元素类型为string,按照插入顺序排序,在列表的头部或尾部添加元素
2.1 LPUSH/LPUSHX/LRANGEL/POP/LIEN
LPUSH key value [value …]在头部(左侧)依次插入列表元素 LPUSHX key value:键必须存在才能执行,在头部插入元素值并返回并返回列表元素数量
LRANGE key start stop:取从位置索引start到位置索引stop的所有元素(所以以0开始)
lpush home a b c d
#home键并不存在,该命令会创建该键及与其关联的List,之后在将参数中的values在左侧依次插入。
lrange home 0 2
#取从位置0开始到位置2结束的3个元素。
lrange home 0 -1
#取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
lpushx home2 e
#home2键此时并不存在,因此lpushx命令将不会进行任何操作,其返回值为0。
lrange home2 0 -1
#可以看到home2没有关联任何List Value。
lpushx home e
#home键此时已经存在,所以lpushx命令插入成功,并返回链表中当前元素的数量。
lrange home 0 0
#获取该键的List Value的头部元素。
lpushx home f g
#可以批量插入
lrange home 0 -1
lpop home
#移除并返回第一个元素,从头开始
llen home
#查看列表中元素个数
lrange home 0 -1
#查看列表中的所有元素
2.2 LREM/ LSET/LINDEX/LTRIM
LREM key count value:从头部开始删除count个值为value的元素,并返回实际删除数量
LSET key index value:将位置索引为index的元素设置新值value
LINDEX key index:获取索引为index的元素
LTRIM key start stop:仅保留从位置索引start到索引stop的元素
lpush home a b c d a c
#为后面的示例准备测试数据
lrem home 2 a
#从头部(left)向尾部(right)变量链表,删除2个值等于a的元素,返回值为实际删除的数量。
#删除指定元素,也可以指定数量,从左往右算
lrange home 0 -1
#看出删除后链表中的全部元素
lindex home 1
#获取索引值为1 (头部的第二个元素)的元素值
lset home 1 e
#将索引值为1(头部的第二个元素)的元素值设置为新值e
lindex home 1
#查看是否设置成功
lindex home 6
#索引值6超过了链表中元素的数量,该命令返回nil
lset home 6 h
#设置的索引值6超过了链表中元素的数量,设置失败,该命令返回错误信息
ltrim home 0 2
#仅保留索引值0到2之间的3个元素,注意第0个和第2个元素均被保留
lrange home 0 -1
#查看trim后的结果
2.3 LINSERT
LINSERT key BEFORE|AFTER pivot value:在元素pivot的前面(做左)或后面(右)插入新元素value
del home
#删除该键便于后面的测试
lpush home a b c d e
#为后面的示例准备测试数据
linsert home before a a1
#在a的前面插入新元素a1
lrange home 0 -1
#查看是否插入成功,从结果看已经插入
linsert home after e e2
#在e的后面插入新元素e2,从返回结果看已经插入成功
lindex home 1
#再次查看是否插入成功
linsert home after k a
#在不存在的元素之前或之后插入新元素,linsert命令操作失败,并返回-1
linsert home1 after a a2
#为不存在的Key插入新元素,linsert命令操作失败,返回0
2.4 RPUSH/RPUSHX/RPOP/RPOPLPUSH
RPUSH key value [value …]在列表的尾部依次插入value
RPUSHX key value:key必须存在才可执行,将value从尾部插入,并返回所有元素数量
RPOP key:在尾部弹出(移除)一个元素,并返回该元素
RPOPLPUSH source destination:在key1的尾部弹出一个元素并返回,将它插入key2的头部
del mykey
#删除该键,以便于后面的测试
rpush mykey a b c d
#从链表的尾部插入参数中给出的values,插入顺序是从右到左依次插入
lrange mykey 0 -1
#通过lrange命令可以获悉rpush在插入多值时的插入顺序
rpushx mykey e
#该键已经存在并且包含4个元素,rpushx命令将执行成功,并将元素e插入到链表的尾部
lindex mykey 4
#通过lindex命令可以看出之前的rpushx命令确实执行成功,因为索引值为4的元素已经是新元素了
rpushx mykey2 e
#由于mykey2键并不存在,因此rpushx命 令不会插入数据,其返回值为0
lrange mykey 0 -1
#在执行rpoplpush命令前,先看一下mykey中链 表的元素有哪些,注意他们的位置关系
RPOP mykey
#移除并返回mykey键的第一个元素,从右取
LRANGE mykey 0 -1
rpoplpush mykey mykey2
#将mykey的尾部元素e弹出,同时再插入到mykey2的头部(原子性的完成这两步操作)
lrange mykey 0 -1
#通过lrange命令查看mykey在弹出尾部元素后的结果
lrange mykey2 0 -1
#通过lrange命令查看mykey2在插入元素后的结果
rpoplpush mykey mykey
#将source和destination设为同一键, 将mykey中 的尾部元素移到其头部
lrange mykey 0 -1
#查看移动结果
3. Hash 数据类型(哈希)
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象
Redis hash 是一个键值(key=>value)对集合
可以采用这样的命名方式:对象类别和 ID 构成键名,使用字段表示对象的属性,而字段值则存储属性值
如果 Hash 中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间
每一个 Hash 可以存储大约 42 亿个键值对
3.1 HEST、HGET、HDEL、HEXISTS
HSET hash field1 a field2 b field3 c
#给hash键创建三个字段及对应字段值
HGET hash field1
#获取hash键,字段为field1的值
HDEL hash field2
#删除hash键,字段为field2的值,成功返回1
HEXISTS hash field2
#盘点hash键中字段为field2的值是否存在,存在返回1
3.2 HLEN、HSETNX、HINCRBY
HLEN hash
#获取hash键的字段数量
HSETNX hash1 field3 z
#给hash1键添加新字段field3,值为z,是否执行基于此字段是否存在,不管键是否存在,返回1表示执行成功
KEYS hash*
#添加新数据后,hash1键存在了
HSETNX hash field3 d
#此字段不存在,所以执行吗不成功
HINCRBY hash3 field1 1
#给hash3键的field1字段值加1
HGET hash3 field1
#确认值为1
HINCRBY hash3 field1 -10
#字段值减10
HGET hash3 fiel
3.3 HGETALL、HKEYS、HVALS、HVALS、HMGET、HMSET
HGETALL hash1
#返回hash1键的所有字段及其值,是逐对列出的
HGETALL hash3
HKEYS hash1
#仅获取hash1键中所有字段名
HKEYS hash3
HVALS hash1
#仅获取hash1键中所有字段值
HVALS hash3
HMSET hash4 field1 hello field2 world
HMGET hash4 field1 field2
4、Set 数据类型(无序集合)
无序集合,元素类型为 String 类型
元素具有唯一性,不允许存在重复的成员
多个集合类型之间可以进行并集、交集和差集运算
应用范围
可以使用 Redis 的 Set 数据类型跟踪一些唯一性数据
比如访问某一博客的唯一 IP 地址信息
对于此场景,我们仅需在每次访问该博客时将访问者的 IP 存入 Redis 中,Set 数据类型会自动保证 IP 地址的唯一性
充分利用 Set 类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系
比如所有购买某一电子设备的客户 ID 被存储在一个指定的 Set 中,而购买另外一种电子产品的客户 ID 被存储在另外一个 Set 中
如果此时我们想获取有哪些客户同时购买了这两种商品时,Set 的 intersections 命令就可以充分发挥它的方便和效率的优势了
4.1 SADD、SMEMBERS、SCARD、SISMEMBER
SADD myset a b c d e
#将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略,假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合
(integer) 5
SMEMBERS myset
#查看插入的结果,输出的顺序与插入顺序无关
SCARD myset
#获取集合中成员的数量
SISMEMBER myset d
#判断键中成员是否存在,返回0表示不存在,1表示存在
SISMEMBER myset f
4.2 SPOP、SREM、SRANDMEMBER、SMOVE
SPOP myset
#随机的移除并返回键中的某一成员
SMEMBERS myset
#查看结果,输出的顺序与插入顺序无关
SPOP myset
SMEMBERS myset
SREM myset a b e
#从键中移出a/b/e,并返回移除成员个数,a/e刚已被移除了,所以返回1
SMEMBERS myset
SRANDMEMBER myset
#该命令随机的返回某一成员
SRANDMEMBER myset
SRANDMEMBER myset
SMOVE myset myset1 c
#将键myset的c成员移到键myset1,成功返回1,失败返回0
SMEMBERS myset
SMEMBERS myset1
5. Zset 数据类型(Sorted Set:有序集合)
Zset 和 Set 一样也是 String 类型元素的集合,且不允许重复的成员
每个元素都会关联一个 double 类型的分数 ,redis 正是通过分数来为集合中的成员进行从小到大的排序
zset的成员是唯一的,但分数(score)却可以重复
score(表示权重),可以通过权重的大小排序
应用范围
可以用于一个大型在线游戏的积分排行榜:
每当玩家的分数发生变化时,可以执行 ZADD 命令更新玩家的分数,此后再通过 ZRANGE 命令获取积分 TOP10 的用户信息
5.1 ZADD、ZRANK、ZCARD、ZRANK、ZCOUNT
ZADD zset 1 a 2 b 3 c 4 d 5 e
#将一个或多个成员元素及其分数值加入到有序集当中
ZRANGE zset 0 -1
#查看成员
ZRANGE zset 0 -1 withscores
#查看成员及对应分数
ZCARD zset
#获取键中成员的数量
ZRANK zset e
#获取成员的位置索引值
ZRANK zset a
ZCOUNT zset 2 4
#分数满足表达式[x <= score <= x]的成员的数量
5.2 ZREM、ZSCOREZINCRBY
ZREM zset a b
#删除成员,返回实际删除成员的数量
ZSCORE zset d
#获取成员的分数
ZINCRBY zset 2 a
#若成员不存在,则zincrby命令将添加该成员分数为2(并假设其初始分数为0)
ZINCRBY zset -1 a
ZRANGE zset 0 -1 withscores
5.3 ZRANGEBYSCORE、ZREMRRANGEBYSCORE、ZREMRANGEBYRANK
DEL zset
(integer) 1
ZADD zset 1 a 2 b 3 c 4 d 5 e
#将一个或多个成员元素及其分数值加入到有序集当中
ZRANGEBYSCORE zset 2 4
#获取分数满足表达式[x <= score <= x]的成员,即 2 3 4
ZRANGEBYSCORE zset -inf +inf limit 2 3
#-inf和+inf表示第一个和最后一个成员,limit 2 3表示索引为2开始的三个成员(a0、b1、c2、d3、e4,即c、d、e)
ZREMRANGEBYSCORE zset 1 3
#删除分数满足表达式[x <= score <= x]的成员,并返回实际删除的数量
ZRANGE zset 0 -1
#查看,确认结果
ZREMRANGEBYRANK zset 1 2
#删除位置索引满足表达式[x <= rank <= x]的成员,即(0d、1e,删除1和2索引值,结果只删了1e)
ZRANGE zset 0 -1
#查看,确认结果,仅剩d
5.4 ZREVRANGE、ZREVRANGEBYSCORE、ZREVRANK
DEL zset
ZADD zset 1 a 2 b 3 c 4 d 5 e
ZRANGE zset 0 -1
ZREVRANGE zset 0 -1
#以位置索引从高到低的方式获取并返回此区间内的成员
ZREVRANK zset a
#获取成员索引,该用法是是反向索引排序
ZREVRANK zset e
ZRANK zset a
#正向为0
ZRANK zset e
ZREVRANGEBYSCORE zset 5 3
#获取分数满足表达式[x >= score >= x]的成员,并以从高到底的顺序输出
ZREVRANGEBYSCORE zset 3 1 limit 1 2
#分数1-3,且索引为1-2的成员
七、Redis 高可用
在 web 服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)
但是在 Redis 语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展,数据安全不会丢失等
在 Redis 中,实现高可用的技术主要包括持久化、主从复制、哨兵和集群,下而分别说明它们的作用,以及解决了什么样的问题:
1. 持久化
持久化是最简单的高可用方法(有时甚至不被归为高可用的手段)
主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失
2. 主从复制
主从复制是高可用 Redis 的基础,哨兵和集群都是在主从复制基础上实现高可用的
主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复
缺陷在于故障恢复无法自动化,写操作无法负载均衡,以及存储能力受到单机的限制
3. 哨兵
在主从复制的基础上,哨兵实现了自动化的故障恢复
缺陷在于写操作无法负载均衡,以及存储能力受到单机的限制
4. 集群
通过集群, Redis 解决了写操作无法负载均衡,以及存储能力受到单机限制的问题
实现了较为完善的高可用方案
八、Redis 持久化
1. 持久化的功能
Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致 Redis 进程异常退出后数据的永久丢失,需要定期将 Redis 中的数据以某种形式(数据或命令)从内存保存到硬盘
当下次 redis 重启时,利用持久化文件实现数据恢复
除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置
2. Redis 提供两种方式进行持久化
RDB 持久化 :原理是将 Reids 在内存中的数据库记录定时保存到磁盘上
AOF 持久化(append only file):原理是将Reids的操作日志以追加的方式写入文件,类似于 mysql 的 binlog
由于 AOF 持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此 AOF 是目前主流的持久化方式,不过 RDB 持久化仍然有其用武之地
九、RDB 持久化
RDB 持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是 rdb
当 Redis 重新启动时,可以读取快照文件恢复数据
1. 触发条件
RDB持久化的触发分为手动触发和自动触发两种
1.1 手动触发
save 命令和 bgsave 命令都可以生成 RDB 文件
save 命令会阻塞 Redis 服务器进程,直到RDB文件创建完毕为止,在 Redis 服务器阻塞期间,服务器不能处理任何命令请求
而 bgsave 命令会创建一个子进程,由子进程来负责创建 RDB 文件,父进程(即 Redis 主进程) 则继续处理请求
bgsave 命令执行过程中,只有 fork 子进程时会阻塞服务器,而对于 save 命令,整个过程都会阻塞服务器,因此 save 已基本被废弃,线上环境要杜绝 save 的使用
1.2 自动触发
在自动触发 RDB 持久时,Redis 也会选择 bgsave 而不是 save 来进行持久化
save m n
#自动触发最常见的情况是在配置文件中通过 savemn,指定当 m 秒内发生 n 次变化时,会触发 bgsave
vim /etc/redis/6379.conf
#219行,以下三个save条件满足任意一个时,都会引起bgsave的调用
save 900 1 :当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
save 300 10 :当时间到300秒时, 如果redis数据发生了至少10次变化,则执行bgsave
save 60 10000 :当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave
#254行,指定 RDB 文件名
dbfilename dump.rdb
#264行,指定 RDB 文件和 AOF 文件所在目录
dir /var/lib/redis/6379
#242行,是否开启 RDB 文件压缩
rdbcompression yes
2. 执行流程
- Redis 父进程首先判断:当前是否在执行 save,或 bgsave/bgrewriteaof 的子进程,如果在执行,则 bgsave
命令直接返回,bgsave/bgrewriteaof
的子进程不能同时执行;主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题 - 父进程执行 fork 操作创建子进程,这个过程中父进程是阻塞的,Redis 不能执行来自客户端的任何命令
- 父进程 fork 后,bgsave 命令返回“Background saving
started”信息并不再阻塞父进程,并可以响应其他命令 - 子进程创建 RDB 文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
- 子进程发送信号给父进程表示完成,父进程更新统计信息
3. 启动加载
- RDB 文件的载入工作是在服务器启动时自动执行的,并没有专门的命令
- 但是由于 AOF 的优先级更高,因此当 AOF 开启时,Redis 会优先载入 AOF 文件来恢复数据
- 只有当 AOF 关闭时,才会在 Redis 服务器启动时检测 RDB 文件,并自动载入
- 服务器载入 RDB 文件期间处于阻塞状态,直到载入完成为止
- Redis 载入 RDB 文件时,会对 RDB 文件进行校验,如果文件损坏,则日志中会打印错误(Redis 启动失败)
十、AOF持久化
当Redis对数据进行操作时记录日志[除了查询操作],并通过重启时再次执行 AOF 文件中的命令来数据进行恢复
1. 配置开启AOF
vim /etc/redis/6379.conf
#700行修改, 开启AOF
appendonly yes
/etc/init.d/redis_6379 restart
2. 执行流程
命令追加
- 写命令不直接写入磁盘而是追加到缓冲区,避免磁盘I/O瓶颈
- 兼容性强、易处理的、可读性高的纯文本格式
文件写入和文件同步
为了避免内存缓冲区的数据意外丢失,所以提供了 fsync、fdatasync 等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性
AOF 缓存区的同步文件策略存在三种同步方式
vim /etc/redis/6379.conf
#729行
appendfsync always:
#命令写入 aof_ buf 后立即调用系统 fsync 操作同步到 AOF 文件,fsync 完成后线程返回
#这种情况下,每次有写命令都要同步到 AOF 文件,硬盘 IO 成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了 Redis 的性能
#即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低 SSD 的寿命
appendfsync no:
#命令写入 aof_ buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步
#同步由操作系统负责,通常同步周期为 30 秒
#这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证
appendfsynceverysec:
#命令写入 aof_ buf 后调用系统 write 操作,write 完成后线程返回
#fsync 同步文件操作由专门的线程每秒调用一次
#everysec 是前述两种策略的折中,是性能和数据安全性的平衡,因此是 Redis 的默认配置,也是我们推荐的配置
文件重写
定期将进程内部数据转化为写命令同步到新AOF文件中,从而减少AOF文件体积[不会对旧AOF文件进行处理]
- (1)Redis 父进程首先判断当前是否存在正在执行 bgsave/bgrewriteaof 的子进程,如果存在则
bgrewriteaof 命令直接返回,如果存在 bgsave 命令则等 bgsave 执行完成后再执行 - (2)父进程执行fork操作创建子进程,这个过程中父进程是阻塞的
- (3.1)父进程 fork 后,bgrewriteaof 命令返回"Background append only file
rewrite started"信息并不再阻塞父进程,并可以响应其他命令;Redis 的所有写命令依然写入 AOF 缓冲区,并根据
appendfsync 策略同步到硬盘,保证原有 AOF 机制的正确 - (3.2)由于 fork 操作使用写时复制技术,子进程只能共享 fork 操作时的内存数据;由于父进程依然在响应命令,因此 Redis
使用 AOF 重写缓冲区(aof_ rewrite_buf)保存这部分数据,防止新 AOF
文件生成期间丢失这部分数据;也就是说,bgrewriteaof 执行期间,Redis 的写命令同时追加到 aof_ buf 和 aof_
rewirte_ buf 两个缓冲区 - (4)子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件
- (5.1)子进程写完新的 AOF 文件后,向父进程发信号,父进程更新统计信息,具体可以通过 info persistence 查看
- (5.2)父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致
- (5.3)使用新的 AOF 文件替换老文件,完成 AOF 重写
触发方式
手动触发
直接调用 bgrewriteaof
命令,该命令的执行与 bgsave
有些类似
都是 fork
子进程进行具体的工作,且都只有在 fork
时阻塞
自动触发
通过设置 auto-aof-rewrite-min-size
选项和 auto-aof-rewrite-percentage
选项来自动执行BGREWRITEAOF
只有当 auto-aof-rewrite-min-size
和 auto-aof-rewrite-percentage
两个选项同时满足时,才会自动触发AOF
重写,即 bgrewriteaof
操作
vim /etc/redis/ 6379. conf
#771行
auto-aof- rewrite-percentage 100
#当前 AOF 文件大小(即 aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生 BGREWRITEAOF操作
auto-aof -rewrite-min-size 64mb
#当前 AOF文件执行 BGREWRITEAOF 命令的最小值
#避免刚开始启动 Reids 时由于文件尺寸较小导致频繁的 BGREWRITEAOF
以上是关于Redis 运维 - 从零开始学习的主要内容,如果未能解决你的问题,请参考以下文章