一、Redis基本数据类型
(1)String字符串类型
(2)list,常用来存储一个有序数据,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
(3)set,集合中不能出现重复的数据。它的底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
(4)sorted set,不允许重复的成员。每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
(5)Hash,也叫散列,可以将对象中的每个字段独立存储
二、缓存穿透
缓存穿透:当查询一个不存在的数据时,如果从存储层查不到这个数据,就不会将其缓存到redis,这就导致每次访问该数据时,都会请求到DB,次数增加就可能导致DB挂掉。
解决方案:
1.缓存空数据(返回空值)
访问第一次时打入DB,这个时候将空值缓存到redis,当再次访问时直接返回空值即可。
优点:简单。缺点:数据一致性差(当DB中修改值后,redis中仍然为空值)。
2.使用布隆过滤器
布隆过滤器主要是用于检索一个元素是否在一个集合中。
首先要预热布隆过滤器,当过滤器中没命中则直接返回结果。
(redisson)实现的布隆过滤器为例:它的底层主要是先去初始化一个比较大数组,里面存放的二进制0或1。在开始都是0,当一个key来了之后经过3次hash计算,模于数组长度找到数据的下标然后把数组中原来的0改为1,这样的话,三个数组的位置就能标明个key的存在。查找的过程也是一样的。
当然是有缺点的,布隆过滤器有可能会产生一定的误判,我们一般可以设置这个误判率,大概不会超过5%,其实这个误判是必然存在的,要不就得增加数组的长度,其实已经算是很划分了,5%以内的误判率一般的项目也能接受,不至于高并发下压倒数据库。
二、缓存击穿
缓存击穿:发生在一个key设置了过期时间,恰好过期后,被高并发访问,这时还没来得及缓存重建,瞬间导致DB挂掉。
解决方案:
1.互斥锁
这里又要考虑是否是单个实例,对于单个实例可以使用同步锁(sync),但是大部分微服务项目是多个实例,这时候需要使用分布式锁。
当缓存失效时,不立即去load db,先使用如 Redis 的setnx 去设置一个互斥锁,当操作成功返回时再进行 load db的操作并回设缓存,否则重试get缓存的方法。
优点:一致性强。缺点:性能低,可能导致死锁(释放锁前redis挂了)。
2.设置key为逻辑过期
①:在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前
key设置过期时间
②:当查询的时候,从redis取出数据后判断时间是否过期
③:如果过期则开通另外一个线程进行数据同步,当前线程正常返回数据,
这个数据不是最新。
优点:高可用。缺点:低一致性。
三、缓存雪崩
缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效或者redis服务器宕机,请求全部转发到DB,DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多key,击穿是某一个key缓存。
解决方案:
1.给key的TTL设置随机值 (多个key同时失效)
比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
2.缓存预热
后台可以设置定时任务,比如使用xxl-job每隔10分钟缓存一次数据
3.利用redis集群提高服务可用性
(哨兵模式,集群模式)
4.添加降级限流策略
Nginx或者pring cloud gateway
5.添加多级缓存
Caffeine或者Guava
四、Redis双写问题
方法一:主动更新(延迟双删)
使用先删除缓存,后改数据库;或者先修改数据库再删除缓存(异常相对低);
延迟双删:删除缓存->更新数据库->删除缓存(更好的避免读脏数据,但无法完全避免)
方法二:采用的阿里的canal组件实现数据同步
不需要更改业务代码,部署一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后在通过canal的客户端获取到数据,更新缓存即可。
方法三:读写锁
采用的是redisson实现的读写锁,在读的时候添加共享锁,可以保证读读不互斥,读写互斥。当我们更新数据的时候,添加排他锁,它是读写,读读都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。这里面需要注意的是读方法和写方法上需要使用同一把锁才行。
五、Redis持久化
1. RDB(redis database backup file) (备份)快照文件
把内存中的所有数据都记录在磁盘中。
缺点:执行间隔长,两次RDB间写入数据容易丢失。
2. AOF(append only file) 追加文件
redis中每一个读命令记录在其中,可以看作为命令日志文件。
缺点:文件体积大,容易产生冗余命令或者无效命令。
六、Redis事务
Redis的事务(transaction)允许在一个单独的操作序列中执行多个命令,并保证这些命令在其他客户端无法中断的情况下执行。
Redis事务的基本命令
MULTI:开启一个事务块。
EXEC:执行所有在事务块中排队的命令。
DISCARD:取消事务,放弃事务块中的所有命令。
WATCH:监视一个或多个键,如果在事务执行之前这些键被修改,那么事务将被取消。
Redis事务的使用步骤
1.使用MULTI命令开始一个事务。
2.执行一系列的命令,这些命令将被放入事务队列中,而不会立即执行。
3.使用EXEC命令提交事务,所有的命令将按顺序执行。
4.如果在事务开始后但在执行之前需要取消事务,可以使用DISCARD命令。