0%

Redis 实战

单线程、IO多路复用的非关系性 K-V 数据库,数据存在内存,操作快,可支持持久化磁盘,常用来做为缓存数据库。

1. 数据类型

  • String
  • List
  • Set
  • Hash
  • Sorted Set(ZSET)

    和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。

2. 过期键删除策略

  • 定时删除,创建一个定时器,键过多时,会占用CPU一部分时间
  • 定期删除,定期随机抽取一部分键,检查是否过期,过期就删除
  • 惰性删除,通过定期删除并不能保证一定会被删除,这时,如果在访问时,发现这个键已过期,那么就会删除
  • 定时删除 浪费CPU资源,生产中不推荐使用

    定期删除和惰性删除并不一定能够删除过期键,例,定期删除中的随机抽取,并未抽取到,过期期间内,用户并未访问,那么这个键就会一直在内存中。怎么解决这个问题呢? Redis 内存淘汰机制。

3. 内存淘汰机制

  • 1、volatile-lru

    从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • 2、volatile-ttl

    从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • 3、volatile-random

    从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • 4、allkeys-lru

    当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

  • 5、allkeys-random

    从数据集(server.db[i].dict)中任意选择数据淘汰

  • 6、no-eviction

    禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

  • 7、volatile-lfu

    从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰

  • 8、allkeys-lfu

    当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

4. 持久化

  • RDB 快照持久化

    在只使用RDB持久化时,若系统崩溃,将丢失最近一次快照之后的所有数据。

  1. 发送 BGSAVE 命令创建快照(Windows 平台不支持)。 Redis创建一个子进程,子进程负责将快照写入磁盘,父进程继续处理命令请求
  2. 发送 SAVE 命令创建快照,接到该命令后Redis服务器将在快照创建完毕前不再相应任何其他命令。该命令不常用。
  3. SAVE m n 配置触发。例如 save 60 10000,那么Redis最近一次创建快照开始算起,当“60秒内有10000次写入”这个条件满足时,Redis会自动触发 BGSAVE 命令。若用户配置多个,任意规则满足时都能触发。
  4. Redis 通过 SHUTDOWN 命令接受到关闭服务器的请求时,或者接受到标准 TERM 信号时,会执行save命令,阻塞所有客户端,save命令结束后关闭服务器。
  5. 当一个服务器连接另一个服务器时,并向对方发送 SYNC 命令复制时,如果主服务器目前没有在执行BGSAVE 操作,或者最近也为执行BGSAVE操作,那么主服务器就会执行BGSAVE命令
  • AOF

AOF会将被执行的命令写到AOF文件的末尾,以此来记录数据发生的变化。

同步频率 appendfsync

  • always: 每个命令都同步写入磁盘,会严重降低Redis速度
  • everysec: 每秒执行一次,显示的将多个写命令同步到磁盘
  • no: 让操作系统决定何时进行同步

重写/压缩 AOF文件

  • 1、向Redis发送BGREWRITEAOF命令,会移除AOF文件中的冗余命令来重写AOF文件,使AOF文件体积变小。该命令和BGSAVE创建快照命令类似,Redis会创建一个子进程,由子进程负责对AOF文件进行重写。

  • 2、与快照SAVE命令一样,AOF 持久化可通过auto-aof-rewrite-min-size、auto-aof-rewrite-percentage来自动执行BGWRITEAOF文件

    • auto-aof-rewrite-min-size: AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。

    • auto-aof-rewrite-percentage:当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。

      两个配置 之间是并的关系,同时满足才会进行压缩

5. 事务

Redis 事务是一组命令的集合。开启事务后,命令会顺序放入事务命令队列,执行事务时,会按照顺序串行执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令队列中。
总的来说,Redis事务就是一次性、顺序行、排他性的执行一个队列中的一系列命令。
https://www.cnblogs.com/DeepInThought/p/10720132.html

  • 相关命令

    • watch key1 key2 … : 监视一或多个key,如果在事务执行之前被监视的key被其他客户端改动,则事务被打断 ( 类似乐观锁 )
    • multi : 标记一个事务块的开始( queued )
    • exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 ) 
    • discard : 取消事务,放弃事务块中的所有命令
    • unwatch : 取消watch对所有key的监控
  • 若事务队列中存在命令性错误(类似java编译错误),执行exec命令时,命令队列中所有的命令都不会被执行

  • 若事务队列中存在运行时错误(类似java中运行异常),执行exec命令时,其他命令会执行,错误的命令抛出异常

  • watch命令和事务组合使用时

    一但执行 EXEC 开启事务的执行后,无论事务使用执行成功, WARCH 对变量的监控都将被取消。

    • 事务执行时,watch 检测的键值未变动,则事务能够正常提交
    • 事务执行时,watch 检测的键值被更改,事务将会失败,并且命令队列中的命令也不会执行

6. 应用

  • 分布式锁

    • SETNX 命令
  • 信号量

    在获取信号量时,要保证加锁,否则,后者仍有可能偷走前者的排名。详情见 《Redis 实战》 6.3.4 消除竞态条件

    • 基础信号量

      ZSET 集合,值为线程的随机字符串,分数为当前时间戳。根据当前线程所在集合的排名,判断是否获取到信号量。也就是根据时间戳的大小进行排名。

    • 公平信号量

      集群环境下,若时间相差在秒以下级别,慢的节点会优先于快的节点,故产生不公平现象

      在基础信号量的前提下,增加一个自增的k-v和另一个ZSET集合,这个ZSET集合的分数为自增序列的值。基础信号量的ZSET用作超时处理,后者的ZSET真正用作信号量的排名

  • 任务队列

    • 先进先出队列、后进先出队列、优先级队列等
  • 消息拉取

    • 消息拉取与 Redis发布/订阅 不同。当消费者下线时,就会错失一部分消息

7. 扩展

  • Redis搜索

    • 反向索引、差集、并集、交集、排序。。。。
  • Redis性能

    • 读性能

      默认情况下,只有主服务器可以写入

      • 从服务器树

      • 哨兵模式

        Redis Sentinel 可以配合Redis 的复制功能使用,并对下线的主服务器进行故障转移。Redis
        Sentinel是运行在特殊模式下的Redis 服务器,
        Sentinel会监视- -系列主服务器以及这些主服务器的从服务器,通过向主服务器发送PUBLISH .
        命令和SUBSCRIBE命令,并向主服务器和从服务器发送PING命令,各个Sentinel 进程可以自
        主识别可用的从服务器和其他Sentinel。当主服务器失效的时候,监视这个主服务器的所有
        Sentinel就会基于彼此共有的信息选出一个Sentinel,并从现有的从服务器当中选出一个新的主服务器。当被选中的从服务器转换成主服务器之后,那个被选中的Sentinel就会让剩余的其他从服务器去复制这个新的主服务器(在默认设置下,Sentinel 会-一个接一个地迁移从服务 器,但这个数量可以通过配置选项进行修改)。
        一般来说,使用Redis Sentinel的目的就是为了向主服务器属下的从服务器提供自动故障转
        移服务。此外,Redis Sentinel还提供了可选的故障转移通知功能,这个功能可以通过调用用户提供的脚本来执行配置更新等操作。

    • 写性能

  • 分片

    • 降低内存占用

      • Redis 压缩,短结构、分片
  • Lua脚本编程

    Lua脚本和单个Redis命令一样以及事务命令一样都是原子操作。
    已经对结构进行了修改的Lua脚本将无法被中断。若只是读命令,可以 SCRIPT KILL命令杀死;若是写命令,杀死脚本将会发生数据不一致的状态,这种情况下唯一能做的就是杀死Redis 服务器,这回导致最近一次快照和最近一次写入AOF文件之后的数据发生所有的变化