JAVA面试篇(三)一Redis

1.基础

1、Redis 为何这么快?

1)基于内存;
➢ 2)单线程减少上下文切换,同时保证原子性;
➢ 3)IO多路复用;
➢ 4)高级数据结构(如 SDS、Hash以及跳表等)。

2、为何使用单线程?

因为 Redis 是基于内存的操作,CPU 不会成为 Redis 的瓶颈,而最有可能是机器内存的大小或者网络带宽。
既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

详细原因:
	➢ 1)不需要各种锁的性能消耗
	Redis 的数据结构并不全是简单的 Key-Value,还有 List,Hash 等复杂的结构,这些结构有可能会进行
	很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就
	需要加非常多的锁,导致的结果是同步开销大大增加。
	
	➢ 2)单线程多进程集群方案
	单线程的威力非常强大,每核心效率也非常高。多线程虽然比单线程有更高的性能上限,但是在今
	天的计算环境中,即便单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,
	这些方案中多线程的技术照样是用不上的。所以单线程、多进程的集群不失为一个时髦的解决方案。

3、缓存三大问题以及解决方案?

➢ 缓存穿透:查询数据不存在
	○ 1)缓存空值
	○ 2key 值校验,如布隆筛选器 ref 分布式布隆过滤器(Bloom Filter)详解(初版)
	
➢ 缓存击穿:缓存过期,伴随大量对该 key 的请求
	○ 1)互斥锁
	○ 2)热点数据永不过期
	○ 3)熔断降级
	
➢ 缓存雪崩:同一时间大批量的 key 过期
	○ 1)热点数据不过期
	○ 2)随机分散过期时间
	

4、先删后写还是先写后删?

➢ 先删缓存后写 DB
	产生脏数据的概率较大(若出现脏数据,则意味着再不更新的情况下,查询得到的数据均为旧的数据)。	
	比如两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,
	先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致
	缓存中的数据是脏的,而且还一直这样脏下去了。

➢ 先写 DB 再删缓存
	产生脏数据的概率较小,但是依然会出现一致性的问题;若更新操作的时候,同时进行查询操作并命中,则查
	询得到的数据是旧的数据。但是不会影响后面的查询。
	
	比如一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓
	存失效,然后之前的那个读操作再把老的数据放进去,所以会造成脏数据。解决方案:
	➢1)缓存设置过期时间,实现最终一致性;
	➢2)使用 Cannel 等中间件监听 binlog 进行异步更新;
	➢3)通过 2PC 或 Paxos 协议保证一致性。

5、如何保证 Redis 的高并发?

Redis 通过主从加集群架构,实现读写分离,主节点负责写,并将数据同步给其他从节点,从节点负责读,从而实现高并发。

6、Redis 如何保证原子性?

由于 Redis 是单线程的,所以 Redis 提供的 API 也是原子操作。但我们业务中常常有
先 get 后 set 的业务常见,在并发下会导致数据不一致的情况。如何解决:
➢ 1)使用 incr、decr、setnx 等原子操作;
➢ 2)客户端加锁;
➢ 3)使用 Lua 脚本实现 CAS 操作。

7、有哪些应用场景?

Redis 在互联网产品中使用的场景实在是太多太多,这里分别对 Redis 几种数据类型做了整理:
➢1)String:缓存、限流、分布式锁、计数器、分布式 Session 等。
➢2Hash:用户信息、用户主页访问量、组合查询等。
➢3)List:简单队列、关注列表时间轴。
➢4Set:赞、踩、标签等。
➢5)ZSet:排行榜、好友关系链表。

2.持久化

1、Redis 的数据过期策略是什么?

在回答词问题之前,首先需要回答另一个问题,就是如何设置 Redis 中数据的过期时间?
➢1)expire key time (以秒为单位)–这是最常用的方式
➢2)setex(String key, int seconds, String value) --字符串独有的方式

2、如果设置了缓存过期时间,如何让其永不过期。

使用 persist key

3、Redis 的数据过期策略是什么?

➢ 常见的过期策略
1)定时删除
	在设置 key 的过期时间的同时,为该 key 创建一个定时器,让定时器在 key 的过期时间来临时,对 key 进行删除。
2)惰性删除
3)定期删除
	每隔一段时间执行一次删除(在 redis.conf 配置文件设置,1s 刷新的频率)过期 key 操作。

➢ Redis采用的过期策略
	Redis 采用了 ‘惰性删除 + 定期删除’ 的方式处理过期数据。

➢ 惰性删除的流程
	1)在进行get或setnx等操作时,先检查key是否过期;
	2)若过期,删除key,然后执行相应操作;
	3)若没过期,直接执行相应操作。

➢ 定期删除的流程
	其核心是对指定个数个库的每一个库随机删除小于等于指定个数个过期 key1)历每个数据库(就是 redis.conf 中配置的 “database” 数量,默认为16);
	
	2)检查当前库中的指定个数个 key (默认是每个库检查 20 个,相当于该循环执行 20 次):
		2.1)如果当前库中没有一个 key 设置了过期时间,直接执行下一个库的遍历;
		2.2)随机获取一个设置了过期时间的 key,检查是否过期,如果过期则删除;
		2.3)判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。

4、持久化文件对过期策略的处理?

过期 key 是不会写入 RDB 和 AOF 文件,同时数据恢复时也会做过期验证。

5、Redis 有哪些内存淘汰机制?

Redis 作为一个内存数据库,在内存空间不足的时候,为了保证命中率,就会和我们操作系统中的
页面置换算法类似,选择一定的数据淘汰策略。

➢ volatile(设置过期时间的数据集)
	1)volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
	2)volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
	3)volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
	4)volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。

➢ allkeys(所以数据集)
	5)allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
	6)allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
	7)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

➢ no-enviction
	8no-enviction(驱逐):禁止驱逐数据,这也是默认策略。
	意思是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续
	进行,采用 no-enviction 策略可以保证数据不被丢失。

PS:在 redis.config 文件中,我们可以设置 maxmemory 的值来配置 Redis 的最大占用内存字节数。

6、Redis 有哪些持久化机制?

RDB 和 AOF。

7、说说 Redis 的 RDB?

RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式。
也就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb。

RDB 支持 同步(save 命令)、后台异步(bgsave)以及自动配置三种方式触发。

➢ 优点
	○ RDB 文件紧凑,全量备份,非常适合用于进行备份和灾难恢复
	○ 生成 RDB 文件时支持异步处理,主进程不需要进行任何磁盘IO操作
	○ RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
	
➢ 缺点
	○ RDB 快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。
	且在快照持久化期间修改的数据不会被保存,可能丢失数据。
	

8、说说 Redis 的 AOF?

全量备份总是耗时的,有时候我们提供一种更加高效的方式 AOF,其工作机制更加简单:会将每一个收
到的写命令追加到文件中。随着时间推移,AOF 持久化文件也会变的越来越大。
为了解决此问题,Redis 提供了 bgrewriteaof 命令,作用是 fork 出一条新进程将内存中的数据以
命令的方式保存到临时文件中,完成对AOF 文件的重写。

AOF 也有三种触发方式:
	➢ 每修改同步 always 
	➢ 每秒同步 everysec
	➢ 不同步 no:从不同步。

➢ 优点
	○ AOF 可以更好的保护数据不丢失,一般 AOF 隔 1 秒通过一个后台线程执行一次 fsync 操作
	○ AOF 日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损
	○ AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写
	○ AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复
	
➢ 缺点
	○ 对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大
	○ AOF开启后,支持的写 QPS 会比RDB支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync 一次
	日志文件,当然,每秒一次 fsync,性能也还是很高的

9、RDB 和 AOF 该如何选择?

通常是二者结合使用的。

3.内存优化

1. 更快地回收过期的键内存
	当你在一个键上设置了过期时间时,redis不会在该瞬间使它过期。这意味着redis消耗内存来保存已经过期的键。
	
	快速回收这些缓存的办法:
		○ 重新启动redis服务器
		○ 在redis.conf中增加maxmemory-samples。(默认值为5,最大为10),以便更快地回收过期的键。
		○ 可以设置一个cron作业,该作业在一定间隔后运行scan命令,这有助于回收过期键的内存。
		○ 尽量所有的键都增加过期时间。
		
➢ 其他方案,暂不细述

4.集群模式

你可能感兴趣的:(java,面试,redis)