文章目录
01、Redis 支持哪些数据类型?
答:Redis 支持五种基本数据类型:String(字符串)、Hash(哈希)、List(列表)、Set(集合)及 ZSet(Sorted Set 有序集合)。还支持 HyperLogLog、Geo、BitMap、Pub/Sub 等数据结构,此外还有 BloomFilter,RedisSearch、Redis - ML 等。
- HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。HyperLogLog 只会根据输入元素来计算基数,而不会存储输入元素本身。
- Geo 用于地理位置的存储和计算,Redis3.2 版本开始提供此功能。
- BitMap 实际上不是特殊的存储结构,其本质上是二进制字符串,可以进行位操作,其经典应用场景之一是日活跃用户统计。
02、谈谈对 Redis 的 AOF 机制的 rewrite 模式的理解?
答:rewrite
模式的作用就是缩小 AOF 持久化文件的体积。由于 AOF 持久化会对每一个写操作进行日志记录,在访问量时大时文件体积会迅速膨胀,这就需要通过 rewrite 模式来缩小文件体积。
rewrite
会像 replication
一样,创建(fork)出一个子进程,以及创建一个临时文件,遍历当前内存数据库中的所有数据,输出到临时文件。在 rewrite
期间的写操作会保存在内存的 rewrite buffer
中,当 rewrite
成功后这些操作也会复制到临时文件中,在最后用临时文件替代 AOF 文件。
触发 rewrite
,是文件大小达到临界点时发生。这个临界点是在 Redis 配置文件 Redis.conf
中配置,相关有两个参数:auto - aof - rewrite - percentage
和 auto - aof - rewrite - min - size
参数。当前 AOF 文件体积大于 auto - aof - rewrite - min - size
,同时 AOF 文件体积的增长率大于 auto - aof - rewrite - percentage
时,会自动触发 AOF 的 rewrite
模式。当然也可手动调用 startAppendOnly
函数来触发 rewrite
。
以上情况在 AOF 打开的情况下发生,如果 AOF 是关闭的,那么 rewrite
操作可以通过 bgrewriteaof
命令来进行。
03、请列举几个 Redis 常见性能问题和解决方案
答:这里列举几个常见的性能问题如下:
- 1)Master 最好不要做 RDB 持久化,因为这时 save 命令会调度
rdbsSave
函数,会阻塞主线程的工作,当数据量比较大时可能造成主线程长时间间断性暂停服务。 - 2)如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒一次。
- 3)为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网中。
- 4)尽量避免在运行压力很大的主库上增加从库。
- 5)主从复制不要用图状结构,用单向链表结构更为稳定,即:
Master→Slave1→Slave2→Slave3…
。这样的结构方便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 崩溃,可以立即启用 Slave1 替换 Master,其他不变。
04、Redis 使用的最大内存是多少?内存数据淘汰策略有哪些?
答:在 Redis 中,最大使用内存大小由 Redis.conf
中的参数 maxmemory
决定。默认值为 0,表示不限制,这时实际相当于当前系统的内存。但如果随着数据的增加,如果对内存中的数据没有管理机制,那么数据集大小达到或超过最大内存的大小时,则会造成 Redis 崩溃。因此需要内存数据淘汰机制。
Redis 淘汰策略配置参数为 maxmemory - policy
,默认为 volatile - lru
,Redis 总共提供了 6 种数据淘汰策略。
- 1)
volatile - lru
:从已设置过期时间的数据集中挑选将要过期的数据淘汰。 - 2)
volatile - ttl
:从已设置过期时间的数据集中挑选最近使用的数据集淘汰。 - 3)
volatile - random
:从已设置过期时间的数据集中任意选择数据淘汰。 - 4)
allKeys - lru
:从数据集中挑选最近最少使用的数据淘汰。 - 5)
allKeys - random
:从数据集中任意选择数据淘汰。 - 6)
no - eviction
(驱逐):禁止驱逐数据,这是默认的策略。
如果 AOF 已开启,Redis 淘汰数据时也会同步到 AOF。
说明一下:volatile
开头表示是对已设置过期时间的数据集淘汰数据,allKeys
开头表示是从全部数据集淘汰数据,后面的 lru、ttl、random
表示的是不同的淘汰策略,no - eviction
是永不回收的数据集合。关于 lru 策略,需要说明的是,Redis 中并不会准确的删除所有键中最近最少使用的键,而是随机抽取 5 个键(个数由参数 maxmemory - samples
决定,默认值是 5),删除这 5 个键中最近最少使用的键。
这里也介绍一下使用淘汰策略的规则:
- 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用
allKeys - lru
。 - 如果数据呈现等分布,也就是所有的数据访问频率大体相同,则使用
allKeys - random
。
05、请谈谈 Redis 的同步机制。
答:Redis 的主从同步分为部分同步(也叫增量同步)和全量同步。Redis 会先尝试进行增量同步,如不成功,则 Slave 进行全量同步。如果有需要,Slave 在任何时候都可以发起全量同步。
Redis 增量同步是指 Slave 初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。增量同步的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
Redis 全量同步一般发生在 Slave 初始化阶段,这时 Slave 需要对 Master 上的所有数据做全量同步。全同步结束后,也就是配置好主从后,Slave 连接到 Master,Slave 都会发送 PSYNC(即增量同步)命令到 Master。
如果是重新连接,且满足增量同步的条件,那么 Redis 会将内存缓存队列中的命令发给 Slave,完成增量同步。否则进行全量同步。
06、谈谈对 Redis 哈希槽的理解。
答:Redis Cluster 提供了自动将数据分散到不同结点的能力,但采取的策略不是一致性 hash,而是哈希槽。Redis 集群将整个 key 的数值域分成 16384 个哈希槽,每个 Key 通过 CRC16 校验后对 16384 取模来决定放置到哪个槽,集群的每个结点负责一部分哈希槽。
07、什么是缓存雪崩?
答:如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,这就造成了缓存雪崩。
下面推荐几个缓存雪崩的解决办法:
- 1)在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 Key 只允许一个线程查询数据和写缓存,其他线程等待。
- 2)可以通过缓存 reload 机制,预先去更新缓存,亦即将发生高并发访问前手动触发加载缓存。
- 3)对不同的 Key,设置不同的过期时间,让缓存失效的时间点尽量均匀。比如我们可以在原有的失效时间基础上增加一个随机值,比如 1 - 5 分钟随机。这样每一个缓存的过期时间的重复率就会大大降低缓存集体失效的概率。
- 4)设置二级缓存,或者双缓存策略。A1 为原始缓存,A2 为拷贝缓存,A1 失效时,可以访问 A2 缓存失效时间设置为短期,A2 设置为长期。
08、什么是缓存击穿?
答:缓存击穿,是指一个 Key 在不停地支撑着高并发,高并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的高并发就穿破缓存,直接请求数据库。缓存击穿和缓存雪崩的区别在于缓存击穿是针对某一个 Key 缓存而言,缓存雪崩则是针对很多 Key。
对一般的网站而言,很难有某个数据能达到缓存击穿的级别,一般是热门网站的秒杀或爆款商品,才有可能发生这种情况。当然,这时把这种商品设置成永不过期或者过期时间超过抢购时段是一种很好的避免发生缓存击穿的方法,如果这时可以不需要考虑数据一致性的问题的话。
09、什么是缓存预热?
答:缓存预热就是系统上线时,提前将相关的缓存数据直接加载到缓存系统,而不是等到用户请求的时候,才将查询数据缓存。这样用户请求可直接查询事先被预热的缓存数据。缓存预热的方式可以有如下几种:
10、如何进行缓存更新?
答:我们知道在缓存中通过 expire
来设置 Key 的过期时间,各缓存服务器一般都有自带的缓存失效策略,这里讲的缓存更新,是指源数据更新之后如何解决缓存数据一致性的问题。个人认为有如下方案:
- 1)数据实时同步失效或更新。这是一种增量主动型的方案,能保证数据强一致性,在数据库更新之后,主动请求缓存更新。
- 2)数据异步更新,这是属于增量被动型方案,数据一致性稍弱,数据更新会有所延迟。一般在数据库后,通过异步方式,用多线程方式或消息队列来实现更新。
- 3)定时任务更新,这是一种全量被动型方案,当然也可以是增量被动型。这种方式保证数据最终一致性,通过定时任务按一定频率调度更新缓存数据一致性最差。
具体采用何种方式,开发者可以根据实际需要来进行取舍。
11、如何进行缓存降级?
答:在网上看到很多地方提到缓存降级,但笔者的理解,很多文章所说的缓存降级,其实都应该是指服务降级。就是说在访问量剧增、服务响应出现问题(如响应延迟或不响应)或非核心服务影响到核心流程的性能的情况下,仍然需要保证核心服务可用,尽管可能一些非主要服务不可用,这时就可以采取服务降级策略。
服务降级的最终目的是保证核心服务可用,即使是有损的。服务降级应当事先确定好降级方案,确定哪些服务是可以降级的,哪些服务是不可降级的。根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心服务的正常运行。
降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。
- 根据服务方式:可以拒接服务,可以延迟服务,也可以随机提供服务。
- 根据服务范围:可以暂时禁用某些功能或禁用某些功能模块。
总之服务降级需要根据不同的业务需求采用不同的降级策略。主要的目的就是服务虽然有损但是总比没有好。
12、如何缓存热点 Key?
答:使用缓存 + 过期时间的策略既可以提高数据读取速度,又能保证数据的定期更新,这种模式基本能够满足绝大部分需求。但是如果当前Key是一个热点Key,并发量非常大,这时就可能产生前面所说的缓存击穿问题。
重建缓存可能是个复杂操作,可能包含有复杂计算 (例如复杂的SQL、多次I/O、多个依赖等)。如果在缓存失效的瞬间,有大量请求进行并发访问,这些访问都会同时访问后端(也就会同时进行重建缓存操作),就会造成后端负载加大,甚至可能造成应用崩溃。
所以缓存热点 Key 为了避免缓存击穿,一是可以设置为永不过期,在不需要考虑数据一致性问题的情况下,个人认为这是最好也最简单的解决方式。如果需要考虑数据一致性问题,需要设置过期时间,那就要考虑如何减少重建缓存的次数,这时采用Redis 的互斥锁是一种解决方式, 这样保证同一时间只能有一个请求执行缓存重建。这样就能有效减少缓存重建次数,但如果重建时间过长,则可能引发其他问题。
13、什么是NoSQL数据库?
答: NoSQL是非关系型数据库的意思,也有的解释成Not Only SQL。
NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
14、NoSQL和RDBMS有什么区别?
关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据。
15、在哪些情况下使用和不使用NoSQL数据库?
在处理非结构化/半结构化的大数据时,在水平方向上进行扩展时,随时应对动态增加的数据项时可以优先考虑使用NoSQL数据库。
在考虑数据库的成熟度、支持、 分析和商业智能、管理及专业性等问题时,应优先考虑关系型数据库。