1.Redis常用的数据类型
String,List,Set,Zset,Hash
String字符串:Redis最基本的类型.一个key对应一个value.String类型是二进制安全的.也就是说可以存储任何数据.value最大内存为512M
数据结构:String的数据结构为简单动态字符串.类似String Buffer.是可以修改的字符串.内部采用预分配冗余空间来减少内存的频发分配
内部为一个预分配空间,一个实际空间.当字符串长度小于1M的时候,扩容都是加倍。当大于1M的时候,每次扩容增加1M,最大容量为512M。
List列表:List是一种单键多值的数据类型.为简单的字符串列表.插入有序可以头插和尾插
数据结构:List的数据结构为快速链表QuickList.在列表元素较少的情况下为压缩列表ZipList.只有在数据量多的时候.这些ZipList会形成一个双向的QuickList列表
Set集合:Set单键多值的数据类型.无序集合.元素不能重复.
数据结构:底层是一个Hash表.所有在不考虑哈希碰撞的情况下.时间复杂度为O1
Hash哈希:类型为key field value
数据结构:压缩列表和哈希表.元素较少时使用的是压缩列表.元素较多时使用的是哈希表
Zset有序集合:元素不可重复.通过评分(score)对元素进行排序.可以通过评分进行范围查询
数据结构:哈希标和跳跃表.哈希表保证元素的唯一性.跳跃表保证元素的排序.可以通过评分范围查询
2.Redis的过期策略有哪些
定时删除,定期删除,惰性删除这三种
定时删除
在设置键的时候同时设置过期时间.当key过期了.定时器马上删除该key。
惰性删除
key过期后依旧在内存中不做处理.当请求操作对应的key时.检查是否过期.如果过期则删除该key.没有正常返回该key。
定期删除
Redis每隔1秒随机抽取过期字典中的20个key进行检查.过期则删除.如果过期的key占总数的1/4.则重复该操作。
默认采用的是定时+惰性删除策略。
3.常用数据类型的使用场景
String:计数,序列化javaBean对象
List:秒杀抢购场景.
Set:用户添加标签
Hash:适用于存储对象
Zset:热门歌曲榜单.评论列表
4.缓存的三大问题以及解决方案
缓存穿透,缓存击穿,缓存雪崩。
缓冲穿透:缓存穿透是指缓存和数据库中都没有数据.而不断有请求访问该资源.一直查询数据库.从而导致数据库压力变大或挂掉
解决方法:
- 缓存空值
- 参数校验
- 布隆过滤器
缓存击穿:缓存击穿是指热点数据过期之后.大量并发请求访问热点数据.因为缓存过期了.所有并发请求都落到数据库中.从而导致数据库压力变大或挂掉
解决方法:
- 多层次缓存
- 热点数据用户过期
- 加锁、熔断降级
缓存雪崩:同一时间大量的key过期.出现了大量请求去访问数据库,造成系统的宕机
解决方法:
- key增加过期随机性
- 熔断降级
- 多层次缓存
5.如何保证Redis的高并发
主从模式:读写分离
哨兵模式:故障的快速修复
6.Redis的内存淘汰策略
一共有8种,分别针对过期字典和所有数据。
针对过期字典
Volatile-lru:从已设置过期时间的数据中挑取最近最少使用的数据淘汰
Volatile-ttl:挑选将要过期的数据淘汰
Volatile-random:随机淘汰
Volatile-lfu:使用频率最低的数据淘汰
针对所有的数据集
Allkeys-lru:所有数据中挑选最近最少使用的数据淘汰
Allkeys-lfu:挑选使用频率最低的数据淘汰‘’‘
Allkeys-random:随机淘汰
No-enviction:禁止驱逐数据.默认的淘汰策略.当内存不足以容纳新数据是.写入操作报错.采用no-enviction可以保证内存中的数据不会丢失
7.Redis持久化策略有哪些
分别是RDB(快照)和AOF(日志追加)持久化机制,默认使用的是RDB
RBD持久化是将当前内存中的数据集快照写入磁盘中。Redis重启,读取磁盘中的快照信息加载到内存,完成数据的恢复。
实现:
- 手动实现:save(阻塞)或者bgsave(非阻塞)命令
- 自动触发:当条件达到配置文件中的阀值是自动触发
执行流程:
- save的时候,Redis会执行Fork操作,创建一个子进程。
- fork操作完成之后,子进程创建新的RDB文件,保存内存的快照,完成之后替换原来的RDB文件
AOF持久化是以日志的形式记录每个写的操作.然后追加到日志文件中.Redis启动是读取日志文件.执行命令以恢复数据
默认是不开启,通过配置文件appendonly=yes开启
执行流程:
1.所有写的命令追加到AOF—BUF(缓存区)中
2.AOF缓存区根据对应的策略向磁盘同步
3.AOF文件过大触发重写机制,默认是64M和原来文件的2倍
AOF策略:
appendfsyn always:每次写都刷到磁盘
appendfsync everysec:一秒刷盘一次,节点宕机最多丢失1秒数据
appendfsync everysec:按照操作系统的机制刷盘
8.Reids集群模式
单实例存Redis缓存会存在的几个问题:
(1)写并发:
Redis单实例读写分离可以解决读操作的负载均衡,但对于写操作,仍然是全部落在了master节点上面,在海量数据高并发场景,一个节点写数据容易出现瓶颈,造成master节点的压力上升。
(2)海量数据的存储压力:
单实例Redis本质上只有一台Master作为存储,如果面对海量数据的存储,一台Redis的服务器就应付不过来了,而且数据量太大意味着持久化成本高,严重时可能会阻塞服务器,造成服务请求成功率下降,降低服务的稳定性。
采用的是:插槽算法,计算对应的key的槽位存储。Redis集群中有16384个哈希槽
9.分布式锁
起源:随着业务的发展.原来单体单机部署的系统演化成了分布式集群.由于不同的业务可能部署在不同的服务器上.使原来的单机版并发控制锁策略失效了.因为出现了跨JVM的情况.程序不是在一台机器上运行.而分布式锁就是用来解决跨JVM限制共享资源访问的一种锁机制
主流的分布式锁有:基于数据库实现.基于缓存实现.基于Zookeeper实现.其中性能最高的是Redis.安全性最好的是Zookeeper
基于redis实现分布式锁:
Redis实现分布式锁.其实实现依赖于一个SetNx命令.当key不存在时才去设置.也就是说成功就表示当前线程获取锁.失败即其他线程在从持有锁。
为了满足可用性:
- 互斥性:在任意时刻,只有一个客户端能持有锁
- 不会发生死锁:即获取锁之后,出现异常能主动解锁,保证其他线程能继续工作
- 加锁和解锁必须是同一个客户端.客户端不能把别人的锁解开
- 加锁和解锁必须具有原子性
- 续期性:在业务完成之前,需要对快过期的锁进行续期
10.如何保证redis和数据库数据的一致性
在多线程的情况下,一般使用延迟双删
1.先删除缓存
2.更新数据库
3.线程等待
4.删除缓存
如果需要强一致性,需要使用锁来取保数据的一致性