1、Redis为什么快?
1、纯内存操作
2、单线程可以省去多线程时CPU上下文会切换的时间
3、渐进式ReHash、缓存时间戳
数组需要扩容的时候,他会维护两张hash表,比如第一张的数组长度为6,另一张的数组长度为12,在set和get的时候他只会把这一个节点的数据hash到长度为12的表中。
Redis用到时间的时候不会使用Thread.currentTimeMiles()方法,这个会方法会调用操作系统,比较耗时,Redis会把时间缓存到内存中。
2、Redis合适的应用场景?
1、分布式缓存
2、分布式锁
3、计数器
4、排行榜(使用有序集合ZSet)
3、Redis6.0之前为什么一直不使用多线程?
1、使用Redis、CPU 不是瓶颈,受制 内存、网络
2、提高Redis, Pipeline(命令批量) 每秒100万个请求
3、单线程,内部维护比较低
4、如果是多线程(线程切换、加锁\解锁、导致死锁问题)
5、惰性Rehash(渐进性式的Rehash)
所以,一般的公司,单线程Redis 就够了。
4、Redis6.0为什么要引入多线程?
1、Redis服务器可以处理8万到10万 QPS,对于80%的公司来说,单线程的Redis已经足够使用。
2、提高Redis, Pipeline(命令批量) 每秒100万个请求
3、但随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的QPS。
4、常见的解决方案是在分布式架构中对数据进行分区并采用多个服务器,有非常大的缺陷:
管理的Redis服务器太多,维护代价大
某些适用于单个Redis服务器的命令不适用于数据分区
数据分区无法解决热点读/写问题
5、指的是IO的多线程(内部执行命令还是单线程)
多线程任务 分摊到 Redis 同步IO中读写 负载。
相当于多核服务器,一个核来处理IO操作。
5、Redis有哪些高级功能?
Redis的慢查询
许多存储系统(例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设调值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似的功能。
Pipeline 批量处理
事务、
数据持久化(RDB和AOF)、
使用哨兵实现集群、
分布式锁
**6、**为什么要用Redis?
为了高性能、高并发。
7、Redis与memcached相对有哪些优势?
Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。
8、怎么理解Redis中事务?
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
Redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和exec两个命令之间。
multi 命令代表事务开始,exec命令代表事务结束。另外discard命令是回滚。
注意:
1、Redis的事务功能很弱。在事务回滚机制上,Redis只能对基本的语法错误进行判断。
2、运行时错误
例如:事务内第一个命令简单的设置一个string类型,第二个对这个key进行sadd命令,这种就是运行时命令错误,因为语法是正确的:
可以看到Redis并不支持回滚功能,第一个set命令已经执行成功,需要自己手动修复这类问题。
9、Redis的过期策略
redis采用的是 定期删除+惰性删除 策略。
1、为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU
资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.
2、定期删除 + 惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis
不是每个100ms将所有的key检查一次,而是随机抽取进行检查,如果这块区域超过25%过期,会
对这块区域再次进行删除。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于
是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置
了过期时间那么是否过期了?如果过期了此时就会删除。
10、什么是缓存穿透?如何避免?
缓存穿透:指查询一个不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。
解决方案:
1.查询返回的数据为空,仍把这个空结果null进行缓存,但过期时间会比较短;
2.布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
11、什么是缓存雪崩?如何避免?
缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到
DB,DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个key 缓存。
12、使用Redis如何设计分布式锁?
基于 Redis 实现的分布式锁,使用到的是 SETNX 命令,有可能会出现死锁现象,锁过期时间不好评估,如果key的过期时间太短,拿到锁的线程还没有执行完业务流程,其他的线程就再次拿到锁了,如果key的过期时间太长,拿到锁的线程如果发生了异常,其他的线程就必须要等锁过期了才能拿到锁,这时候就需要我们开启一 个「守护线程」,定时去检测这个锁的失效时间,如果锁快要过期了,操作共享资源还末完成,那么就自动对锁进行 「续期」,重新设置过期时间。这个守护线程我们一般也把它叫做「看门狗」线程。
13、什么是bigkey?会有什么影响?
1、bigkey是指key对应的value所占的内存空间比较大。
如果按照数据结构来细分的话,一般分为字符串类型bigkey和非字符串类型bigkey。
**字符串类型:**体现在单个value值很大,一般认为超过10KB就是bigkey
**非字符串类型:**哈希、列表、集合、有序集合,体现在元素个数过多。
2、bigkey的危害体现在三个方面:
内存空间不均匀
操作bigkey比较耗时
网络拥塞:每次获取bigkey产生的网络流量较大
3、如何发现bigkey
可以通过redis-cli--bigkeys命令统计bigkey的分布。
14、Redis如何解决key冲突?
1、业务隔离。
2、通过添加前缀的方式对key进行设计。
3、"Redis 并发竞争" 问题就是高并发写同一个key时导致的值错误。
常用的解决方法:
- 乐观锁,
watch
命令可以方便的实现乐观锁。注意不要在分片集群中使用。 - 分布式锁,适合分布式系统环境,分布式锁的实现方式很多,比如 ZooKeeper、Redis 等
- 时间戳,适合有序场景
- 消息队列,在并发量很大的情况下,可以通过消息队列进行串行化处理
15、怎么提高缓存命中率?
1、缓存预加载(预热)
2、增加缓存的存储空间,提高缓存的数据、提高命中率
3、调整缓存的存储类型
4、提升缓存的更新频次
16、Redis持久化方式有哪些?有什么区别?
我们一般采用RDB、AOF、混合持久化。
RDB的优缺点:
优点:RDB持久化文件,速度比较快,而且存储的是一个二进制文件,传输起来很方便。
缺点:**RDB无法保证数据的绝对安全,**有时候就是1s也会有很大的数据丢失。
AOF的优缺点:
优点:AOF相对RDB更加安全,一般不会有数据的丢失或者很少,官方推荐同时开启AOF和RDB。
缺点:AOF持久化的速度,相对于RDB较慢,存储的是一个文本文件,到了后期文件会比较大,传输困难。
17、为什么Redis需要把所有数据放到内存中?
Redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘,所以Redis
具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响Redis的性能。
18、如何保证缓存与数据库双写时的数据一致性
第一种方案:采用延时双删策略
具体的步骤就是:
先删除缓存;
再写数据库;
休眠500毫秒;
再次删除缓存。
第二种方案:异步更新缓存(基于订阅binlog的同步机制)
技术整体思路:
MySQL binlog增量订阅消费+消息队列+增量数据更新到redis
19、Redis集群方案应该怎么做?
- Redis Sentinel(哨兵),体量较小时,选择 Redis Sentinel,单主 Redis 足以支撑业务。
哨兵模式基于主从复制模式。
**哨兵顾名思义,就是来为Redis集群站哨的,一旦发现问题能做出相应的应对处理。**其功能包括
- 监控master、slave是否正常运行
- 当master出现故障时,能自动将一个slave转换为master(大哥挂了,选一个小弟上位)
- 多个哨兵可以监控同一个Redis,哨兵之间也会自动监控
2、Redis Cluster Redis 官方提供的集群化方案,体量较大时,选择 Redis Cluster,通过分片,使用更多内存。
哨兵模式解决了主从复制不能自动故障转移,达不到高可用的问题,但还是存在难以在线扩容,
Redis容量受限于单机配置的问题。Cluster模式实现了Redis的分布式存储,即每台节点存储不同
的内容(将16383个槽进行平分),来解决在线扩容的问题。
Cluster模式集群节点最小配置6个节点(3主3从,因为需要半数以上),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
所有的redis节点彼此互联(PING-PONG机制)。
3、Twemprox (了解)
Twemprox是Twtter开源的一个 Redis和 Memcached 代理服务器,主要用于管理 Redis和Memcached 集群,减少与Cache 服务器直接连接的数量。
- Codis (了解)
Codis是一个代理中间件,当客户端向Codis发送指令时,Codis负责将指令转发到后面的Redis来执行,并将结果返回给客户端。一个Codis实例可以连接多个Redis实例,也可以启动多个Codis实例来支撑,每个Codis节点都是对等的,这样可以增加整体的QPS需求,还能起到容灾功能。
20、Redis集群方案什么情况下会导致整个集群不可用?
**1、当访问一个 Master 和 他的Slave 节点都挂了的时候,会报 槽无法获取。**如果我们配置了一个
参数,即使有槽没有分配也是可以使用的。
2、当集群 Master 节点个数小于 3 个的时候,或者集群可用节点个数为偶数的时候,基于 fail 的
这****种选举机制 的自动主从切换过程 可能会不能正常工作。
21、说一说Redis哈希槽的概念?
slot:称为哈希槽
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
22、Redis集群会有写操作丢失吗?为什么?
1、过期 key 被清理
2、最大内存不足,导致 Redis 自动清理部分 key 以节省空间
3、主库故障后自动重启,从库 异步进行同步
4、单独的主备方案,网络不稳定触发 哨兵的自动切换主从节点,切换期间会有数据丢失。
23、Redis常见性能问题和解决方案有哪些?
1、持久化性能问题
主从 主节点(master)不要做持久化,从节点(slave)做持久化
2、如果数据比较重要,从节点(slave)开启AOF, 策略每秒同步一次
3、在同一个局域网内,主从复制会流畅。
4、 尽量避免 主库 压力很大的情况下,增加从库
5、主从复制 不要采用网状结构、要采用线性结构
24、热点数据和冷数据是什么
1、热数据
比如点赞数、评论数这些不断变化的数据,考虑使用缓存, 同步到redis.
2、冷数据
经常不访问的数据
3、如何判断是冷数据还是热数据
数据更新之前至少读取2次----才能放缓存
25、什么情况下可能会导致Redis阻塞?
1、客户端使用了可能造成阻塞的命令
keys * 、Hgetall 、smembers 等,
2、Bigkey删除, 比如zset (删除100万的元素 需要2S)
3、清空库的时候,比如 flushdb flushall
4、AOF日志同步写,记录AOF日志大量的写操作,1个同步写磁盘耗时需要1 ~2ms。
5、 从库加载RDB文件的时候
26、Redis的内存淘汰机制?LRU算法是什么?
以下三个都是设置了过期时间的:
volatile-lru: 尝试回收最少使用的键(LRU)
volatile-ttl: 优先回收存活时间(TTL)较短的键,
volatile-random: 回收随机的键
以下两个是针对所有的键:
allkeys-lru: 尝试回收最少使用的键(LRU)
allkeys-random: 回收随机的键
LRU算法
类似于mybatis的管理page的链表,也是用到了LRU算法。