Redis缓存相关详解 桃扇骨 2022-12-26 10:18 86阅读 0赞 字符串(string)、散列(hash)、列表(lists、集合(set)、有序集合(sorted set) redis持久化操作,第一种是 rdb 形式,一种是 aof 形式 rdb:属于全量数据备份,备份的是数据 aof:append only if , 增量 持久备份,备份的是指令 如 【set key , del key】 redis 作为缓存的使用,搭配数据库使用的两种方案: 1.jedis整合使用方案 第一层在缓存进行查询,如果查询到数据则直接返回,如果查不到数据则到数据库中查询,并且刷新添加缓存 2.作为mybatis/hibernate二级缓存使用方案 一级缓存: sqlSession 进程缓存,单次链接有效 ## 一、String相关操作 ## String操作类型: Set key value 设置key,value Get key 获得值key对应的value的值 Strlen key 获得key对应的value的长度 Incr key 对key对应的value的值自增1 Incrby key 【数字】 指定数字递增 Decr key 对key对应的value的值自减1 Decrby key 【数字】 指定数字递减 Getrange key 0 -1 显示指定范围的key对应的value值(0到-1显示全部) Setrange key 0 x 从零开始,修改原来的值,将原来的修改;原来为“10”执行后为“x0” Setex key 【过期时间秒】 value 设置值的同时给定过期时间 Setnx key value 若key不存在,设置value值才会成功【可用于分布式锁】 Mset key value key value key value 一次性设置多个值 Mget key key key 一次性获得多个值 Msetnx key value key value 一次性设置多个之前不存在的值,若其中有一个key存在的话就不会成功 ## 二、list相关操作 ## list操作类: Lpush key value value value 存值,结果[先进后出] Rpush key value value value 存值,结果按顺序,[先进先出] Lrange key 0 -1 查看list中的数据(0到-1显示全部) Lpop key 出栈,从左到右,每次出栈一个元素,相当于从list中删除 Rpop key 出栈,从右到左,每次出栈一个元素,相当于从list中删除 Lindex key 【下标】 具体显示list中角标对应的值,从0开始计数 Lrem key 【数字】 【元素】 删除list中几个相同的元素 Ltrim key 【下标1】【下标2】 截取出保存下标1到下标2的元素,其他下标对应的元素被删除 Lset key 【下标】 【元素】 修改list数字中对应下标的元素 Linsert key before/after 【元素1】【元素2】 在元素1的前面/后面 插入元素2,若元素1有多个,则只对最前面的那个匹配元素1的元素的前后进行操作 r是对底部进行操作,l是对顶部进行操作 ## 三、set相关操作 ## set操作: Sadd key 【元素1】【元素2】【元素3】 一次性添加多个元素,会自动去重 Smembers key 查看当前key中的所有元素 Scard key 获取元素个数 Srem key 【元素】【元素】【元素】 删除指定元素 Srandmember key 【数字】 在指定的set中随机的显示三个数字 Spop key 【数字】 随机出栈指定的个数个元素 Smove key1 key2 【key1中的元素】 将key1中的元素剪切到key2中 Sdiff key1 key2 显示出存在于set1中但不存在于set2中的元素 Sinter key1 key2 显示出key1和key2共同拥有的元素 交集 Sunion key1 key2 显示出key1和key2两者相加的所有元素 并集 ## 四、hash相关操作 ## **hash的结构类似于 Map< String, Map<Object, Object> >** hash操作: 键值对 Hset hash key1 value1 key2 value2 设置值,hash允许重复 当key重复的时候会覆盖前面出现的key Hget hash key 获取value Hgetall hash 获取所有的key和value Hmset hash key1 value1 key2 value2 一次存一个对象的多个不同的value Hdel hash key 删除指定的key Hlen hash 查看长度 Hexists hash key 判断hash中key是否存在 Hkeys hash 获取所有的key值 Hvals hash 获取所有的value值 Hincrby hash key 【整数数字】 指定的key按指定的数字递增 Hincrbyfloat hash key 【小数】 指定的key按指定的小数递增 Hsetnx hash key value 若key值在hash中不存在就添加 ## 五、zset相关操作(有序集合) ## zset操作:有序集合 key不允许重复 zset(key value)key值必须是数字(key为序号,依据此序号来排序) Zadd zset key1 value1 key2 value2 一次性添加多个数据 Zrange zset 0 -1 显示所有的value值,当范围为 0 到 -1 时显示全部,下标从0开始 Zrange zset 0 -1 withscores 现在所有的key和value,当范围为 0 到 -1 时显示全部,下标从0开始 Zrangebyscore zset 【key1】【key2】 显示key1到key2之间的key的值(包含数字1和数字2) 数字2比数字1大 Zrangebyscore zset 【(key1】【key2】 显示key1到key2之间的key的值(加了前括号就不包含改数字) zrangebyscore zset 【key1】【key2】 limit【key3】【数字4】 从结果中截取key3开始截取 数字4 个元素 Zrem zset value1 value2 value3 删除指定的key中的value Zcard zset 统计zset中key的个数 Zcount zset 【key1】【key2】 统计key1到key2之间的key个数 Zrank zset value 通过value的值value所在的下标 Zscore zset value 获取key的值 Zrevrank zset value 显示倒叙过来的下标 Zrevrange zset 0 -1 倒叙显示所有value Zrevrangbyscore zset [key1] [key2] 倒叙显示key1到key2的之间的value值 这里key1比key2大 ## 六、redis相关操作 ## Redis 默认有16个数据库,即16个database Select 【数字】 转到第几个数据库 Dbsize 查看当前数据库有多少个key Keys * 当前库的key查询出来 Flushdb 清除当前库 Flushall 清除所有库 Auth 【密码】 认证密码 Exists【key的名字】 判断某个key是否存在 Move key 【db序号】 将当前库的key剪切到指定db序号 Expire key【时间秒】 为给定的key设置过期时间,过期后会移除系统 Ttl key 查看还有多少秒过期,-1表示永远不过期,-2表示已过期 Type key 查看你的key是什么类型 Del key 删除key 事务ACID特性: 原子性:事务作为一个整体被执行,包含在其中对数据的操作要么全部被执行,要么都不执行 一致性:事务应该确保数据库的状态从一个一致的状态转变成另一个一致的状态。 隔离性:多个事务并发执行时,一个事务的执行不应该影响其他事务的执行 持久性:已被提交的事务对数据库的修改应该永久被保存在数据库中 ## 七、redis集群 ## ![385861ba42b4b9dc6cc620d679739d46.png][] ### master-slaver 一主二从 ### master 配置文件:redis-6379.conf port 6379 daemonize yes logfile "6379.log" dbfilename "dump-6379.rdb" dir "/opt/soft/redis/data" slave-1 配置文件:redis-6380.conf port 6380 daemonize yes logfile "6380.log" dbfilename "dump-6380.rdb" dir "/opt/soft/redis/data" # 关键配置:将这个 redis 指定为某个第一个 redis 的 slaver slaveof 127.0.0.1 6379 slave-2 配置文件:redis-6381.conf port 6381 daemonize yes logfile "6381.log" dbfilename "dump-6381.rdb" dir "/opt/soft/redis/data" # 关键配置:将这个 redis 指定为某个第一个 redis 的 slaver slaveof 127.0.0.1 6379 ### sentinel集群 ### sentinel-26379.conf #设置 sentinel 工作端口 port 26379 #后台运行 daemonize yes #日志文件名称 logfile "26379.log" #设置当前 sentinel 监控的 redis ip 和 端口 sentinel monitor mymaster 127.0.0.1 6379 2 #设置判断 redis 节点宕机时间 sentinel down-after-milliseconds mymaster 60000 #设置自动故障转移超时 sentinel failover-timeout mymaster 180000 #设置同时故障转移个数 sentinel parallel-syncs mymaster 1 sentinel-26380.conf #设置 sentinel 工作端口 port 26380 #后台运行 daemonize yes #日志文件名称 logfile "26380.log" #设置当前 sentinel 监控的 redis ip 和 端口 sentinel monitor mymaster 127.0.0.1 6379 2 #设置判断 redis 节点宕机时间 sentinel down-after-milliseconds mymaster 60000 #设置自动故障转移超时 sentinel failover-timeout mymaster 180000 #设置同时故障转移个数 sentinel parallel-syncs mymaster 1 sentinel-26381.conf #设置 sentinel 工作端口 port 26391 #后台运行 daemonize yes #日志文件名称 logfile "26381.log" #设置当前 sentinel 监控的 redis ip 和 端口 sentinel monitor mymaster 127.0.0.1 6379 2 #设置判断 redis 节点宕机时间 sentinel down-after-milliseconds mymaster 60000 #设置自动故障转移超时 sentinel failover-timeout mymaster 180000 #设置同时故障转移个数 sentinel parallel-syncs mymaster 1 针对几个监控设置的配置做一下详细说明: * **sentinel monitor \[master-group-name\] \[ip\] \[port\] \[quorum\]** 这个命令中【master-group-name】是 master redis 的名称;【ip】和【port】分别是其 ip 和端口,很好理解。最后一个参数【quorum】是”投票数“ 举个栗子,redis 集群中有3个 sentinel 实例,其中 master 挂掉了,如果这里的票数是2,表示有2个 sentinel 认为 master 挂掉啦,才能被认为是正真的挂掉啦。其中 sentinel 集群中各个 sentinel 之间通过 gossip 协议互相通信。 具体怎样投票还涉及到 redis 集群中的【主观下线】和【客观下线】的概念,后面再详细介绍。 * **down-after-milliseconds** sentinel 会向 master 发送心跳 PING 来确认 master 是否存活,如果 master 在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个 sentinel 会主观地认为这个 master 已经不可用了。而这个down-after-milliseconds 就是用来指定这个“一定时间范围”的,单位是毫秒。 * **failover-timeout** 这个参数 redis 官方文档中并未做详细说明,但是很好理解,就是 sentinel 对 redis 节点进行自动故障转移的超时设置,当 failover(故障转移)开始后,在此时间内仍然没有触发任何 failover 操作,当前sentinel 将会认为此次故障转移失败。 * **parallel-syncs** 当新master产生时,同时进行 slaveof 到新 master 并进行同步复制的 slave 个数,也就是同时几个 slave 进行同步。因为在 salve 执行 salveof 与新 master 同步时,将会终止客户端请求,因此这个值需要权衡。此值较大,意味着“集群”终止客户端请求的时间总和和较大,此值较小,意味着“集群”在故障转移期间,多个 salve 向客户端提供服务时仍然使用旧数据。 我们配置三个 sentinel 几点组成一个 sentinel 集群,端口分别是 23679,23680,23681 然后就可以启动 sentinel 集群了 启动 sentinel 有两种方式: 1. `redis-sentinel /path/to/sentinel.conf` 2. `redis-server /path/to/sentinel.conf --sentinel` ## 八、缓存穿透 ## * 什么是缓存穿透?你有什么解决方案来防止缓存穿透? * 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候, 在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次 无用的查询)。这样请求就绕过缓存直接查数据库 * 你有什么解决方案来防止缓存穿透? * **采用布隆过滤器BloomFilter** * 将所有可能存在的数据哈 希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力 * **缓存空值** * 如果一个查询返回的数据为空(不管是数据不 存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库 ## 九、缓存雪崩 ## 什么是缓存雪崩?你有什么解决方案来防止缓存雪崩? * 如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。 由于原有缓存失效,新缓存未到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU 和内存造成巨大压力,严重的会造成数据库宕机 * 你有什么解决方案来防止缓存雪崩? * **加锁排队** * key: whiltList value:1000w个uid 指定setNx whiltList value nullValue mutex互斥锁解决,Redis的SETNX去set一个mutex key, 当操作返回成功时,再进行load db的操作并回设缓存; 否则,就重试整个get缓存的方法 * **数据预热** * 缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key * **双层缓存策略** * C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。 * **定时更新缓存策略** * 失效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存 去set一个mutex key, 当操作返回成功时,再进行load db的操作并回设缓存; 否则,就重试整个get缓存的方法 * **数据预热** * 缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key * **双层缓存策略** * C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。 * **定时更新缓存策略** * 失效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存 * **设置不同的过期时间,让缓存失效的时间点尽量均匀** [385861ba42b4b9dc6cc620d679739d46.png]: /images/20221120/1f8451dddad34cff9d5005836abdfb84.png
还没有评论,来说两句吧...