Redis是一个开源使用ANSI C语言编写、支持网络、基于内存可持久化的日志型、Key-Value数据库,提供多种语言的API。
不适合的场景:
数据量太大:会增加成本,
访问频率太低:保存在内存中纯属浪费资源
1、String字符串(键)
使用场景:缓存、计数器、共享Session、限速
2、Hash哈希
使用场景:本身就是键值对结构,,比字符串序列化更加直观,更新操作更加便捷
3、List列表
使用场景:列表类型是用来存储多个有序的字符串,还可以获取指定范围的元素列表、获取指定索引下的元素,Redis的lpush + brpop命令组合即可实现阻塞队列,生产者客户端是用lpush从列表左侧插入元素,多个客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用。
4、Set集合
和列表不同的是不允许有重复元素,并且是无序的,不能通过索引下标获取元素,但是支持集合内的增删改查,支持多个集合取交集、并集、差集。
5、zset(sortedset)有序集合
使用场景:给每个元素设置一个分数,作为排序的依据,排行榜,以及榜单维护可能是:按照时间、按照播放量、按照获得的赞数等。
用户查询一个一定不存在的数据,刚开始在缓存中查询不到,于是就去数据库中查询,查询不到,数据也不写入缓存,这就导致每次查询这个不存在的数据都去数据库中查询
解决办法:
缓存空对象,如果返回的数据为空,我们仍然把空结果进行缓存,过期时间设置很短(5分钟)。
缓存空对象存在的问题
1、需要更多的内存空间,设置较短的过期时间
2、缓存和存储的数据会有一段时间窗口的不一致,可能对业务造成影响,可以用消息系统或其他方式清除掉缓存层的空对象。
布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,避免了对底层存储系统的查询压力。
缓存集中在一段时间失效,所有查询落在数据库上
解决办法:
1.在缓存的时候给过期时间加上一个随机值,大幅度减少缓存同一时间过期。
2.加锁排队:缓存失效后,通过加锁或队列来控制读数据库写缓存的线程数量,如:对于某一个key只允许一个线程查询数据和写缓存,其他线程等待;
3.数据预热:通过缓存reload机制,先去更新缓存,即将发生大并发前手动触发加载不同的key,设置不同的过期时间,尽量让失效时间均匀。
4.做二级缓存(双缓存策略)cache1为原始缓存,cache1为拷贝缓存,cache1失效,可以访问cache2,原始失效时间为短期,拷贝失效时间为长期。
仍然存在问题,更新数据库成功了,但是删除缓存没有删除成功,再读缓存每次都是错误的数据了
利用消息队列
对业务代码造成大量侵入,耦合在一起
订阅mysql数据库的binlog日志对缓存进行操作
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。RDB(默认)和AOF
RDB
Redis DataBase的缩写。按照一定的周期策略把内存的数据以快照的形式保存到硬盘的二进制文件,即Snapshot快照存储,数据文件为dump.rdb,通过配置文件中的save参数定义快照的周期。
rdbSave:生成RDB文件,
rdbLoad:从文件加载到内存
AOF
AOF是Append-only file的缩写,Redis会将每一个收到的写的命令都通过Write函数追加到文件最后,类似于MySQL的binlog。Redis重启是会通过执行文件中保存的写命令在内存中重建整个数据库的内容。每当执行服务器任务或函数时,flushAppendOnlyFile函数都会被调用:
write:根据条件,将aof_buf中的缓存写入到AOF文件;
save:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中
区别:
volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰;
volatile-ttl:从已设置过期时间的数据集中挑选要过期的数据淘汰;
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰;
allkeys-lru:从所有数据集中挑选最近最少使用的数据淘汰;
allkeys-random:从所有数据集中任意选择数据进行淘汰;
noeviction:禁止驱逐数据;
Redis的淘汰算法实际实现上并非对所有key,而是抽样一小部分并且从中选出被淘汰的key。
保证缓存的数据都是热点数据,可以将内存最大使用量设置为热点数据占用的内存量,然后启用allkeys-lru,淘汰策略,将最近最少使用的数据淘汰;
Redis4.0引入了volatile-lfu和allkeys-lfu淘汰策略,通过统计访问的频率,将频率访问最少的键值对淘汰。