string 操作命令 (最大存储512MB)
set key value
get key
del key
mset key value key1 value1 key2 value2 设置多个key和value
mget key key1 key2 key3 获取多个key
多个key操作, 发送一次指令,执行多次,返回一次
设置数值增加
incy key key的value+1
incrby key 5 key的value+5
incrbyfloat key 1.5 key的value+1.5
设置数值减
decr kye key的value-1
decrby key 5 key的value-5
设置key的过期时间
setex key seconds value 设置key多少秒过期
psetex key milliseconds value 设置key 多少毫秒过期
hash操作命令(最大存储2的32次方 -1)
hset key field value
hget key field
hgetall key 单数为子key,双数为value
hdel key field
hmset key field1 value1 field2 value2 向key中添加多个field和value
hmsge key field1 field2 获取多个数据
hlen key 获取key中的字段数
hexists key field 获取key中是否存在field
hkeys key 获取key里所有的 field
hvals key 获取key里所有的value
设置数值增加
hincrby key field 5 设置 field的value +5
hincrbyfloat key field 1.5 设置 field的value +1.5
list操作命令(最大存储2的32次方 -1)
双向链表
lpush key value1 value2 向key的左边添加多个value
rpush key value1 value2 向key的右边添加多个value
lrange key 0 2 获取从左边下标0开始到下标2的数据
lindex key 2 从左边开始获取下标为2的数据
llen key
lpop key 从左边获取数据并删除
rpop key 从右边获取数据并删除
blpop key 5 阻塞从左边获取数据等待5秒
brpop key 5 阻塞从左边获取数据等待5秒
lrem key 1 value 从list中删除指定的value删除1个
set操作命令
不允许有数据重复
sadd key value1 value2 向key中添加多个数据
smembers key 获取key所有数据
srem key value1 value2 删除key中的多个value
scard key 获取key中数据数
sismember key value 获取key中是否存在value
srandmember key 5 随机获取集合中指定数量的数据
spop key 3 随机获取集合中的某个数据并将该数据移出集合
sinter key1 key2 获取两个key 的交集
sunion key1 key2 获取两个key 的并集
sdiff key1 key2 获取两个key 的差集 key1-key2
sinterstore newKey key1 key2 获取两个key 的交集并添加newKey中
sunionstore newKey key1 key2 获取两个key 的并集并添加newKey中
sdiffstore newKey key1 key2 获取两个key 的并集并添加newKey中
smove key1 key2 value 将key1中的value移动到key2中
zset操作命令(最大存储64位)
重复设置一个key中的value的值,排序号会修改,value不会修改
zadd key 100 value 排序号 value 添加数据
zrange key 0 2 [withscores] 获取key下标0到2的数据,withscores 获取排序号
zrevrange key 0 2 倒序
zrem key value
zrangebyscore key min max [withscores][limit] 获取排序号 min max之间的数据
zrevrangebyscore key max min
zremrangebyrank 0 2 删除下标0到2的数据
zremrangebyscore key min max 删除排序号min max之间的数据
zcard key 获取数据总数
zcount key min max 获取排序号之间的数据总数
zinterstore 交集
zunionstore 并集
zrank key value 获取key中value对应的索引位置(小到大排)
zrevrank key value 获取key中value对应的索引位置(大到小排)
zscore key value 获取key中value的排序号
zincrby key 5 value 对key中value的排序号+5
key基本操作
del key 删除指定key
exists key 获取key是否存在
type key 获取key的类型
expire key 3 设置key 3秒过期
pexpire key 100 设置key 100毫秒过期
ttl key 查看key 的过期时间 -1 永久有效 -2已过期或被删除的数据或未定义的数据
pttl key
persist key 把key转换为永久存在
bitmaps基本操作
getbit key index 获取key对应位置上的bit值
setbit key index value 设置指定key对应位置上的bit值,value 只以是1或0
bitcount key [start end] 统计指定key中1的数量
bitop op destKey key1 key2 对指定key接位进行交(and)、并(or)、非(not)、异或(xor) 操作,并将结果保存到destkey中
hyperLogLog基本操作(去重,数据统计)
pfadd key value
pfcount key 获取key去重后的个数
pfmerge newkey key1 key2 合并key1 key2中的数据并去重
geo类型操作
geoadd key lon lat number 添加坐标点
geopos key number 获取坐标点
geodist key number number unit 计算坐标距离
georadius key 根据坐标尔范围内的数据
georadiusbymember key 根据点求范围内的数据
geohash key 获取指定点对应的坐标hash值
事务基本操作
multi 开启事物
exec 执行事物
discard 取消事物
watch 基于特定条件的事务执行
watch key 对key添加监视锁,在执行exec前如果key发生了变化,终止事务执行。
unwatch 取消对所有的key的监视
分布式锁
setnx key value
利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功
- 对于返回设置成功的,拥有控制权,进行下一步操作(1)
- 对于返回设置失败,排队等待 (0)
工作原理
db操作
select index 切换数据库存
ping 测试redis是否通
dbsize 查看key的总数
redis服务启动
redis-server 默认配置启动
redis-server --port 6380 设置启动端口
redis-server redis.conf 设置启动配置文件
redis客户端连接
redis-cli 连接默认redis
redis-cli -h 127.0.0.1 连接指定redis服务
redis-cli -p 6380 连接指定端口redis服务
redis.conf配置
daemonize yes 守护进程启动
bind 127.0.0.1 绑定主机地址(绑定后只有这里的IP可以访问)
databases 16 设置数据库的个数
port *** 指定端口
maxclients 0 设置同一时间最大客户端连接数,0为无限制,当客户端连接达到上限,会关闭新的连接
timeout 300 客户端闲置最大时长,达到最大值后关闭连接,设置为0,关闭功能
lnclude /path/server-端口号.conf 导入并加载指定配置文件信息,用到快速创建redis公共配置较多的redis实例文件
dir "/opt/data" 设置文件保存路径 日志,持久化文件
loglevel debug|verbose|notice|warning 设置日志级别
logfile "aaa.log" 设置日志文件名
dbfilename dump.rdb 设置本地数据库文件名,默认值为 dump.rdb
dir 设置存储.rdb文件路径
rdbcompression yes 设置存储到本地数据库时是否压缩数据,默认为yes
rdbchecksum yes 设置是否进行rdb文件格式校验,该校验过程在写文件和读文件进程均进行
stop-writes-on-bgsave-error yes bgsave后台存储过程中如果出现错误现象,是否停止保存操作,默认开启
save second changes 满足限定时间范围内key的变化数量达到指定数量进行持久化, second监控时间范围,changes监控key的变化数量
appendonly yes|no 开启aof持久化功能,默认不开启
appendfsync always|everysec|no aof写数据策略
appendfilename filename aof持久化文件名
auto-aof-rewrite-min-size 64mb aof文件至少要达到64M才会自动重写,文件大小恢复速度本来就很快,重写的意义不大
auto-aof-rewrite-percentage 100 aof文件自上一次重写后文件增长了100%则再次触发重写
info Persistence 获取redis运行参数
maxmemory 最大使用内存
maxmemory-samples 每次选取待删除的个数
maxmemory-policy 达到最大内存后,对被挑选出来的数据进行删除的策略
aof-use-rdb-preamble yes 开启混合持久化 aof rdb
RDB
save 阻塞生成rdb文件,马上执行
bgsave 后面生成rdb文件,发送指令后,会调用操作系统fork函数生成子进程,子进程穿件rdb文件
RDB工作原理
AOF
bgrewriteaof 重写aof
AOF 写数据三种策略
always(每次)
everysec(每秒)
no(系统控制)
aof重写
aof重写作用
- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率
aof重写击规则
- 进程内已超时的数据不再写入文件
- 忽略无效指令,重写时使用进程内数据直接生成,这样就的AOF文件只保留最终数据的写入命令
- 对同一数据的多条写命令合并为一条命令
AOF工作原理
Redis 4.0 混合持久化
AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将 重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一 起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改 名,原子的覆盖原有的AOF文件,完成新旧两个AOF文件的替换。 于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。
过期数据 删除策略
定时删除 时间到了就直接删除(处理器性能换空间)
惰性删除 时间到了不删除,下次访问在进行删除(空间换处理器性能)
定期删除
删除策略(maxmemory-policy)
LRU 最长时间没有被使用 LFU 在规定时间内使用最少的
noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
检测易失数据(可以会过期的数据集 server.db[i].expires)
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-lru: 挑选最近最少使用的数据跳台
- volatile-lfu: 挑选最近使用次数最少的数据
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
检测合库数据(所有数据集server.db[i].dict)
- allkeys-lfu: 挑选最近使用次数最少的数据
- allkeys-lru: 挑选最近最少使用的数据跳台
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
主从复制
repl-backlog-size 1mb 设置主节点复制缓冲区的大小
- 命令传播阶段出现了断网的现象
- 网络闪断闪连
- 短时间网络中断 部分复制
- 长时间断开 全量复制
- 部分复制的三个核心要素
- 服务器的运行ID(run id)
- 主服务器的复制积压缓冲区
- 主从服务器的复制偏移量
服务器的运行ID(run id)
- 概念:服务器的运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行ID
- 组成:运行id由40位字符组成,是一个随机的十六进制字符
- 作用: 运行id被用于在服务器间进行传输,识别身份如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行ID,用于对方识别
- 实现方式: 运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自已的运行id发送给slave,slave保存此id,通过info server命令,可以查看节点的run id
复制缓冲区
- 概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,第次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
- 复制缓冲区默认数据存储空间大小是1M,由于存储空间大小是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新的元素会被放入队列
- 由来: 每台服务器启动时,如果开启有AOF或被连接成为master节点,即创建复制缓冲区
- 作用: 用来保存master收到的所有指令(仅影响数据变更的指令)
- 数据来源: 当master接收到主客户端时指令时,除了将指令执行,会将指令存储到缓冲区中
主从服各器复制偏移量(offset)
- 概念: 一个数字,描述复制缓冲区中的指令字节位置
- 分类:
- master 复制偏移量: 记录发送给所有slave的指令字节对应的位置(多个)
- slave 复制偏移量: 记录slave接收master发送过来的指令字节对应的位置(一个)
- 数据来源
- master端:发送一次记录一次
- slave端:接收一次记录一次
- 作用: 同步信息,比对master与slave的差异,当slave断线后,恢复数据使用
心跳机制
- 进入命令传播阶段时,master与slave间需要进行信息交换,使用心跳机制时空行维护,实现双方连接保持在线
- master心跳
- 指令:ping
- 周期: 由repl-ping-slave-period决定,默认10秒
- 作用: 判断slave是否在线
- 查询: info replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常
- slave心跳任务
- 指令: replconf ack {offset}
- 周期: 1秒
- 作用1: 汇报slave自已的复制偏移量,获取最新的数据变更指令
- 作用2: 判断master是否在线
- 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作
- min-slaves-to-write 2
- min-slaves-max-lag 8
- slave数量少于2个,或者所有slave的延迟都>=10秒时,强制关闭master写功能,停止数据同步
- slave数量由slave发送 replconf ack命令确认
- slave延迟由slave发送replconf ack命令确认
频繁的全量复制
伴随着系统的运行,master的数据量会赿来越大,一旦master重启,runid将发生变化,会导致全部slave的全量复制操作
内部优化调整方案:
- master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
- 在master关闭时执行命令shutdown save,进行RDB持久化,将runid与offset保存到RDB文件中
- repl-id repl-offset
- 通过redis-check-rdb命令可以查看该信息
3. master重启后加载RDB文件,恢复数据; 重启后,将RDB文件中保存的repl-id与repl-offset加载到内存中
- master_repl_id = repl master_repl_offset = rpl-offset
- 通过info命令可以查看该信息
作用: 本机保存上次runid,重启后恢复该值,使所有slave认为还是之前的master
网络环境不佳,出现网络中断,slave不提供服务
原因:复制缓冲区过小,断网后slave的offset越界,触发全量复制,slave反复进行全是不是复制
解决方案: 修改复制缓冲区大小 repl-backlog-size
建议修改
- 测算从master到slave的重连平均时长second
- 获取master平均每秒产生写命令数据总量 write_size_per_second
- 最优复制缓冲区空间 = 2 * second * write_size_per_second
master的CPU占用过高或slave频繁断开连接
原因
- slave 每1秒发送 replconf ack命令到master
- 当slave接到了慢查询时 (keys *,hgetall等),会大量占用cpu性能
- master每1秒调用复制定时函数 replicationCron(),比对slave发现长时间没有进行响应
最终结果 : maseter 各种资源(输出缓冲区、带宽、连接等)被严重占用
解决方案:通过设置合理的超时时间,确认是否释放slave
repl-timeout 该参数定义了超时间的阀值(默认60秒),超过该值,释放slave
哨兵
哨兵是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master
配置哨兵(sentinel.conf)
sentinel monitor mymaster 127.0.0.1 6379 2 监控的IP 端口号 名称 sentinel通过投票后认为mater宕机的数量,此处为至少
2
个
sentinel down-after-milliseconds mymaster 30000 30
秒ping不通主节点的信息,主观认为master宕机
sentinel parallel-syncs mymaster 1 故障转移后重新主从复制,
1
表示串行,>
1
并行
sentinel failover-timeout myymaster 180000 故障转移开始,三分钟内没有完成,则认为转移失败
启动哨兵
redis-sentined sentinel-端口号.conf
哨兵leader选举流程
集群(cluster)
配置
cluster-enabled yes 开启
cluster-config-file nodes-6379.conf cluster配置
cluster-node-timeout 30000 cluster下线时间
cluster-migrtion-barrier count master连接的slave最小数量
节点命令
cluster nodes 查看节点信息
cluster replicate master-id 进入从节点redis
cluster meet ip:port 新增主节点
cluster forget id 忽略一个没有solt的节点
cluster failover 手动故障转移
数据存储
crc16(key)%16384
生成集群配置
./redis-trib.rb create --replicas 1 ip......
daemonize yes
port 6379
dir /usr/local/redis/bin/redis-cluster/6379/
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
protected-mode no
appendonly yes
logfile redis.log
./redis-cli --cluster create --cluster-replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
#添加新的节点(主) redis-cli --cluster add-node 新节点IP:端口 已存在节点IP:端口
./redis-cli --cluster add-node 127.0.0.1:6385 127.0.0.1:6379
#添加新的从节点(从) cluster-master-id 为 127.0.0.1:6385 的runid
#redis-cli --cluster add-node 新节点IP地址:端口 存在节点IP:端口 --cluster-slave (从节点) --cluster-master-id (master节点的ID)
redis-cli --cluster add-node 127.0.0.1:6386 127.0.0.1:6379 --cluster-slave --cluster-master-id 87215b26c5aeceb602c5165fc2fbb58ec11c5e32
#rebalance平衡集群节点slot数量
./redis-cli --cluster rebalance 10.42.35.201:6379 --cluster-threshold 1 --cluster-use-empty-masters
Redis集群原理分析
槽位定位算法
跳转重定位
Redis集群节点间的通信机制
gossip:
网络抖动
Redis集群选举原理分析
集群是否完整才能对外提供服务
Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?
redisson分布式锁实现原理
redis失效机制
超时后只有对key执行DEL命令或者SET命令或者GETSET时才会清除。 这意味着,从概念上讲所有改变key的值的操作都会使他清除。 例如,INCR递增key的值,执行LPUSH操作,或者用HSET改变hash的field所有这些操作都会触发删除动作。
Redis如何淘汰过期的keys
Redis keys过期有两种方式:被动和主动方式。
当一些客户端尝试访问它时,key会被发现并主动的过期。
当然,这样是不够的,因为有些过期的keys,永远不会访问他们。 无论如何,这些keys应该过期,所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。
具体就是Redis每秒10次做的事情:
测试随机的20个keys进行相关过期检测。
删除所有已经过期的keys。
如果有多于25%的keys过期,重复步奏1.
这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys。
回收策略
当maxmemory限制达到的时候Redis会使用的行为由 Redis的maxmemory-policy配置指令来进行配置。
以下的策略是可用的:
noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
allkeys-random: 回收随机的键使得新添加的数据有空间存放。
volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
如果没有键满足回收的前提条件的话,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。
选择正确的回收策略是非常重要的,这取决于你的应用的访问模式,不过你可以在运行时进行相关的策略调整,并且监控缓存命中率和没命中的次数,通过RedisINFO命令输出以便调优。
一般的经验规则:
使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布,也就是说,你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么,这是个很好的选择。.
使用allkeys-random:如果你是循环访问,所有的键被连续的扫描,或者你希望请求分布正常(所有元素被访问的概率都差不多)。
使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值,来决定哪些对象应该被过期。
allkeys-lru 和 volatile-random策略对于当你想要单一的实例实现缓存及持久化一些键时很有用。不过一般运行两个实例是解决这个问题的更好方法。
为了键设置过期时间也是需要消耗内存的,所以使用allkeys-lru这种策略更加高效,因为没有必要为键取设置过期时间当内存有压力时。
回收进程如何工作
理解回收进程如何工作是非常重要的:
一个客户端运行了新的命令,添加了新的数据。
Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
一个新的命令被执行,等等。
所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。
如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。
近似LRU算法
Redis的LRU算法并非完整的实现。这意味着Redis并没办法选择最佳候选来进行回收,也就是最久未被访问的键。相反它会尝试运行一个近似LRU的算法,通过对少量keys进行取样,然后回收其中一个最好的key(被访问时间较早的)。
不过从Redis 3.0算法已经改进为回收键的候选池子。这改善了算法的性能,使得更加近似真是的LRU算法的行为。
Redis LRU有个很重要的点,你通过调整每次回收时检查的采样数量,以实现调整算法的精度。这个参数可以通过以下的配置指令调整:
maxmemory-samples 5
redis事务
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
为什么 Redis 不支持回滚(roll back)
以下是这种做法的优点:
Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
pipe mode的工作原理是什么?
难点是保证redis-cli在pipe mode模式下执行和netcat一样快的同时,如何能理解服务器发送的最后一个回复。
这是通过以下方式获得:
redis-cli –pipe试着尽可能快的发送数据到服务器。
读取数据的同时,解析它。
一旦没有更多的数据输入,它就会发送一个特殊的ECHO命令,后面跟着20个随机的字符。我们相信可以通过匹配回复相同的20个字符是同一个命令的行为。
一旦这个特殊命令发出,收到的答复就开始匹配这20个字符,当匹配时,就可以成功退出了。
同时,在分析回复的时候,我们会采用计数器的方法计数,以便在最后能够告诉我们大量插入数据的数据量。
redis复制是怎么进行工作
如果设置了一个slave,不管是在第一次链接还是重新链接master的时候,slave会发送一个同步命令 然后master开始后台保存,收集所有对修改数据的命令。当后台保存完成,master会将这个数据文件传送到slave,然后保存在磁盘,加载到内存中;master接着发送收集到的所有的修改数据的命令,这好比一个流命令,是redis协议本身来实现的。
你可以自己通过远程登录来进行尝试,当服务器在做一些工作并发送同步命令的时候链接到redis端口,你将会看到大量的数据传输,然后收到的每个命令会会显示在远程登录的会话中。
当master和slave因一些故障当机时,slaves会自动的重链,如果master收到多个slave的同步请求,master会执行一个后台保存,以确保所有的slaves都是正常的。
当master和slave能够维持链接,就会有一个完整的同步进行。
Redis 持久化
Redis 提供了不同级别的持久化方式:
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
快照
在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。你也可以通过调用 SAVE或者 BGSAVE , 手动让 Redis 进行数据集保存操作。
比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动保存一次数据集:
save 60 1000
这种持久化方式被称为快照 snapshotting.
工作方式
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
Redis 调用forks. 同时拥有父进程和子进程。
子进程将数据集写入到一个临时 RDB 文件中。
当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
只追加操作的文件(Append-only file,AOF)
快照功能并不是非常耐久(dura ble): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
你可以在配置文件中打开AOF方式:
appendonly yes
从现在开始, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。
日志重写
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 则可以自动触发 AOF 重写, 具体信息请查看 2.4 的示例配置文件。
AOF有多耐用?
你可以配置 Redis 多久才将数据 fsync 到磁盘一次。有三种方式:
每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全
每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。
推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。
如果AOF文件损坏了怎么办?
服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:
为现有的 AOF 文件创建一个备份。
使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复:
$ redis-check-aof –fix
(可选)使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。
工作原理
AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:
Redis 执行 fork() ,现在同时拥有父进程和子进程。
子进程开始将新 AOF 文件的内容写入到临时文件。
对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
怎样从RDB方式切换为AOF方式
在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :
为最新的 dump.rdb 文件创建一个备份。
将备份放到一个安全的地方。
执行以下两条命令:
redis-cli config set appendonly yes
redis-cli config set save “”
确保写命令会被正确地追加到 AOF 文件的末尾。
执行的第一条命令开启了 AOF 功能: Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。
执行的第二条命令用于关闭 RDB 功能。 这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。
重要:别忘了在 redis.conf 中打开 AOF 功能! 否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。
AOF和RDB之间的相互作用
在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。 反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。
如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行: 一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。 当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。
备份redis数据
在阅读这个小节前, 请牢记下面这句话: 确保你的数据由完整的备份. 磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。
Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。
这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。
创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。