Redis二轮复习
牛客网的问题
1、详细的说说Redis的数据类型
- 5种基本的数据类型和3种特殊的数据类型
- 基本数据类型
- string(SDS,简单动态字符串):有三种编码方式
- int,如果全是数字类型会转成int
- embstr,<44,c中大于64的属于大字符串,又因为sds的结构会占19位,终止符占1位
- raw,>44
- list
- 3.2版本前有两种形式:linkedlist、ziplist(用紧凑连续的内存块存数据,更节省空间)
- 3.2后,quicklist存
- hash
- ziplist:当键值数量小于2,且值小于 64字节时
- hashtable:字典
- set
- inset:全是整数且数量不大时
- hashtable:数量大时
- zset/sort set
- ziplist:个数小于128个,且长度小于64字节时
- skiplist+dict:dict用对象到score,skiplist用于排序
- skiplistnode(对象,分数,前指针,level数组(后指针,跨度))
- string(SDS,简单动态字符串):有三种编码方式
- 特殊类型
- bitmap:布隆过滤器
- geospatial:位置信息
- HyperLogLogs:基数统计
2、说说Redis的持久化策略
- 三种:RDB、AOF、RDB+AOF
- RDB持久化:将当前进程中的数据已生成快照的方式保存到硬盘中,是redis默认的持久化机制
- 手动触发(save)、自动触发(BGSAVE)
- 优点:持久化时生成的文件体积小,恢复数据快
- 缺点:数据安全性低,每次运行BGSAVE都需要执行fork子进程操作,重量级操作不能频繁进行,所以没有做到实时的持久化
- AOF持久化:通过记录redis的所有命令,每执行一次就记录一次数据,保存在AOF文件中。先写到缓存中,设置同步时机在写到磁盘中。
- 同步到磁盘中:
- always:每次写命令都同步,严重影响服务器性能
- everysec:每秒同步一次,不会对性能有很大影响
- no:让系统决定什么时候同步指令
- 优点:保证了数据的安全性和完整性,即便是中途宕机,也可以恢复过来
- 缺点:文件要大很多,恢复速度慢
- 同步到磁盘中:
- RDB+AOF:在同时开启rdb和aof持久化时,重启时只会加载aof持久化文件,不会加载rdb持久化文件
- RDB持久化:将当前进程中的数据已生成快照的方式保存到硬盘中,是redis默认的持久化机制
3、分布式锁
- 解决问题:分布式情况下,多个应用操作同一数据
- 场景:秒杀修改库存、用户重复提交数据
- 方案一:
- 实现方式:加锁:setnx(key,1),解锁:del(key)
- 问题:如果客户忘记解锁,将会出现死锁
- 方案二:
- setnx(key,1)+expire(key,30),解锁:del(key)
- 问题:由于setnx和expire的非原子性,当第二步挂掉,仍然会出现死锁
- 方案三:
- 将setnx和expire变成原子性操作,SET key value [EX seconds] [PX milliseconds] [NX|XX],解锁:del(key)
- 问题:当锁到期会自动释放,所以要看一下还是不是这个value再删除
4、缓存穿透、击穿、雪崩的区别
- 缓存穿透:数据不在缓存中,需要请求数据库
- 解决:热点数据提取加入缓存
- 缓存击穿:缓存和数据库中都没有
- 解决:布隆过滤器
- 缓存雪崩:大量的数据请求直接请求到数据库中,缓存中没有
- 解决:热点数据提前加入缓存;设置不同过期时间;利用多个缓存,第二个设置更长的过期时间
5、Redis如何与数据库保持双写一致性
- (读写穿透)先更新缓存,再更新数据库
- 优点:能够保证数据访问是都会命中redis,降低数据库压力
- 缺点:
- 每次修改都会操作缓存降低了服务器的性能
- 当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象
- 先更新数据库,再更新缓存
- 缺点:
- 可能导致数据库和redis中的数据不一致(1)数据库更新成功,redis更新失败(2)当两个请求并发更新同一条数据
- 缺点:
- 先删除redis,再更新数据库
- 缺点:
- 数据库(DB)和缓存(Cache)数据不一致:请求1先把cache中的A数据删除 -> 请求2从DB中读取数据->请求1再把DB中的A数据更新
- 解决:延时双删策略
- 缺点:
- (旁路缓存模式)先更新数据库再删除缓存
- 缺点:可能导致数据库和redis中的数据不一致(数据库更新成功,redis更新失败)
- redis更新失败:加入队列进行重试
- 虽然会有短暂的不一致性,但还是推荐使用这个:
- 1.先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力;
- 2.如果业务应用中读取数据库和写缓存的时间不好估算,那么,延迟双删中的等待时间就不好设置。
6、请你说说Redis数据类型中的zset,它和set有什么区别?底层是怎么实现的?
- 是否有序
- set:inset,全是整数且数量不大时;dict
- zset:ziplist,小于12864字节;skiplist+dict
7、说说Redis的单线程架构
- Redis的网络IO和键值对读写是由一个线程来完成的,但Redis的其他功能,例如持久化、异步删除、集群数据同步等操作依赖于其他线程来执行。
- redis为什么这么快
- 单线程的网络io和键值对读写,减少了线程切换造成的性能开销
- redis是基于内存的
- redis是io多路复用的
8、如何实现Redis高可用
- 哨兵模式
- 集群模式
9、redis主从复制
- 增量/全量
10、缓存淘汰策略
- 定期
- 定时
- 惰性