目录
12. 使用Redis作为缓存,Redis和mysql数据库一致性如何实现?
1. 什么是Redis?
- Redis是一个使用C语言写成的,开源的高性能key-value非关系缓存数据库,它支持存储的value类型相对更多,包括:string(字符串),list(链表),set(集合),hash(哈希类型),zset(sorted set --有序集合)。Redis的数据都基于缓存,Redis的操作都是原子性的。
2. Redis的优缺点?
- 优点:
- 读写性能优异。
- 支持数据持久化,支持AOF和RDB两种持久化方式。
- 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
- 数据结构丰富,除了支持string类型的value外还支持hash,set,zset,list等。
- 支持主从复制,主机自动将数据同步到从机,进行读写分离。
- 缺点:
- 数据库容易受到内存容量的限制,不能用作海量数据的高性能读写,因此redis适合的场景主要局限在较小的数据量的高性能操作和运算。
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的ip才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换ip还会引入数据不一致的问题,降低了系统的可用性。
- Redis较难支持在线扩容,在集群容量达到上限,在线扩容就会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
3. Redis有哪些数据结构?
Redis的数据结构主要有5种:string,set,zset,list,hash
数据类型 | 可存储的值 | 操作 | 应用场景 |
string | 字符串,整数,浮点数 | 对整个字符串或者字符串的其中一部分执行操作,对整数和浮点数执行自增或自减操作 | 简单的键值对缓存 |
set | 无序集合 | 检查一个元素是否存在于集合,计算交集并集差集,从集合随机获取元素 | 交集,并集,差集操作,比如交集,可以把两个人的粉丝列表弄一个交集 |
zset | 有序集合 | 添加,获取,删除元素,根据分值范围或成员来获取元素,计算一个键的排名 | 去重但可以排序,例如排行榜 |
list | 列表 | 从两端压入或弹出元素,对单个或多个元素进行修剪,只保留一个范围内的元素 | 存储一些列表的数据结构,类似粉丝列表,文章评论列表等 |
hash | 包含键值对的无序集合 | 添加,获取,移除单个键值对,获取所有键值对,检查某个键是否存在 | 结构化的数据,例如对象 |
4. Redis的应用场景
- 计数器
- 可以对String进行自增自减计算,从而实现计数器的功能,redis这种内存类型数据库读写性能很高,很适合频繁读写操作。
- 缓存
- 将热点数据放入内存,设置内存最大使用量以及淘汰策略保证缓存的命中率。
- 会话缓存
- 可以使用Redis来统一存储多态服务器的会话信息,当应用服务器不再存储用户的会话信息,就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
- 排行榜
- Zset可以实现有序性操作,实现排行榜功能。
- 共同好友
- set可以实现交集,并集,差集,从而实现共同好友功能。
- 分布式锁
- 分布式场景下,无法使用单机环境的锁对多个节点上的进程同步,可以使用redis自带的setnx实现分布式锁,除外 还可以使用官方提供的RedLock分布式锁实现。
5. 持久化?
持久化就是把内存的数据写到磁盘中,防止服务器宕机导致数据丢失
6. Redis 的持久化机制是什么?有什么优缺点?
Redis 提供两种持久化的机制RDB(默认)和AOF机制
- RDB:是Redis DataBase缩写快照
- RDB是redis默认的持久化方式,按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期
- 优点:
- 只有一个dump.rdb方便持久化
- 容灾性能好,一个文件可以保存到安全的磁盘
- 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以IO最大化。使用单独子进程进行持久化,主进程不会进行任何IO操作,保证了redis的高性能
- 相对于数据集大时比AOF启动效率高
- 缺点:
- 数据安全性低。RDB是隔段时间持久化,持久化间发生故障,会发生数据丢失,适合数据要求不严谨的时候
- 优点:
- RDB是redis默认的持久化方式,按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期
- AOF持久化
- AOF持久化是将Redis执行的每次写命令记录到单独的日志文件,当重启Redis会重新将持久化的日志中文件恢复数据
- 两种方法同时开启,数据恢复Redis优先选择AOF恢复
- 优点:
- 数据安全,aof持久化可以配置appendfsync属性,有always,每进行一次操作就记录到aof文件中一次
- 通过append模式写文件,即使中途服务器宕机,可以通过redis-check-aof工具解决数据一致性的问题。
- aof机制的rewrite模式,aof文件没被rewrite之前(文件过大时会对命令 进行合并重写,可以删除其中的某些命令)
- 缺点
- aof文件比RDB大,恢复速度慢
- 数据集大的时候,比RDB气动效率低
- 优点:
- 两种持久化机制的优缺点?
- AOF文件比RDB更新效率高,优先使用AOF还原数据
- AOF比RDB安全性高也更大
- RDB比AOF性能好
- 两种都配置了,优先加载AOF
7. Redis 的过期删除策略?
过期删除策略通常有三种:
- 定时过期:设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除,该策略可以立即清除过期的数据面对内存很友好,但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量
- 惰性过期:只有当访问一个key时,才会判断该key是否过期,过期则删除。该策略可以最大化的节省CPU资源,对内存不是很友好。极端情况可能出现大量的过期key没有再次被访问,从而不被清除,占用大量内存。
- 定期过期:每隔一段时间,就会扫描一定数量的的数据库的expires字典中的一定数量的key,并且清除其中过期的key。该策略是前两者折中的方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得cpu和内存资源达到最优的平衡效果。
8. Redis 的内存淘汰策略有哪些?
Redis 的内存淘汰是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外内存的数据。
- 全局键空间选择性移除
- noeviction:当内存不足以容纳新写入的数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入的数据时,在键空间移除最近最少使用的key(常用)
- allkeys-random:当内存不足以容纳新写入的数据时,在键空间随即删除
- 设置过期时间的键空间选择性移除
-
volatile-lru :当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key 。
-
volatile-ttl :当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key 优先移除。
-
volatile-random :当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key 。总结:Redis的内存淘汰策略选取并不会影响过期key的处理,内存淘汰策略用于处理内存不足时需要申请额外的空间的数据;过期策略主要用于处理过期的缓存数据。
-
9. Redis的事务保证原子性吗,支持回滚吗?
Redis中,单条命令是原子性执行的,但事务不保证原子性,不支持回滚。
10. 什么是Redis穿透?
- 是指查询一个不存在的数据,由于缓存无法命中,将去查询数据库,但是数据库也无此记录,并且出于容错考虑,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
- 解决方法:
- 1. 从缓存取不到的数据,在数据库也没有取到,这时可以将key-value写为key-null,缓存有效时间设置短点,如30秒。这样可以防止攻击用户反复使用同一个id暴力攻击
- 2. 接口层校验,如用户权限校验,id校验,id<=0直接拦截
- 3. 布隆过滤,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截,从而避免了底层存储系统的查询压力。
10. 什么是Redis击穿?
- 是指对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:如果这个key在大量请求同时进来之前正好失效,那么所有对这个key的数据查询都落到DB,我们称为缓存击穿。
- 解决方案:
- 在分布式的环境下,应使用分布式锁来解决,分布式锁的实现方案有多种,比如使用Redis的setnx、使用Zookeeper的临时顺序节点等来实现。
11. 什么是redis雪崩?
- 是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩
- 解决方法:
- 原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
12. 使用Redis作为缓存,Redis和mysql数据库一致性如何实现?
-
延迟双删策略
- 写库前后进行redis.del(key)操作,并且设定合理的超时时间。具体实现步骤:
- 先删除缓存
- 再写数据库
- 休眠500毫秒(具体业务时间来定)
- 再次删除缓存。
- 写库前后进行redis.del(key)操作,并且设定合理的超时时间。具体实现步骤:
- 设置缓存的过期时间
- 理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面读请求自然会从数据库中读取新值然后回填缓存
- 结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写功能的耗时。
- 如何写完数据库后,再次删除缓存成功?
- 1. 更新数据库数据
- 2. 数据库会将操作信息写入binlog日志中
- 3. 订阅程序提取出所需的数据以及key
- 4. 另起一段非业务代码,获得该信息
- 5. 尝试删除缓存操作,发现删除失败
- 6. 将这些数据发送至消息队列
- 7. 重新从消息队列获得该数据,重试操作
13. Redis使用规范
阿里巴巴Redis使用规范:https://developer.aliyun.com/article/531067