1.sortedSet底层
sortedset中的每一个元素都带有一个score属性可以基于score属性对元素进行排序,底层的实现是一个跳表加hash表。
可排序元素不重复
查询速度快
2.NoSQL和SQL
SQL
1对数据的格式有严格的约定
Table必须定义每个属性的数据格式
每个Table必须含有主键
只能存储Table格式的数据
2允许Table之间建立联系
支持不同Table之间建立一对一、一对多、多对一、多对多的关系
支持Join操作来基于关系进行联合查询
3有统一的查询语言
所有的关系型数据库都支持基于SQL的查询语言
NoSQL
对数据格式没有约束
可以存储文档、图、Key-Value等等
每个存储对象是一个集合,集合内的元素可以是各种形式
数据之间一般没有或只有很少的关联
没有统一的查询语言,每个数据库都会提供自己的API接口
3.缓存穿透
缓存穿透:查询一个不存在的数据, mysql 查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库
解决方案
1.缓存空数据,查询返回的数据为空,仍把这个结果进行缓存
2.布隆过滤器
什么是布隆过滤器
布隆过滤器主要是用于检索一个元素是否在一个集合中。我们当时使用的是redisson实现的布隆过滤器。
它的底层主要是先去初始化一个比较大数组,里面存放的二进制0或1。在一开始都是0,当一个key来了之后经过3次hash计算,模于数组长度找到数据的下标然后把数组中原来的0改为1,这样的话,三个数组的位置就能标明一个key的存在。查找的过程也是一样的。
当然是有缺点的,布隆过滤器有可能会产生一定的误判,我们一般可以设置这个误判率,大概不会超过5%,其实这个误判是必然存在的,要不就得增加数组的长度,其实已经算是很划分了,5%以内的误判率一般的项目也能接受,不至于高并发下压倒数据库。
4.缓存击穿
缓存击穿的意思是指某一热点数据存储到Redis中,该数据处于并发场景下,如果此时该key过期失效,这样就会有大量并发请求进入数据库,对数据库产生巨大压力甚至压跨数据库。
解决方案:
第一可以使用互斥锁:当缓存失效时,不立即去load db,先使用如 Redis 的 setnx 去设置一个互斥锁当操作成功返回时再进行load db的操作并回设缓存,否则重试get缓存的方法
setnx
第二种方案可以设置当前key逻辑过期,大概是思路如下:
①:在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前key设置过期时间
2):当查询的时候,从redis取出数据后判断时间是否过期
3:如果过期则开通另外一个线程进行数据同步,当前线程正常返回数据,这个数据不是最新
当然两种方案各有利弊:
如果选择数据的强一致性,建议使用分布式锁的方案,性能上可能没那么高,锁需要等,也有可能产生死锁的问题
如果选择key的逻辑删除,则优先考虑的高可用性,性能比较高,但是数据同步这块做不到强一致。
5.什么是缓存雪崩
缓存雪崩意思是设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多key,击穿是某一个key缓存。
给不同的 Key 的 TTL 添加随机值
利用 Redis 集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存
6.缓存的更新策略
主动更新策略
1.Cache Aside Pattern用的最多
由缓存的调用者在更新数据库的同时更新缓存
2.Read/Write Through Pattern
缓存与数据库整合为一个服务,由服务来维护一致性,调用者调用该服务无需关心缓存一致性问题
3.write behind caching pattern
调用者只操作缓存,由其它线程异步的将缓存数据持久化到数据库保证最终一致
7.Redis持久化,哪种恢复快
RDB是一个快照文件,它是把redis内存存储的数据写到磁盘上,当redis实例宕机恢复数据的时候,方便从RDB的快照文件中恢复数据。
AOF的含义是追加文件,当redis操作写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次执行一遍命令来恢复数据
RDB因为是二进制文件,在保存的时候体积也是比较小的,它恢复的比较快,但是它有可能会丢数据,我们通常在项目中也会使用AOF来恢复数据,虽然AOF恢复的速度慢一些,但是它丢数据的凤险要小很多,在AOF文件中可以设置刷盘策略,我们当时设置的就是每秒批量写入一次命令
bgsave 开始时会 fork 主进程得到子进程,子进程共享主进程的内存数据。完成 fork 后读取内存数据并写入 RDB 文
件。
fork 采用的是 copy-on-write 技术:
• 当主进程执行读操作时,访问共享内存;
• 当主进程执行写操作时,则会拷贝一份数据,执行写操作
8.Redis的数据过期策略有哪些?
第一种是惰性删除,在设置该key过期时问后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。第二种是 定期删除,就是说每隔一段时间,我们就对一些key进行检查,删除里面过期的key定期清理的两种模式:
SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf的 hz 选项来调整这个次数
FAST模式执行频率不固定,每次事件循环会尝试执行,但两次间隔不低于2ms,每次耗时不超过1ms
Redis的过期删除策略:惰性删除+定期删除两种策略进行配合使用。
9.Redis 数据淘汰策略
当 Redis 中的内存不够用时,此时在向 Redis 中添加新的 key ,那么 Redis 就会按照某一种规则将
内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。
Redis 支持 8 种不同策略来选择要删除的 key :
noeviction : 不淘汰任何 key ,但是内存满时不允许写入新数据,默认就是这种策略。
volatile-ttl : 对设置了 TTL 的 key ,比较 key 的剩余 TTL 值, TTL 越小越先被淘汰
allkeys-random :对全体 key ,随机进行淘汰。
volatile-random :对设置了 TTL 的 key ,随机进行淘汰。
allkeys-lru : 对全体 key ,基于 LRU 算法进行淘汰
volatile-lru : 对设置了 TTL 的 key ,基于 LRU 算法进行淘汰
allkeys-lfu : 对全体 key ,基于 LFU 算法进行淘汰
volatile-lfu : 对设置了 TTL 的 key ,基于 LFU 算法进行淘汰
使用建议
优先使用 allkeys-lru 策略。充分利用 LRU 算法的优势,把最近最常访问的数据留在缓存中。如果业务有明显
的冷热数据区分,建议使用。
2. 如果业务中数据访问频率差别不大,没有明显冷热数据区分,建议使用 allkeys-random ,随机选择淘汰。
3. 如果业务中有置顶的需求,可以使用 volatile-lru 策略,同时置顶数据不设置过期时间,这些数据就一直不被删
除,会淘汰其他设置过期时间的数据。
4. 如果业务中有短时高频访问的数据,可以使用 allkeys-lfu 或 volatile-lfu 策略。
10.Redis分布锁如何实现
在redis中提供了一个命令setnx
由于redis的单线程的,用了命令之后,只能有一个客户端对某一个key设置值,在没有过期或删除key的时候是其他客户端是不能设置这个key的
如何实现分布锁的有效时长
redis的setnx指令不好控创这个问题,我们当时采用的reds的一个框架redisson实现的。
在redisson中需要手动加锁。并且可以控制锁的失效时间和等待时间。当锁住的一个业务还没有执行完成的时候,作redisson中引入了一个看门狗机制,就是说每隔一段时间就检查当前业务是否还持有锁,如果持有就增加加锁的持有时间,当业务执行完成之后需要使用释放锁就可以了
还有,个好处就是,在高并发下,业务有可能会执行很快。如果客户1有锁的时候。客户2来了以后并不会马上拒绝,它会不断尝试获取,如果客户1释放放之后,客户2可以马上有,性能得到了提升。
分布式锁可以重入吗
嗯,是可以重入的。这样做是为了避免死锁的产生。这个重入其实在内部就是判断是否是当前线程持有的锁。如果是当前线程持有锁就会计数,如果释放锁就会在计算上减一。在存储数据的时候采用的hash结构,大key可以按照自己的业务进行定制,其中小key是当前线程的唯一标识,alue是当前线程重入的次教
Redis实现主从一致性
MultiLock
11.Redis为什么被设计成单线程的
是因为最大限度地利用CPU缓存和避免多线程并发带来的锁争用,上下文切换等开销,从而实现更高的性能和最低的延迟此外采用异步I/O模型可以同时处理多个客户端请求进一步提高并发请求
12.如何保证Redis缓存双写一致
当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致
看Redis篇-详解双写一致_redis 双写一致-CSDN博客
13.Redis为什么那么快
14.Redis集群有哪些方案?
15.redis集群脑裂,该怎么解决呢?
关于解决的话,我记得在redis的配置中可以设置:第一可以设置最少的salve节点个数,比如设置至少要有一个从节点才能同步数据,第二个可以设置主从数据复制和同步的延迟时间,达不到要求就拒绝请求,就可以避免大量的数据丢失