面试题由23年8月开始记录,主要参考B站黑马程序员的视频(新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)_哔哩哔哩_bilibili)和JavaGuide(项目介绍 | JavaGuide),并在多次面试中二次改进并增加题目。内容仅供参考,建议理解使用。
前言
本篇内容主要为RabbitMq、Redis和Mysql,这些内容在初级面试中被问到的频率较高,多数是基础问题。
RabbitMQ
RabbitMQ-如何保证消息不丢失
RabbitMQ消息的重复消费问题如何解决
RabbitMQ中死信交换机(RabbitMQ延迟队列有了解过吗)
RabbitMQ如果有100万消息堆积在MQ,如何解决(消息堆积怎么解决)
RabbitMQ的高可用机制有了解过吗
Redis
如果发生了缓存穿透、击穿、雪崩,该如何解决
《
缓存三兄弟
》
穿透
无中生有key,布隆过滤null隔离。- 缓存
击穿
过期key,锁与非期解难题。雪崩
大量过期key,过期时间要随机。- 面试必考三兄弟,可用限流来保底。
缓存穿透
查询一个
不存在
的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库例子: 一个get请求: api/news/getById/1
-
解决方案一
- 缓存空数据,查询返回的数据为空,扔把这个空结果进行缓存
- {key:1, value:null}
- 简单
- 但消耗内存,可能会发生
不一致
的问题
- 缓存空数据,查询返回的数据为空,扔把这个空结果进行缓存
-
解决方案二
- 布隆过滤器
- 内存占用少,没有多余的key
- 但实现复杂,存在误判
- 布隆过滤器
布隆过滤器
bitmap(位图) : 相当于以
(bit)位
为单位的数据,数组中每个单元只能存储二进制数0或1
布隆过滤器作用: 可以用于检索一个元素是否存在一个集合中,拦截不存在的数据
误判情况:
误判率: 数组越小误判率越大, 数组越大误判率就越小, 但是同时带来更多的内存消耗
- 布隆过滤器实现方案
- Redisson
- Guava
缓存击穿
给某一个key设置了过期时间,当key过期时,恰好这时间点有大量对这个key的并发请求,这些并发请求可能瞬间把db压垮
例子:
-
解决方案一
-
互斥锁
- 强一致
- 但性能差
- 适用于
支付
业务
-
-
解决方案二
-
逻辑过期
- 高可用
- 性能优
- 但不能保证数据绝对一直
- 适用于注重
用户体验
业务
-
缓存雪崩
同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力
-
解决方案
-
给不同的key的TTL添加随机值
-
利用Redis集群提高服务的可用性(哨兵模式、集群模式)
-
给缓存业务添加降级限流策略(ngxin、Spring cloud gateway)
- 降级可作为系统的保底策略,适用于穿透、击穿、雪崩
-
给业务添加多级缓存(Guava或Caffeine)
-
redis作为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
双写一致性:当修改了
数据库
的数据也要同时更新缓存
的数据,缓存和数据库的数据要保持一致
- 读操作
- 缓存命中,直接返回;
- 缓存未命中,写入缓存,设定超时时间
- 写操作
- 延迟双删
-
强一致性业务
- 强一致
- 性能低
- 共享锁
- 读锁readLock,加锁之后,其他线程可以共享读操作
- 排它锁
- 独占锁writeLock,加锁之后,线程阻塞其他线程读写操作
-
允许短暂不一致业务
- 异步通知保证数据的最终一致性
基于MQ
基于Canal
redis作为缓存,数据的持久化是怎么做的?
-
RDB
- 全称Redis Database Backup file(Redis数据备份文件), 也叫Redis数据快照。
- 简单来说就是把内存中的所有数据都记录到磁盘中。当redis实例故障重启后,从磁盘读取快照文件,恢复数据
- RDB的执行原理
- bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件
- fork采用的是copy-on-write技术
- 当主进程执行读操作时,访问共享内存
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作
-
AOF
- 全称Append Only File(追加文件)。Redis处理的每一个命令都会记录在AOF文件,可以看做是命令日志文件。AOF持久化方式是将redis的操作日志以追加的方式写入
磁盘文件
中。
- 全称Append Only File(追加文件)。Redis处理的每一个命令都会记录在AOF文件,可以看做是命令日志文件。AOF持久化方式是将redis的操作日志以追加的方式写入
AOF是
默认关闭
的,需要修改redis.conf配置文件来开启AOF
AOF的
命令记录的频率
也可以通过redis.conf文件来配
因为是
记录命令
,AOF文件会比RDB文件大得多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof
命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置
RDB和AOF各有优缺点,如果对数据安全性要求较高,在实际开发中往往会
结合
两者使用。
加入redis的key过期之后,会立即删除吗?
Redis对数据设置的有效时间,数据过期之后,就需要将数据从内存中删除掉。可以按照不同的规则进行删除,这种删除规则就被称之为数据的删除策略(数据过期策略)。
-
惰性删除
- 设置key过期时间后,我们不去管它,当需要该key时,在检查其是否过期,如果过期,我们就删掉,反之返回该key
- 对CPU友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查
- 对内存不友好,如果一个key已经过期,但是一直没有使用,该key就会一直存在内存中,内存永远不会释放
-
定期删除
- 每隔一段时间,就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中过期的key)。
- 可以通过限制删除操作执行的时长和频率来减少删除操作对CPU的影响。另外定期删除也能有效释放过期键占用的内存。
- 但难以确定删除操作执行的时长和频率
定期清理有两种模式
- SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf的hz选项来调整这个次数
- FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms Redis的过期删除策略:
惰性删除
+定期删除
进行配合使用
假如缓存过多,内存是有限的,内存被占满了怎么办?(redis的数据淘汰策略)
当Redis中内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中数据删除掉,这种数据的删除规则被称为内存的淘汰策略。
- noeviction(
默认策略
)- 不淘汰任何key,但是内存满时不允许写入新数据
- volatile-ttl
- 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰
- allkeys-random
- 对全体key,随机进行淘汰
- volatile-random
- 对设置了TTL的key,随机进行淘汰
- allkeys-lru
- 对全体key,基于LRU算法进行淘汰
- volatile-lru
- 对设置了TTL的key,基于LRU算法进行淘汰
- allkeys-lfu
- 对全体key,基于LFU算法进行淘汰
- volatile-lfu
- 对设置了TTL的key,基于LFU算法进行淘汰
redis分布式锁是如何实现的?
Redis实现分布式锁
Redis实现分布式锁主要利用Redis的
setnx
命令。setnx是SET if not exists(如果不存在,则SET)的简写。
- 获取锁
# 添加锁,NX是互斥,EX是设置超时时间 SET lock value NX EX 10
- 释放锁
# 释放锁,删除即可 DEL key
![]()
redisson实现的分布式锁
加锁、设置过期时间等操作都是基于lua脚本完成
其他面试题
五种基本数据类型
- String(字符串)
- 需要存储常规数据的场景
- 举例:缓存 Session、Token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。
- 相关命令:
SET
、GET
。
- 需要计数的场景
- 举例:用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数。
- 相关命令:
SET
、GET
、INCR
、DECR
。
- 分布式锁
- 利用
SETNX key value
命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)。
- 利用
- 需要存储常规数据的场景
- List(列表)
- 信息流展示
- 举例:最新文章、最新动态。
- 相关命令:LPUSH、LRANGE。
- 信息流展示
- Hash(散列)
- 对象数据存储场景
- 举例:用户信息、商品信息、文章信息、购物车信息。
- 相关命令:
HSET
(设置单个字段的值)、HMSET
(设置多个字段的值)、HGET
(获取单个字段的值)、HMGET
(获取多个字段的值)。
- 对象数据存储场景
- Set(集合)
- 需要存放的数据不能重复的场景
- 举例:网站 UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。
- 相关命令:SCARD(获取集合数量) 。
- 需要获取多个数据源交集、并集和差集的场景
- 举例:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等场景。
- 相关命令:
SINTER
(交集)、SINTERSTORE
(交集)、SUNION
(并集)、SUNIONSTORE
(并集)、SDIFF
(差集)、SDIFFSTORE
(差集)。
- 需要存放的数据不能重复的场景
- Sorted Set(有序集合)
- 需要随机获取数据源中的元素根据某个权重进行排序的场景
- 举例:各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。
- 相关命令:
ZRANGE
(从小到大排序)、ZREVRANGE
(从大到小排序)、ZREVRANK
(指定元素排名)。
- 需要随机获取数据源中的元素根据某个权重进行排序的场景
3 种特殊数据类型详解
- Bitmap
- 需要保存状态信息(0/1 即可表示)的场景
- 举例:用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
- 相关命令:SETBIT、GETBIT、BITCOUNT、BITOP。
- 需要保存状态信息(0/1 即可表示)的场景
- HyperLogLog
- 数量量巨大(百万、千万级别以上)的计数场景
- 举例:热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计、
- 相关命令:
PFADD
、PFCOUNT
。
- 数量量巨大(百万、千万级别以上)的计数场景
- GEO
-
需要管理使用地理空间数据的场景
- 举例:附近的人。
- 相关命令:
GEOADD
、GEORADIUS
、GEORADIUSBYMEMBER
。
-
MYSQL
基础
优化
在MYSQL中,如何定位慢查询?
- 方案一:开源工具
- 调试工具
- Arthas
- 运维工具
- Prometheus、Skywalking
- 调试工具
- 方案二:Mysql自带慢日志
- 慢日志记录所有执行时间超过制定参数(long_query_time,单位: 秒,默认10秒)的所有SQL语句的日志
- 需要再mysql的配置文件(/etc/my.cnf)中配置开启慢查询日志
- 配置完成之后,重启mysql服务器进行测试,查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log
SQL语句执行很慢,如何分析
可以采用
EXPLAIN
或者DESC
命令获取MySQL如何执行SELECT语句的信息
- type
- sql的连接类型
- prossible_key
- 当前sql可能用到的索引
- key
- 当前sql实际命中的索引
- key_len
- 索引占用的大小
- Extra
- 额外的优化建议
了解过索引吗?(什么是索引)
详情可看B站尚硅谷的视频115-为什么使用索引及索引的优缺点_哔哩哔哩_bilibili
什么是聚簇索引,什么是非聚簇索引?
知道什么叫覆盖索引吗?
MYSQL超大分页处理
![]()
![]()
适合建立索引的情况
- 字段的数值有唯一性的限制
- 频繁作为 WHERE 查询条件的字段
- 经常 GROUP BY 和 ORDER BY 的列
- UPDATE、DELETE 的 WHERE 条件列
- DISTINCT 字段需要创建索引
- 多表 JOIN 连接操作时,创建索引注意事项
- 使用列的类型小的创建索引
- 使用字符串前缀创建索引
- 区分度高(散列性高)的列适合作为索引
- 使用最频繁的列放到联合索引的左侧
- 在多个字段都要创建索引的情况下,联合索引优于单值索引
不适合建立索引的情况
- 在
where中使用不到的字段
,不要设置索引 数据量小的表
最好不要使用索引- 有
大量重复数据的列
上不要建立索引 - 避免对
经常更新的表
创建过多的索引 - 不建议用
无序的值
作为索引 - 删除
不再使用或者很少使用
的索引 - 不要定义
冗余或重复
的索引
索引创建原则有哪些?
什么情况下索引会失效?
谈谈对sql的优化经验
锁
Mysql锁有哪些,如何理解
- 表锁
- 读锁、写锁
- 意向锁
- 自增锁
- 元数据锁
- 行锁
- 记录锁
- 间隙锁
- 临键锁
- 插入意向锁
- 页锁
- 悲观锁
- 乐观锁
- 显式锁、隐式锁
- 全局锁
- 死锁
其他面试题
事务的特性是什么?可以详细说一下吗?(ACID)
并发事务带来哪些问题?怎么解决这些问题?MySQL默认的隔离级别是什么?
- 并发事务问题
- 脏读
- 不可重复读
- 幻读
- 隔离级别
- 读未提交
- 读已提交
- 可重复读
- 串行化
undo log和redo log的区别
事务的隔离性说如何保证的呢?
- 排他锁
- 如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁
- MVCC
- 多版本并发控制
尾声
本篇为初级面试题最后一篇,后续会抽空分享面试心得与工作心得,感谢您的阅读。