Redis
安装Redis
wget http://download.redis.io/releases/redis-5.0.6.tar.gz
tar -zxvf redis-5.0.6.tar.gz
yum install gcc
cd redis-5.0.6
make MALLOC=libc
cd src && make install
启动
直接启动
./redis-server
[root@iZwz991stxdwj560bfmadtZ src]# ./redis-server
18685:C 13 Dec 12:56:12.507 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18685:C 13 Dec 12:56:12.507 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=18685, just started
18685:C 13 Dec 12:56:12.507 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.6 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 18685
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
18685:M 13 Dec 12:56:12.508 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
18685:M 13 Dec 12:56:12.508 # Server initialized
18685:M 13 Dec 12:56:12.508 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
18685:M 13 Dec 12:56:12.508 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
18685:M 13 Dec 12:56:12.508 * Ready to accept connections
后台启动
第一步:修改redis.conf文件
将
daemonize no
修改为
daemonize yes
第二步:指定redis.conf文件启动
./redis-server /usr/local/redis-4.0.6/redis.conf
日志
[root@iZwz991stxdwj560bfmadtZ src]# ./redis-server /usr/local/redis-4.0.6/redis.conf
18713:C 13 Dec 13:07:41.109 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18713:C 13 Dec 13:07:41.109 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=18713, just started
18713:C 13 Dec 13:07:41.109 # Configuration loaded
开机启动
1、在/etc目录下新建redis目录
[root@iZwz991stxdwj560bfmadtZ etc]# mkdir redis
2、将/usr/local/redis-4.0.6/redis.conf 文件复制一份到/etc/redis目录下,并命名为6379.conf
[root@iZwz991stxdwj560bfmadtZ redis]# cp /usr/local/redis-5.0.6/redis.conf /etc/redis/redis.conf
3、将redis的启动脚本复制一份放到/etc/init.d目录下
[root@iZwz991stxdwj560bfmadtZ init.d]# cp /usr/local/redis-5.0.6/utils/redis_init_script /etc/init.d/redisd
4、vim编辑redisd文件,在第一行加入如下两行注释,保存退出
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
注释的意思是,redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10。
5、设置redis开机自启动
先切换到/etc/init.d目录下
然后执行自启命令
[root@iZwz991stxdwj560bfmadtZ init.d]# chkconfig redisd on
现在可以直接已服务的形式启动和关闭redis了
启动:
service redisd start
[root@izwz991stxdwj560bfmadtz ~]# service redisd start
Starting Redis server...
2288:C 13 Dec 13:51:38.087 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2288:C 13 Dec 13:51:38.087 # Redis version=4.0.6, bits=64, commit=00000000, modified=0, pid=2288, just started
2288:C 13 Dec 13:51:38.087 # Configuration loaded
关闭:
方法1:service redisd stop
[root@izwz991stxdwj560bfmadtz ~]# service redisd stop
Stopping ...
Redis stopped
方法2:redis-cli SHUTDOWN
Redis文件
redis-benchmark(redis压测工具)
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000
redis-check-aof(redis-aof文件修复检测工具)
./redis-check-aof --fix appendonly.aof
redis-check-rdb(dump.rdb文件修复检测工具)
与redis-check-aof 用法相同
redis-sentinel
哨兵模式启动命令文件,详见哨兵模式
redis-server
redis-cli
Redis命令
Redis配置说明
logfile
#日志文件位置及文件名称
bind 0.0.0.0
#监听地址,可以有多个 如bind 0.0.0.0 127.0.0.1
daemonize yes
#yes启动守护进程运行,即后台运行,no表示不启用
pidfile /var/run/redis.pid
# 当redis在后台运行的时候,Redis默认会把pid文件在在/var/run/redis.pid,也可以配置到其他地方。
# 当运行多个redis服务时,需要指定不同的pid文件和端口
port 6379
# 指定redis运行的端口,默认是6379
unixsocket
#sock文件位置
unixsocketperm
#sock文件权限
timeout 0
# 设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接, 0是关闭此设置
loglevel debug
# 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
logfile ""
# 日志文件配置,默认值为stdout,标准输出,若后台模式会输出到/dev/null
syslog-enabled
# 是否以syslog方式记录日志,yes开启no禁用,与该配置相关配置syslog-ident 和syslog-facility local0 分别是指明syslog的ident和facility
databases 16
#配置可用的数据库个数,默认值为16,默认数据库为0,数据库范围在0-(database-1)之间
always-show-logo yes #4.0以后新增配置
#是否配置日志显示redis徽标,yes显示no不显示
################################ 快照相关配置 #################################
save 900 1
save 300 10
save 60 10000
#配置快照(rdb)促发规则,格式:save <seconds> <changes>
#save 900 1 900秒内至少有1个key被改变则做一次快照
#save 300 10 300秒内至少有300个key被改变则做一次快照
#save 60 10000 60秒内至少有10000个key被改变则做一次快照
dbfilename dump.rdb
#rdb持久化存储数据库文件名,默认为dump.rdb
stop-write-on-bgsave-error yes
#yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no则代表继续写
rdbchecksum yes
#开启rdb文件校验
dir "/etc"
#数据文件存放目录,rdb快照文件和aof文件都会存放至该目录
################################# 复制相关配置参数 #################################
slaveof <masterip> <masterport>
#设置该数据库为其他数据库的从数据库,设置当本机为slave服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
masterauth <master-password>
#主从复制中,设置连接master服务器的密码(前提master启用了认证)
slave-serve-stale-data yes
# 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:
# 1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求
# 2) 如果slave-serve-stale-data是指为no,除了INFO和SLAVOF命令之外的任何请求都会返回一个错误"SYNC with master in progress"
repl-ping-slave-period 10
#从库会按照一个时间间隔向主库发送PING命令来判断主服务器是否在线,默认是10秒
repl-timeout 60
#设置主库批量数据传输时间或者ping回复时间间隔超时时间,默认值是60秒
# 一定要确保repl-timeout大于repl-ping-slave-period
repl-backlog-size 1mb
#设置复制积压大小,只有当至少有一个从库连入才会释放。
slave-priority 100
#当主库发生宕机时候,哨兵会选择优先级最高的一个称为主库,从库优先级配置默认100,数值越小优先级越高
min-slaves-to-write 3
min-slaves-max-lag 10
#设置某个时间断内,如果从库数量小于该某个值则不允许主机进行写操作,以上参数表示10秒内如果主库的从节点小于3个,则主库不接受写请求,min-slaves-to-write 0代表关闭此功能。
################################## 安全相关配置 ###################################
requirepass
#客户端连接认证的密码,默认为空,即不需要密码,若配置则命令行使用AUTH进行认证
maxclients 10000
# 设置同一时间最大客户端连接数,4.0默认10000,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,
# 如果设置 maxclients 0,表示不作限制。
# 当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxmemory 4gb
#设置最大使用的内存大小
maxmemory-policy noeviction
#设置达到最大内存采取的策略:
# volatile-lru -> 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
# allkeys-lru -> 利用LRU算法移除任何key
# volatile-random -> 移除设置过过期时间的随机key
# allkeys->random -> remove a random key, any key
# volatile-ttl -> 移除即将过期的key(minor TTL)
# 4.0默认noeviction代表不删除任何key,只在写操作时候返回错误。
maxmemory-samples 5
#LRU,LFU等算法样本设置,默认5个key
############################## AOF相关配置###############################
appendonly no
# 设置AOF持久化,yes开启,no禁用,开启后redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。
# 但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重写。
appendfilename "appendonly.aof"
#设置AOF文件名
appendfsync everysec
# AOF文件写策略,Redis支持三种同步AOF文件的策略:
# no: 不进行同步,交给操作系统去执行 ,速度较快
# always: always表示每次有写操作都调用fsync方法强制内核将该写操作写入到文件,速度会慢, 但是安全,因为每次写操作都在AOF文件中.
# everysec: 表示对写操作进行累积,每秒同步一次,折中方案.
# 默认是"everysec",按照速度和安全折中这是最好的。
no-appendfsync-on-rewrite no
# AOF策略设置为always或者everysec时,后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作
# 在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复,即使fsync在另外一个线程进行处理,为了减缓这个问题,可以设置下面这个参数no-appendfsync-on-rewrite
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
#当AOF文件增长到一定大小的时候Redis能够调用BGREWRITEAOF对日志文件进行重写,它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)。
#基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动
# 同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况
# 设置 percentage 为0就关闭这个特性
#auto-aof-rewrite-percentage 代表AOF文件每次重写文件大小(以百分数代表),100表示百分之百,即当文件增加了1倍(100%),则开始重写AOF文件
#auto-aof-rewrite-min-size 设置最小重写文件大小,避免文件小而执行太多次的重写
aof-load-truncated yes
#当redis突然运行崩溃时,会出现aof文件被截断的情况,Redis可以在发生这种情况时退出并加载错误,以下选项控制此行为。
#如果aof-load-truncated设置为yes,则加载截断的AOF文件,Redis服务器启动发出日志以通知用户该事件。
#否则,如果该选项设置为no,则服务器将中止并显示错误并停止启动。当该选项设置为no时,用户需要在重启之前使用“redis-check-aof”实用程序修复AOF文件在进行重启
################################## 慢查询配置 ###################################
slowlog-log-slower-than 10000
#Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端,返回结果等,只是命令执行时间,可以通过两个参数设置slow log:一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微秒,因此1000000代表一分钟
#另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除
slowlog-max-len 128
#慢查询命令记录队列长度设置,该队列占用内存,可以使用SLOWLOG RESET清空队列
############################### 高级配置 ###############################
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
# 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值
# Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,
# 这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
list-max-ziplist-size -2
#Lists也以特殊方式编码,以节省大量空间。
#可以指定每个内部列表节点允许的条目数
#作为固定的最大大小或最大元素数。
#对于固定的最大大小,使用-5到-1表示:
#-5:最大大小:64 Kb < - 不建议用于正常工作负载
#-4:最大尺寸:32 Kb < - 不推荐
#-3:最大尺寸:16 Kb < - 可能不推荐
#-2:最大尺寸:8 Kb < - 好
#-1:最大尺寸:4 Kb < - 良好
#正数意味着存储_exactly_元素数量
#每个列表节点。
#性能最高的选项通常为-2(8 Kb大小)或-1(4 Kb大小)
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# list数据类型多少节点以下会采用去指针的紧凑存储格式。
# list数据类型节点值大小小于多少字节会采用紧凑存储格式。
activerehashing yes
# Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用
# 当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。
# 如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
#客户端输出缓冲区限制可用于强制断开客户端,由于某种原因,没有足够快地从服务器读取数据,常见的原因是Pub / Sub客户端不能像很快的消费一条消息,可以为三种不同类型的客户端设置不同的限制:
#normal - >普通客户端,包括MONITOR客户端
#subve - >从服务器客户端
#pubsub - >客户端订阅了至少一个pubsub通道或模式
#设置方法:client-output-buffer-limit 软限制大小 硬限制大小 秒数
#当客户端达到硬限制大小则立即断开连接,当客户端达到软限制时候并且在设置的秒数缓冲大小任然超了,则在设置的秒数后断开连接
达到最大内存采取的策略
- volatile-lru -> 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
- allkeys-lru -> 利用LRU算法移除任何key
- volatile-random -> 移除设置过过期时间的随机key
- allkeys->random -> remove a random key, any key
- volatile-ttl -> 移除即将过期的key(minor TTL)
- 4.0默认noeviction代表不删除任何key,只在写操作时候返回错误。
数据类型
通常使用redis不外乎使用其常用的5中数据类型:string、list、hash、set、sorted_set,在3.2版本以后新添加geo经纬度支持,以下将对其类型的常用操作做说明。
命令使用前言
通大多数据库一样,redis所有的命令提供了帮助,可以使用help +命令名称查看其使用方法,帮助信息中不仅有命令用法,还有命令始于版本信息,分组等。
为了友好的使用,redis还将所有命令都进行了分组,同时使用help+@+组名进行查看每个组中所有命令,以下是所有分组信息。
上面以及介绍如何查看命令使用方法,所以在以下数据类型操作时候,只举例常用的命令,更多命令参考https://redis.io/commands
注意:redis在3.2版本新增geo数据类型。
generic #一般命令组,对大多数类型适用
string #字符串类型命令组,使用所有字符串类型
list #列表类型命令组
set #集合类型命令组
sorted_set #有序集合命令组
hash #hash操作命令组
pubsub #发布命令组
transactions #事务操作命令组
connection #连接相关命令组
server #服务器相关命令组
scripting #lua 脚本命令组
hyperloglog #hyperloglog类型命令组,redis在 2.8.9 版本添加了 HyperLogLog 结构
cluster #集群相关命令组
geo #经纬度相关命令组,适用于3.2.0以后的版本
查看事务操作所有命令
key操作
DEL key #删除某个key
KEYS pattern #查看符合正则的所有key
EXISTS key [key ...] #判断某个key是否存在,可支持多个,返回存在的个数
EXPIRE key seconds #刷新某个key过期时间
MOVE key db #移动key到某个数据库
string操作
字符串操作中需要注意的是,redis中的整型也当作字符串处理。
SET key value [EX seconds] [PX milliseconds] [NX|XX] #设置key为指定的字符串值。
#参数:
#EX seconds – 设置键key的过期时间,单位时秒
#PX milliseconds – 设置键key的过期时间,单位时毫秒
#NX – 只有键key不存在的时候才会设置key的值
#XX – 只有键key存在的时候才会设置key的值
APPEND key value #如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
GET key #获取key值,不存在则返回nil
GETRANGE key start end #获取指定key值的索引开始位置和结束位置所对应的值,索引从0开始
GETSET key value #设置新的key值,并获取设置之前的值,如果key不存在则设置,并返回nil
MGET key [key ...] #批量获取key的值
MSET key value [key value ...] #批量设置key的值
DECR key #数字类型的key自减操作,key类型不是数字则报错
INCR key #数字类型key 自加操作,与DECR相反
DECRBY key decrement #数字类型key指定减少数值
INCRBY key increment #数字类型key指定增加数值,与DECRBY相反
STRLEN key #获取key长度
list操作
列表中的元素索引从0开始,倒数的元素可以用“-”+倒数位置表示,如-2,代表倒数第二个元素,-1则代表最后一个元素。
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边。
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
LPUSH key value [value ...] #从列表左边放入一个或者多个元素
LPUSHX key value #当列表存在时,从左边放入一个元素
RPUSH key value [value ...] #从列表右边放入一个或者多个元素
RPUSHX key value #当列表存在时,从右边放入一个元素
LSET key index value #根据索引设置列表中元素的值,当list不存在是报错
LINDEX key index #根据列表索引获取元素值,索引从0开始
LINSERT key BEFORE|AFTER pivot value #在列表中,基于某个基准点插入值,pivot代表基准点
LLEN key #获取列表长度
LRANGE key start stop #根据索引获取列表中的元素,列表索引最后一个可以使用-1
LREM key count value #从存于 key 的列表里移除前 count 次出现的值为 value 的元素
#count > 0: 从头往尾移除值为 value 的元素
#count < 0: 从尾往头移除值为 value 的元素
#count = 0: 移除所有值为 value 的元素
LPOP key #从列表左边删除一个元素
RPOP key #从列表右边删除一个元素
RPOPLPUSH source destination #删除source列表中的删除最后一个元素将其追加到destination列表
LTRIM key start stop #根据索引start和stop保留列表元素
hash操作
hash操作所有命令都以H开头。
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
HDEL key field [field ...] #删除hash表中一个或多个字段
HEXISTS key field #判断hash表中字段是否存在
HGET key field #获取hash表中字段的值
HGETALL key #获取hash表中所有字段
HSET key field value # 设置hash表中字段的值
HSETNX key field value #只有当字段不存在时候才设置hash表中字段值,
HLEN key #获取hash表中字段个数
HVALS key #获取hash表中所有字段的值
HKEYS key #获取hash表中所有的字段
HSTRLEN key field #获取hash表中指定字段的值的长度
HMSET key field value [field value ...] #批量设置hash表中字段的值
HMGET key field [field ...] #批量获取hash表中字段的值
集合set操作
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
SADD key member [member ...] #添加一个或多个元素到集合中
SREM key member [member ...] #删除一个或多个集合中的元素
SCARD key #获取集合中元素数量
SMEMBERS key #返回集合中所有的元素
SINTER key [key ...] #获取两个或两个以上集合的交集
SUNION key [key ...] #获取两个或两个以上集合的并集
SDIFF key [key ...] #获取两个或者两个以上集合的差集
SISMEMBER key member #判断元素是否是在指定集合中
SMOVE source destination member #移动一个集合中的元素到另一个集合
SPOP key [count] #移除count个集合中元素,count可选参数,默认为1,即移除一个
有序集合操作
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
ZADD key [NX|XX] [CH] [INCR] score member [score member ...] #向一个有序集合添加成员(元素)
#参数:
#XX: 仅仅更新存在的成员,不添加新成员。
#NX: 不更新存在的成员。只添加新成员。
#CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
#INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
ZCARD key #获取有序集合中元素个数
ZCOUNT key min max #指定分数范围的元素个数
ZINCRBY key increment member #为有序集的元素的score值加上增加指定的increment
ZRANGE key start stop [WITHSCORES] #根据有序集合中分数区间获取集合中的元素
ZRANGE key start stop [WITHSCORES] #获取有序集合中元素的排名
ZREM key member [member ...] #删除有序集合中一个或多个元素
ZSCORE key member #设置元素在集合中的分数
GEO类型操作
Redis的GEO是 3.2 版本的新特性,对GEO(地理位置)的支持。这个功能可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作。
geo类型命令不多,总共6个所以这里全部列举出来了。
GEOADD key longitude latitude member [longitude latitude member ...] #将指定的地理空间位置(纬度、经度、名称)添加到指定的key中
GEODIST key member1 member2 [unit] #返回两个给定位置之间的距离。如果两个位置之间的其中一个不存在, 那么命令返回空值。指定单位的参数 unit 必须是以下单位的其中一个:
#m 表示单位为米
#km 表示单位为千米
#mi 表示单位为英里
#ft 表示单位为英尺
GEOPOS key member [member ...] #从key里返回所有给定位置元素的位置(经度和纬度)
GEOHASH key member [member ...] #返回一个或多个位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
#以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
#范围可以使用以下其中一个单位:
#m 表示单位为米。
#km 表示单位为千米。
#mi 表示单位为英里。
#ft 表示单位为英尺。
#在给定以下可选项时, 命令会返回额外的信息:
#WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
#WITHCOORD: 将位置元素的经度和维度也一并返回。
#WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
#命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:
#ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
#DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。
#在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 COUNT <count> 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。
#返回值:
#在没有给定任何 WITH 选项的情况下, 命令只会返回一个像 [“New York”,”Milan”,”Paris”] 这样的线性(linear)列表。
#在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等选项的情况下, 命令返回一个二层嵌套数组, 内层的每个子数组就表示一个元素
#在返回嵌套数组时, 子数组的第一个元素总是位置元素的名字。 至于额外的信息, 则会作为子数组的后续元素, 按照以下顺序被返回:
#以浮点数格式返回的中心与位置元素之间的距离, 单位与用户指定范围时的单位一致。
#geohash 整数。
#由两个元素组成的坐标,分别为经度和纬度。
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
#这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的。
发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图代表其发布订阅之间的关系
运作原理
每个Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer结构, 结构的pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息:
struct redisServer {
// ...
dict *pubsub_channels;
// ...
};
其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。比如说,在下图展示的这个pubsub_channels示例中,client1 、 client2 和 client3 就订阅了 channel1 , 而client3也同时订阅了channel2。
当客户端调用SUBSCRIBE命令时, 程序就将客户端和要订阅的频道在pubsub_channels字典中关联起来。
通过pubsub_channels字典, 程序只要检查某个频道是否为字典的键, 就可以知道该频道是否正在被客户端订阅; 只要取出某个键的值, 就可以得到所有订阅该频道的客户端的信息。
了解了pubsub_channels字典的结构之后, 解释PUBLISH命令的实现就非常简单了: 当调用PUBLISH channel message命令, 程序首先根据channel定位到字典的键, 然后将信息发送给字典值链表中的所有客户端。
订阅模式
redis的发布订阅不仅仅提供简单的订阅频道,还提供模式匹配订阅。模式订阅使用命令PSUBSCRIBE实现。
redisServer.pubsub_patterns属性是一个链表,链表中保存着所有和模式相关的信息:
struct redisServer {
// ...
list *pubsub_patterns;
// ...
};
链表中的每个节点都包含一个redis.h/pubsubPattern结构:
typedef struct pubsubPattern {
redisClient *client;
robj *pattern;
} pubsubPattern;
client 属性保存着订阅模式的客户端,而 pattern 属性则保存着被订阅的模式。
每当调用 PSUBSCRIBE命令订阅一个模式时, 程序就创建一个包含客户端信息和被订阅模式的pubsubPattern结构, 并将该结构添加到redisServer.pubsub_patterns链表中。
作为例子,下图展示了一个包含两个模式的 pubsub_patterns 链表, 其中 client123 和 client256 都正在订阅 tweet.shop.* 模式:
通过遍历整个pubsub_patterns链表,程序可以检查所有正在被订阅的模式,以及订阅这些模式的客户端。
当执行PUBLISH进行命令向channel命令发送消息时,PUBLISH除了将message 发送到所有订阅channel的客户端之外, 它还会将channel和pubsub_patterns中的模式进行对比, 如果channel和某个模式匹配的话, 那么也将message 发送到订阅那个模式的客户端,例如一个客户端订阅了aa.bb.*频道,那么他会收到来自所有aa.bb开头的所有频道消息。
PSUBSCRIBE pattern [pattern ...] #使用模式订阅一个或多个符合给定模式的频道
PUNSUBSCRIBE [pattern [pattern ...]] #退订所有给定模式的频道
SUBSCRIBE channel [channel ...] #订阅给定的一个或多个频道的信息
UNSUBSCRIBE [channel [channel ...]] #指退订给定的频道
PUBSUB subcommand [argument [argument ...]] #查看订阅与发布系统状态
PUBLISH channel message #将信息发送到指定的频道
实践
在以下示例中,将分别用SUBSCRIBE命令订阅aa.bb和使用PSUBSCRIBE模式订阅频道aa.bb*。
SUBSCRIBE订阅:
PSUBSCRIBE订阅:
此时我们使用PUBSH向aa.bb发送消息,返回接受到的频道数,两个订阅者都能收到消息。
订阅者1:
模式订阅者:
小结
订阅信息由服务器进程维持的redisServer.pubsub_channels字典保存,字典的键为被订阅的频道,字典的值为订阅频道的所有客户端。当有新消息发送到频道时,程序遍历频道(键)所对应的(值)所有客户端,然后将消息发送到所有订阅频道的客户端上。订阅模式的信息由服务器进程维持的redisServer.pubsub_patterns链表保存,链表的每个节点都保存着一个pubsubPattern结构,结构中保存着被订阅的模式,以及订阅该模式的客户端。程序通过遍历链表来查找某个频道是否和某个模式匹配。当有新消息发送到频道时,除了订阅频道的客户端会收到消息之外,所有订阅了匹配频道的模式的客户端,也同样会收到消息。退订频道和退订模式分别是订阅频道和订阅模式的反操作。
事务
所谓事务应具有以下特效:原子性(Atomicity), 一致性(Consistency),隔离性(Isolation),持久性(Durability),简称ACID,但redis所提供的事务比较简单,它通过MULTI、EXEC、DISCARD和WATCH等命令实现事务。
而Redis只支持简单的事务,将执行命令放入队列缓存,当程序中有异常或命令出错,执行DISCARD清空缓存队列不执行队列中命令,其事务过程有以下特点:
-
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
-
事务是一个泛原子操作(这里我以泛原子称呼,在某些情况redis的事务不是原子性的,后续会说明):事务中的命令要么全部被执行,要么全部都不执行。
EXEC 命令负责触发并执行事务中的所有命令:
- 如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。
- 另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。
特别说明文中的泛原子操作:
- redis在开启事务以后,若执行命令具有显示的错误或者客户端中断则此次事务在执行EXEC命令时会调用DISCARD清空缓存队列不执行队列中的所有任务,此时是原子性的。
- 当执行命令过程中,命令没有显示的报错(例如LSET操作设置一个不存在的list),而是在EXEC调用时候某个命令出错,那么在这之前已经执行的命令将不会回滚,所以严格说来,redis并不支持原子性。
MULTI #用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令执行缓存队列中的命令。
EXEC #执行缓存队列中的命令
DISCARD #清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态,如果使用了WATCH命令,那么DISCARD命令就会将当前连接监控的所有键取消监控。
WATCH key [key ...] #当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的
UNWATCH #清除所有先前为一个事务监控的键,如果你调用了EXEC或DISCARD命令,那么就不需要手动调用UNWATCH命令
乐观锁机制
乐观锁:总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或检查再设置(CAS)操作实现。
redis通过WATCH命令实现乐观锁,作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。在执行EXEC命令之前,如果Redis检测到至少有一个键被修改了,那么整个事务便会中止运行,然后EXEC命令会返回一个nil值,提醒用户事务运行失败。
注意:WATCH命令需要在MULTI之前执行,不然redis会将其一个命令放入缓存队列中。
示例:在以下示例中通过一个客户端开启事务监听name键,另一个客户端在执行EXEC之前修改name键,此次事务将不会执行,并返回nil,如下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNWCmGuW-1571727695764)(evernotecid://E2552011-7212-44AD-AC20-49677C71DF39/appyinxiangcom/11888059/ENNote/p169?hash=f1333e68524ec6fc3c4c2dd05010786b)]
原子性实践
为演示redis严格意义上将不支持原子性,做了一些简单实践。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEaZOvBQ-1571727695764)(evernotecid://E2552011-7212-44AD-AC20-49677C71DF39/appyinxiangcom/11888059/ENNote/p169?hash=cac1893c1cacb82344e9babb2702756e)]
从上面的结果可以看出,在开启事务前name 值为Rose,在开启事务先后执行了SET命令和LSET命令,但是LSET命令是错误的,当我们调用EXEC执行事务完事务以后,在回头看事务中的SET命令已经生效,并未回滚,因为在次过程中该命令没有显示的报错,所以可以说redis的事务不支持原子性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m10gubGV-1571727695765)(evernotecid://E2552011-7212-44AD-AC20-49677C71DF39/appyinxiangcom/11888059/ENNote/p169?hash=a4b8817259212d903d92e7a8c8e6ec09)]
Redis持久化
Rdb持久化
RDB持久化方式是通过快照(snapshotting)完成的,当符合一定条件时,redis会自动将内存中所有数据以二进制方式生成一份副本并存储在硬盘上。当redis重启时,并且AOF持久化未开启时,redis会读取RDB持久化生成的二进制文件(默认名称dump.rdb,可通过设置dbfilename修改)进行数据恢复,对于持久化信息可以用过命令“info Persistence”查看。
快照文件位置
RDB快照文件存储文件位置由dir配置参数指明,文件名由dbfilename指定,如下:
快照触发条件
RDB生成快照可自动促发,也可以使用命令手动触发,以下是redis触发执行快照条件,后续会对每个条件详细说明:
- 客户端执行命令save和bgsave会生成快照;
- 根据配置文件save m n规则进行自动快照;
- 主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;
- 客户端执行数据库清空命令FLUSHALL时候,触发快照;
- 客户端执行shutdown关闭redis时,触发快照;
save命令触发
客户端执行save命令,该命令强制redis执行快照,这时候redis处于阻塞状态,不会响应任何其他客户端发来的请求,直到RDB快照文件执行完毕,所以请慎用。
实践操作:
首先使用info Persistence查看最近一次持久化时间:
此时我们执行save命令,并再次查看最新快照保存时间已经是最新一次时间:
也可以直接查看RDB数据文件目录下的RDB文件最新时间:
bgsave命令触发
bgsave命令可以理解为background save即:“后台保存”。当执行bgsave命令时,redis会fork出一个子进程来执行快照生成操作,需要注意的redis是在fork子进程这个简短的时间redis是阻塞的(此段时间不会响应客户端请求,),当子进程创建完成以后redis响应客户端请求。其实redis自动快照也是使用bgsave来完成的。
对上述过程描述:
- 客户端执行bgsave命令,redis主进程收到指令并判断此时是否在执行bgrewriteaof(AOF文件重新过程,后续会讲解),如果此时正好在执行则bgsave直接返回,不fork子进程,如果没有执行bgrewriteaof重写AOF文件,则进入下一个阶段;
- 主进程调用fork方法创建子进程,在创建过程中redis主进程阻塞,所以不能响应客户端请求;
- 子进程创建完成以后,bgsave命令返回“Background saving started”,此时标志着redis可以响应客户端请求了;
- 子经常根据主进程的内存副本创建临时快照文件,当快照文件完成以后对原快照文件进行替换;
- 子进程发送信号给redis主进程完成快照操作,主进程更新统计信息(info Persistence可查看),子进程退出;
实践操作
执行bgsave
查看日志,能看到6MB文件内存副本写到了磁盘上,同时打印“Background saving terminated with success”代表文件bgsave操作完成。
查看统计信息最后一次RDB保存时间已经更新:
save m n规则触发
save m n规则说明:在指定的m秒内,redis中有n个键发生改变,则自动触发bgsave。该规则默认也在redis.conf中进行了配置,并且可组合使用,满足其中一个规则,则触发bgsave,在上篇博文也进行了解释,如下:
save 900 1 ,表明当900秒内至少有一个键发生改变时候,redis触发bgsave操作。
实践操作:
改变一个键,满足save 900 1 :
此时查看redis日志,会发现redis立即响应开始bgsave操作:
FLUSHALL触发
flushall命令用于清空数据库,请慎用,当我们使用了则表明我们需要对数据进行清空,那redis当然需要对快照文件也进行清空,所以会触发bgsave。
实践操作
日志:
shutdown触发
shutdown命令触发就不用说了,redis在关闭前处于安全角度将所有数据全部保存下来,以便下次启动会恢复。
实践操作:
可以使用客户端连入执行shutdown命令,也可以直接使用脚本关闭redis,这里我使用init脚本(系统centos6.X)。
查看日志:
主从触发
在redis主从复制中,从节点执行全量复制操作,主节点会执行bgsave命令,并将rdb文件发送给从节点,该过程会在复制篇中进行阐述。
故障恢复
当redis意外崩溃或者关闭再次启动时,此时AOF持久化未开启时(默认未开启),将使用RDB快照文件恢复数据。
来模拟故障情况,让再启动redis服务:
观察日志会发现,启动时候load RDB文件。
RDB相关配置
#save m n
#配置快照(rdb)促发规则,格式:save <seconds> <changes>
#save 900 1 900秒内至少有1个key被改变则做一次快照
#save 300 10 300秒内至少有300个key被改变则做一次快照
#save 60 10000 60秒内至少有10000个key被改变则做一次快照
#关闭该规则使用svae “”
dbfilename dump.rdb
#rdb持久化存储数据库文件名,默认为dump.rdb
stop-write-on-bgsave-error yes
#yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件。
rdbchecksum yes
#在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。
dir "/etc/redis"
#数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
rdbcompression yes
#是否开启RDB文件压缩,该功能可以节约磁盘空间
AOF持久化
当redis存储非临时数据时,为了降低redis故障而引起的数据丢失,redis提供了AOF(Append Only File)持久化,从单词意思讲,将命令追加到文件。AOF可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中,在redis启动时候优先选择从AOF文件恢复数据。由于每一次的写操作,redis都会记录到文件中,所以开启AOF持久化会对性能有一定的影响,但是大部分情况下这个影响是可以接受的,我们可以使用读写速率高的硬盘提高AOF性能。与RDB持久化相比,AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)。
AOF实现本质
AOF实现本质是基于redis通讯协议,将命令以纯文本的方式写入到文件中。
redis协议:
首先Redis是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:
(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。
(-) 表示一个错误信息,具体信息是当前行-后面的字符。
(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。
(KaTeX parse error: Can't use function '\r' in math mode at position 21: …一行数据长度,不包括换行符长度\̲r̲\n,后面则是对应的长度的数据。
(? 表示返回一个数值,:后面是相应的数字节符。
我们可以直接查看AOF文件中的格式,如下图:
开启AOF
默认情况下,redis是关闭了AOF持久化,开启AOF通过配置appendonly为yes开启,我们修改配置文件或者在命令行直接使用config set修改,在用config rewrite同步到配置文件。通过客户端修改好处是不用重启redis,AOF持久化直接生效。
AOF持久化过程
redisAOF持久化过程可分为以下阶段:
1.追加写入
redis将每一条写命令以redis通讯协议添加至缓冲区aof_buf,这样的好处在于在大量写请求情况下,采用缓冲区暂存一部分命令随后根据策略一次性写入磁盘,这样可以减少磁盘的I/O次数,提高性能。
2.同步命令到硬盘
当写命令写入aof_buf缓冲区后,redis会将缓冲区的命令写入到文件,redis提供了三种同步策略,由配置参数appendfsync决定,下面是每个策略所对应的含义:
no:不使用fsync方法同步,而是交给操作系统write函数去执行同步操作,在linux操作系统中大约每30秒刷一次缓冲。这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,一旦redis出现故障,数据丢失严重。
always:表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低。
everysec:数据将使用调用操作系统write写入文件,并使用fsync每秒一次从内核刷新到磁盘。 这是折中的方案,兼顾性能和数据安全,所以redis默认推荐使用该配置。
3.文件重写(bgrewriteaof)
当开启的AOF时,随着时间推移,AOF文件会越来越大,当然redis也对AOF文件进行了优化,即触发AOF文件重写条件(后续会说明)时候,redis将使用bgrewriteaof对AOF文件进行重写。这样的好处在于减少AOF文件大小,同时有利于数据的恢复。
为什么重写?比如先后执行了“set foo bar1 set foo bar2 set foo bar3” 此时AOF文件会记录三条命令,这显然不合理,因为文件中应只保留“set foo bar3”这个最后设置的值,前面的set命令都是多余的,下面是一些重写时候策略:
重复或无效的命令不写入文件
过期的数据不再写入文件
多条命令合并写入(当多个命令能合并一条命令时候会对其优化合并作为一个命令写入,例如“RPUSH list1 a RPUSH list1 b" 合并为“RPUSH list1 a b” )
重写触发条件
AOF文件触发条件可分为手动触发和自动触发:
手动触发:客户端执行bgrewriteaof命令。
自动触发:自动触发通过以下两个配置协作生效:
-
auto-aof-rewrite-min-size: AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。
-
auto-aof-rewrite-percentage:当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。
-
redis开启在AOF功能开启的情况下,会维持以下三个变量
- 记录当前AOF文件大小的变量aof_current_size。
- 记录最后一次AOF重写之后,AOF文件大小的变量aof_rewrite_base_size。
- 增长百分比变量aof_rewrite_perc。
-
每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:
- 没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
- 没有BGREWRITEAOF在进行;
- 当前AOF文件大小要大于server.aof_rewrite_min_size的值;
- 当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比(auto-aof-rewrite-percentage参数)
重写过程
AOF文件重写过程与RDB快照bgsave工作过程有点相似,都是通过fork子进程,由子进程完成相应的操作,同样的在fork子进程简短的时间内,redis是阻塞的,以下图文说明其重写过程:
过程说明:
过程说明:
aof_rewrite_buf 代表重写缓冲区 aof_buf代表写写命令存放的缓冲区
-
开始bgrewriteaof,判断当前有没有bgsave命令(RDB持久化)/bgrewriteaof在执行,倘若有,则这些命令执行完成以后在执行。
-
主进程fork出子进程,在这一个短暂的时间内,redis是阻塞的。
-
主进程fork完子进程继续接受客户端请求,所有写命令依然写入AOF文件缓冲区并根据appendfsync策略同步到磁盘,保证原有AOF文件完整和正确。由于fork的子进程仅仅只共享主进程fork时的内存,因此Redis使用采用重写缓冲区(aof_rewrite_buf)机制保存fork之后的客户端的写请求,防止新AOF文件生成期间丢失这部分数据。此时,客户端的写请求不仅仅写入原来aof_buf缓冲,还写入重写缓冲区(aof_rewrite_buf)。
-
子进程通过内存快照,按照命令重写策略写入到新的AOF文件。
4.1 子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。
4.2 主进程把AOFaof_rewrite_buf中的数据写入到新的AOF文件(避免写文件是数据丢失)。
-
使用新的AOF文件覆盖旧的AOF文件,标志AOF重写完成。
数据恢复
之前已经提到当AOF开启时候,redis数据恢复优先选用AOF进行数据恢复,以下使用停止redis来模拟redis故障,然后在重写启动进行恢复。
查看日志会发现数据恢复已经变成从AOF(append only file)文件中恢复:
AOF配置参数
auto-aof-rewrite-min-size 64mb
#AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。
auto-aof-rewrite-percentage 100
#当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。
appendfsync everysec
#no:不使用fsync方法同步,而是交给操作系统write函数去执行同步操作,在linux操作系统中大约每30秒刷一次缓冲。这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,一旦redis出现故障,数据
#always:表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低。
#everysec:数据将使用调用操作系统write写入文件,并使用fsync每秒一次从内核刷新到磁盘。 这是折中的方案,兼顾性能和数据安全,所以redis默认推荐使用该配置。
aof-load-truncated yes
#当redis突然运行崩溃时,会出现aof文件被截断的情况,Redis可以在发生这种情况时退出并加载错误,以下选项控制此行为。
#如果aof-load-truncated设置为yes,则加载截断的AOF文件,Redis服务器启动发出日志以通知用户该事件。
#如果该选项设置为no,则服务将中止并显示错误并停止启动。当该选项设置为no时,用户需要在重启之前使用“redis-check-aof”实用程序修复AOF文件在进行启动。
appendonly no
#yes开启AOF,no关闭AOF
appendfilename appendonly.aof
#指定AOF文件名,4.0无法通过config set 设置,只能通过修改配置文件设置。
dir /etc/redis
#RDB文件和AOF文件存放目录
实践
实践操作这里使用手动执bgrewriteaof演示重写。
查看日志:
RDB-AOF混合持久化
redis4.0相对与3.X版本其中一个比较大的变化是4.0添加了新的混合持久化方式。前面已经详细介绍了AOF持久化以及RDB持久化,这里介绍的混合持久化就是同时结合RDB持久化以及AOF持久化混合写入AOF文件。这样做的好处是可以结合 rdb 和 aof 的优点, 快速加载同时避免丢失过多的数据,缺点是 aof 里面的 rdb 部分就是压缩格式不再是 aof 格式,可读性差。
开启混合持久化
4.0版本的混合持久化默认关闭的,通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。
混合持久化过程
混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,如下图:
数据恢复
开启了混合持久化时,启动redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
aof文件开头是rdb的格式, 先加载rdb内容再加载剩余的 aof。aof文件开头不是rdb的格式,直接以aof格式加载整个文件。
实践开启混合持久化,并在开启后立马执行写操作,为了证实混合持久化的后半部分AOF过程
查看日志:
此时的aof文件已经和只开启AOF持久化文件不一样了,上半部分是RDB持久化的数据,下半部分是AOF格式数据。
优缺点
RDB
优点:
RDB 是一个非常紧凑(compact)的文件,体积小,因此在传输速度上比较快,因此适合灾难恢复。
RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
缺点:
RDB是一个快照过程,无法完整的保存所以数据,尤其在数据量比较大时候,一旦出现故障丢失的数据将更多。
当redis中数据集比较大时候,RDB由于RDB方式需要对数据进行完成拷贝并生成快照文件,fork的子进程会耗CPU,并且数据越大,RDB快照生成会越耗时。
RDB文件是特定的格式,阅读性差,由于格式固定,可能存在不兼容情况。
**AOF **
优点:
数据更完整,秒级数据丢失(取决于设置fsync策略)。
兼容性较高,由于是基于redis通讯协议而形成的命令追加方式,无论何种版本的redis都兼容,再者aof文件是明文的,可阅读性较好。
缺点:
数据文件体积较大,即使有重写机制,但是在相同的数据集情况下,AOF文件通常比RDB文件大。
相对RDB方式,AOF速度慢于RDB,并且在数据量大时候,恢复速度AOF速度也是慢于RDB。
由于频繁地将命令同步到文件中,AOF持久化对性能的影响相对RDB较大,但是对于我们来说是可以接受的。
混合持久化
优点:
混合持久化结合了RDB持久化 和 AOF 持久化的优点, 由于绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。
缺点:
兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,阅读性较差
Redis常用集群
主从模式
哨兵模式
cluster
Redis分布式锁
分布式锁一般应用于互联网秒杀、抢优惠卷、接口幂等性校验等