DB面试中经常会问到MySQL和Redis。更新了之前关于MySQL的高频问题。今天分享一些关于Redis的高频面试题。一般关于Redis的面试官可能会问你项目的问题,或者问你有没有用过MySQL以外的数据库。1、说说你对Redis的理解?首先,Redis是基于C语言编写的,是一个读写速度很快的内存数据库。Redis在项目中也经常用到。一般用于缓存或者分布式锁。它还可以用来设计消息队列。它还支持事务、持久化、Lua脚本和多集群解决方案。追问:和Memcached有什么区别?现在公司普遍使用Redis来实现缓存,而且Redis本身也越来越强大!但是,了解Redis和Memcached的区别和共性,有助于我们在进行相应的技术选择时,有的放矢!它们的共同点:都是基于内存的数据库,一般用作缓存。两者都有过期政策。两者都表现得很好。区别:Redis支持更丰富的数据类型(支持更复杂的应用场景)**。Redis不仅支持简单的k/v类型数据,还提供list、set、zset、hash等数据结构的存储。Memcached只支持最简单的k/v数据类型。Redis支持数据持久化。它可以将内存中的数据保存在磁盘上,重启时可以再次加载使用。Memecache将所有数据存储在内存中。Redis有灾难恢复机制。因为缓存中的数据可以持久化到磁盘。Redis可以在服务器内存用完后,将不用的数据放到磁盘上。而Memcached在服务器内存用完后会直接报异常。Memcached没有原生的集群模式,需要依赖客户端向集群写入数据;但Redis目前原生支持集群模式。Memcached是一种多线程、非阻塞IO多路复用网络模型;Redis采用单线程多路复用IO多路复用模型。(Redis6.0引入多线程IO)Redis支持发布订阅模型、Lua脚本、事务等功能,Memcached不支持。此外,Redis支持更多的编程语言。Memcached过期数据的删除策略只采用惰性删除,而Redis则同时采用了惰性删除和周期性删除。2、Redis有哪些数据类型?答:常见的有五种基本数据类型和三种特殊数据类型,基本数据结构:String、list、set、zset和hash,三种特殊数据类型:位图(bitmaps)、计数器(hyperloglogs)和地理空间(geospatialindexes)。String:一般用于需要统计的场景,比如用户访问次数,热门文章的点赞转发次数等。列表:发布订阅或消息队列,慢查询。hash:对象数据在系统中的存储。set:存储的数据不能重复,需要获取多个数据源的交集和并集的场景。zset:数据需要按照一定权重排序的场景。Java训练例如,在直播系统中,实时排名信息包括直播间在线用户列表、各种礼物排名、弹幕消息(可以理解为消息维度的消息排名)等信息.推荐看一下Zset的底层数据结构,面试的时候也会问到。3、Redis有哪几种持久化方式?优缺点都有什么?持久化就是将内存中的数据写入磁盘,防止服务宕机时内存数据丢失。Redis提供了两种持久化方式:RDB(默认)快照方式和AOF追加方式。RDB(RedisDataBase:通过创建快照获取内存中某个时间点存储的数据的副本。创建快照后,用户可以备份快照并将快照复制到其他服务器,从而创建服务器用相同的数据复制。(如果系统真的崩溃了,用户将丢失上次快照后更改的所有数据。)AOF(AppendOnlyFile:将执行的写命令写入AOF文件的末尾。比较:AOF文件比RDB更新如果频率高,优先使用AOF恢复数据。AOF比RDB更安全,更大。RDB性能优于AOF。如果两者都配置优先加载AOF4。Redis过期后数据删除策略?常用过期数据的删除策略有两种(重要!自己搭建cachewheel需要考虑的事项):惰性删除:只在取出key的时候检查数据过期,这个对CPU最友好,但是可能会造成太多过期键不删除定期删除:每隔一定时间提取一批键,删除过期键。而且Redis底层会通过限制删除操作的时长和频率,来降低删除操作对CPU时间的影响。定时删除对内存更友好,惰性删除对CPU更友好。两者各有优缺点,所以Redis采用的是正则删除+惰性/惰性删除。但是仅仅设置key的过期时间还是有问题的。因为可能还会有很多过期key被定时删除和懒删除遗漏的情况。这样就会导致内存中堆积了大量过期的key,然后就会Outofmemory。5、Redis的数据淘汰策略有哪些?Redis提供了6种数据淘汰策略:volatile-lru(leastrecentlyused):从数据集(server.db[i].expires)中选择最近最少使用的数据,设置了过期时间volatile-ttl:从集合中选择过期的数据Fromthedatasetwithexpirationtime(server.db[i].expires)toeliminatevolatile-random:selectdatafromthedatasetwithexpirationtime(server.db[i].expires)淘汰allkeys-lru(leastrecently)used):当内存不足以容纳新写入的数据时,在key空间中,去掉最近最少使用的key(这个是最常用的)allkeys-random:来自数据集(server.db[i].dict)inarbitraryselectionofdataeliminationno-eviction:禁止数据逐出,即当内存不足以容纳新写入的数据时,新的写入操作会报错。这不应该被任何人使用!6、什么是缓存穿透?如何避免?什么是缓存故障以及如何避免它?什么是缓存雪崩?如何避免?缓存穿透一般缓存系统根据key进行缓存和查询。如果没有对应的值,就去后台系统(比如DB)去查找。一些恶意请求会故意查询不存在的key,大量的请求会给后端系统带来很大的压力。这称为缓存穿透。如何避免?1:即使查询结果为空也缓存,将缓存时间设置短一些,或者插入key对应的数据后清空缓存。2:过滤一定不能存在的key。可以把所有可能的key放到一个大的Bitmap中,查询的时候通过bitmap进行过滤。缓存击穿:对于一个设置了过期时间的key,当缓存在某个时间点过期时,这个时间点有大量并发请求这个key。当这些请求发现缓存过期时,一般会从后端DB中加载数据并Set回缓存。这时候大的并发请求可能会瞬间压垮DB。如何避免?:1.使用mutex:当缓存失败时,不要立即加载db,先使用redis等setnx设置一个互斥量,然后在操作成功返回时加载db并重置缓存,否则重置尝试获取缓存的方法.2.永不过期:物理不会过期,但逻辑会过期(后台异步线程刷新)。缓存雪崩当缓存服务器重启或一定时间内大量缓存失效时,这会在失效时给后端系统带来很大的压力。导致系统崩溃。如何避免?1:缓存过期后,通过加锁或队列控制读数据库和写缓存的线程数。例如,只允许一个线程查询某个key的数据和写cache,其他线程等待。2:做二级缓存,A1为原始缓存,A2为副本缓存,当A1失效时,可以访问A2,A1的缓存过期时间设置为短期,A2设置为长期3:不同的key,设置不同的过期时间,这样缓存失效的时间点尽量统一_java培训机构7、你用过Redis分布式锁吗?先用setnx去竞争锁,然后用expire给锁加一个过期时间,防止锁忘记释放。如果在setnx之后执行expire之前进程意外崩溃或者需要重启维护怎么办?set命令的参数非常复杂,所以应该可以把setnx和expire同时合并成一个命令!文章来自代码世界小白
