redis

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重写作用

  1. 降低磁盘占用量,提高磁盘利用率
  2. 提高持久化效率,降低持久化写时间,提高IO性能
  3. 降低数据恢复用时,提高数据恢复效率

aof重写击规则

  1. 进程内已超时的数据不再写入文件
  2. 忽略无效指令,重写时使用进程内数据直接生成,这样就的AOF文件只保留最终数据的写入命令
  3. 对同一数据的多条写命令合并为一条命令

 

AOF工作原理

Redis 4.0 混合持久化

aof-use-rdb-preamble yes

 

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)

  1.   volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
  2.   volatile-lru: 挑选最近最少使用的数据跳台  
  3.   volatile-lfu: 挑选最近使用次数最少的数据
  4.    volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

  检测合库数据(所有数据集server.db[i].dict)  

  1.  allkeys-lfu: 挑选最近使用次数最少的数据
  2.  allkeys-lru: 挑选最近最少使用的数据跳台  
  3.   allkeys-random: 回收随机的键使得新添加的数据有空间存放。

 
 

主从复制

 

replicaof 192.168.0.60 6379        # (从节点) 从本机 6379 redis 实例复制数据
replica read only yes       只读

 

repl-backlog-size 1mb    设置主节点复制缓冲区的大小

 

 

 

 

  •  

 

  • 命令传播阶段出现了断网的现象
  1. 网络闪断闪连
  2. 短时间网络中断    部分复制
  3. 长时间断开           全量复制
  • 部分复制的三个核心要素
  1. 服务器的运行ID(run id)
  2. 主服务器的复制积压缓冲区
  3. 主从服务器的复制偏移量

 

服务器的运行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)

  • 概念: 一个数字,描述复制缓冲区中的指令字节位置
  • 分类:
  1. master 复制偏移量: 记录发送给所有slave的指令字节对应的位置(多个)
  2. slave 复制偏移量: 记录slave接收master发送过来的指令字节对应的位置(一个)
  • 数据来源
  1. master端:发送一次记录一次
  2. slave端:接收一次记录一次
  • 作用: 同步信息,比对master与slave的差异,当slave断线后,恢复数据使用

 

 

心跳机制

  • 进入命令传播阶段时,master与slave间需要进行信息交换,使用心跳机制时空行维护,实现双方连接保持在线
  • master心跳
  1. 指令:ping
  2. 周期: 由repl-ping-slave-period决定,默认10秒
  3. 作用: 判断slave是否在线
  4. 查询: info replication   获取slave最后一次连接时间间隔,lag项维持在0或1视为正常
  • slave心跳任务
  1. 指令: replconf ack {offset}
  2. 周期: 1秒
  3. 作用1: 汇报slave自已的复制偏移量,获取最新的数据变更指令
  4. 作用2: 判断master是否在线
  • 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作
  1.  min-slaves-to-write 2
  2. min-slaves-max-lag 8
  3. slave数量少于2个,或者所有slave的延迟都>=10秒时,强制关闭master写功能,停止数据同步
  • slave数量由slave发送 replconf ack命令确认
  • slave延迟由slave发送replconf ack命令确认

 

频繁的全量复制

伴随着系统的运行,master的数据量会赿来越大,一旦master重启,runid将发生变化,会导致全部slave的全量复制操作

内部优化调整方案:

  1. master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
  2. 在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

 建议修改

  1. 测算从master到slave的重连平均时长second
  2. 获取master平均每秒产生写命令数据总量 write_size_per_second
  3. 最优复制缓冲区空间  =  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选举流程

当一个master服务器被某sentinel视为客观下线状态后,该sentinel会与其他sentinel协商选出sentinel的leader进行故
障转移工作。每个发现master服务器进入客观下线的sentinel都可以要求其他sentinel选自己为sentinel的leader,选举
是先到先得。同时每个sentinel每次选举都会自增配置纪元(选举周期),每个纪元中只会选择一个sentinel的leader。如
果所有 超过一半 的sentinel选举某sentinel作为leader。之后该sentinel进行故障转移操作,从存活的slave中选举出新
的master,这个选举过程跟集群的master选举很类似。
哨兵集群只有一个哨兵节点,redis的主从也能正常运行以及选举master,如果master挂了,那唯一的那个哨兵节点就
是哨兵leader了,可以正常选举新master。
不过为了高可用一般都推荐至少部署三个哨兵节点。为什么推荐奇数个哨兵节点原理跟集群奇数个master节点类似。

 

 

集群(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......

redis‐cli ‐‐cluster create ‐‐cluster‐replicas ip.....
cluster info (查看集群信息)、 cluster nodes (查看节点列表)
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 Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点
中。
当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户
端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需
要纠正机制来实现槽位信息的校验调整。

槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体
槽位。
HASH_SLOT = CRC16(key) mod 16384

跳转重定位

当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自己管理,这时它会向客户端发送
一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。客户端收到指令后除了跳转到正
确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有 key 将使用新的槽位映射表。
 

Redis集群节点间的通信机制

redis cluster节点间采取gossip协议进行通信
维护集群的元数据有两种方式:集中式和gossip
集中式:
优点在于元数据的更新和读取,时效性非常好,一旦元数据出现变更立即就会更新到集中式的存储中,其他节点读取的
时候立即就可以立即感知到;不足在于所有的元数据的更新压力全部集中在一个地方,可能导致元数据的存储压力。

gossip:

gossip协议包含多种消息,包括ping,pong,meet,fail等等。
ping :每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元
数据;
pong : 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新;
fail : 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
meet :某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信,不需要
发送形成网络的所需的所有CLUSTER MEET命令。发送CLUSTER MEET消息以便每个节点能够达到其他每个节点只需通
过一条已知的节点链就够了。由于在心跳包中会交换gossip信息,将会创建节点间缺失的链接。
 
gossip协议的优点在于元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,找到所有节点上去更新,
有一定的延时,降低了压力;缺点在于元数据更新有延时可能导致集群的一些操作会有一些滞后。
   10000端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信
的就是17001端口。 每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping消息之后返
回pong消息。

网络抖动

真实世界的机房网络往往并不是风平浪静的,它们经常会发生各种各样的小问题。比如网络抖动就是非常常见的一种现
象,突然之间部分连接变得不可访问,然后很快又恢复正常。
为解决这种问题,Redis Cluster 提供了一种选项 cluster­-node­-timeout ,表示当某个节点持续 timeout 的时间失
联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换 (数据的重
新复制)。

Redis集群选举原理分析

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有
多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:
1.slave发现自己的master变为FAIL
2.将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
3.其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发
送一次ack
4.尝试failover的slave收集master返回的FAILOVER_AUTH_ACK 5.slave收到 超过半数master的ack 后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其
中一个挂了,只剩一个主节点是不能选举成功的)
6.广播Pong消息通知其他集群节点。
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在
集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
•延迟计算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
•SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持
有最新数据的slave将会首先发起选举(理论上)。

集群是否完整才能对外提供服务

当redis.conf的配置cluster-require-full-coverage为no时,表示当负责一个插槽的主库下线且没有相应的从库进行故
障恢复时,集群仍然可用,如果为yes则集群不可用。

Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?

因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂
了,是达不到选举新master的条件的。
奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相
比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点
了,所以奇数的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 服务器的物理机器之外。
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值