0422-面试
-
redis 缓存击穿、穿透、雪崩
- 击穿:单一 key 失效,并发请求打到数据库上
- 均匀设置过期时间
- 穿透:单一 key 不存在,请求打到数据库上
- 检查 key 是否否和要求
- 缓存空值或默认值
- 使用布隆过滤器先判断下数据是否存在
- 布隆过滤器的原理是:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了
- 雪崩:某一时间,大量的 key 失效,请求打到数据库上。
- 均匀设置过期时间
- 如果 key 不在 redis 里面,就加一个互斥锁,保证统一时间只有一个请求来构建缓存,互斥锁要加超时时间。
- 不够缓存设置有效期,后台定时更新 redis 的缓存
- 服务熔断,请求限流
- 构建高可用 redis 集群
- 击穿:单一 key 失效,并发请求打到数据库上
-
出现了死锁如何解决?
- 保持案发现场
-
SM3、SM4 的区别,以及流程?
- SM3 类似 MD5
- SM4 对称加密
- 加密流程:对 msg base64 编码,对 base64 编码进行 SM3 摘要的得到 sm3 字符串, 对 base64 编码进行 SM4 摘要的得到 sm4 字符串
- 解密流程:对 sm4 字符串解密,得到 base64 编码,对 base64 编码进行 sm3 摘要,与请求中的 sm3 字符串进行比较
-
HTTP
- RESTful 风格
- PUT
- POST
- GET
- DELETE
- Accept 的值
- text/html
- application/json
- application/octet-stream 下载文件
- RESTful 风格
-
Innodb 和 myisam 的区别
- InnoDB 支持事务,行级锁、表锁;查询全表行数需要遍历全表;适合大量增删改的场景(数据安全);
- MyISAM 不支持事务,支持表锁,不支持行级锁;查询全表行数快;适合大量查询的场景;
-
索引
- 索引的类型
- 主键索引
- 唯一索引
- 普通索引
- 组合索引
- 全文索引
- 数据结构:B+树
- 最左匹配原则:复合索引,匹配从最左边开始匹配,
- 回表:根据非主键索引找不到所有要查询的列,最后还是要去主键索引上查找数据。
- 覆盖索引:仅通过索引就能查询到想要查询的数据,不用回表。
- 索引下推:把
where
中的一些过滤条件放到引擎层来过滤。
- 索引的类型
-
JVM 调优的案例
- 分析 GC 日志,导出 dump 文件
- 修改堆内存大小
- 设置在 OOM 时导出 dump 文件
- 如果频繁创建对象,应该适当的增加年轻代的空间
- 如果有较多的持久对象,应该适当的增加老年代空间
-
导入导出优化(数据量很大)
- 分页查询出要导出的数据
- 分页时,如果数据量很大的话,使用
子查询
来代替limit
进行分页。 - 1000W 数据,每页大小 100000 ,导出需要 12 分钟左右。
- 优化
select count(*) from table_name
, 让这个查询走普通索引,而不是主键索引。查找时,会把索引的数据加载到内存,主键索引树上存放所有的数据(占用内存大),普通索引树上存放的是索引列的数据。 - 设置 fetchSize 减轻对内存的压力。
- 分页时,如果数据量很大的话,使用
- 使用
SXSSFWorkBook
对象 - 重复使用样式对象
CellStyle
,不要每次填充cell
时都创建一个新的样式对象 - 导出实测
- 使用 limit 来进行分页 1000w ,每页 10000 超过 1 小时
- 使用子查询 + limit 分页, 1000w ,每页 10w -Xmx1g ;导出会有内存溢出
- 使用子查询 + limit 分页, 1000w ,每页 10w, -Xmx1g ,每从数据库中读取到 1000 条记录,向 sheet 中写入一次;耗时:761700 ms 约等于 12 分半
- 使用子查询 + limit 分页, 1000w ,每页 10w , -Xmx1g ,每个 sheet 100w 行,每个 sheet 页使用一个线程;耗时:333506 ms 约等于 5 分半
- 使用子查询 + limit 分页, 1000w ,每页 10w , -Xmx1g ,每个 sheet 100w 行,每个 sheet 页使用一个线程,设置 fetchSize 为 1000 ;耗时:408296ms 约等于 6 分 48 秒
- 使用子查询 + limit 分页, 1000w ,每页 10w , -Xmx1g ,每个 sheet 100w 行,每个 sheet 页使用一个线程,设置 fetchSize 为 10000 ;耗时:耗时:350596ms 约等于 5 分 50 秒
- 使用子查询 + limit 分页, 1000w ,每页 10w , -Xmx4g ,每个 sheet 100w 行,每个 sheet 页使用一个线程,每个线程一个数据库连接, workBook 的 rowAccessWindowSize 设置为 10 w,List 的 size 为 10w, ;耗时:耗时:266845 ms 约等于 4 分 26 秒
- 分页查询出要导出的数据
-
HashMap 、HashTable 的区别
- HashMap 线程不安全;底层数据结构:数据+链表/红黑树,链表的长度大于 8 时,转为红黑树;key 允许为空;
- HashTable 线程安全;key 不允许为空;
- 集合的种类
- List
- Set
- Map
- set 和 list 的区别
- Set 无序,不重复
- List 有序,可重复
-
使用到的 Spring 组件
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Spring Cloud Alibaba
-
js 数据类型
- 基本数据类型
- undefined
- null
- boolean
- string
- number
- symbol ES6 新增
- 引用数据类型
- object
- array
- function
- 基本数据类型
-
==
、===
的区别==
比较前会先将对象类型转成一致,再比较内容。===
先比较类型是否一样,一样的话,再比较内容。
-
用到的 Spring 注解
- spring 实现异步的几种方式
- @Async 注解
- 线程池
- IoC 是如何实现的?
- spring 实现异步的几种方式
如何保证数据库与缓存的一致性?
两种方案
- 先更新数据库
- 更新数据库后,删除缓存,如果删除缓存失败,将 key 传递给消息队列,让消费者来删除缓存。
- 更新数据库,订阅数据库变更日志,将数据变更的 key 传递给消息队列,让消费者来删除缓存。
- 先删除缓存
- 先删除缓存,在更新数据库会有两个问题
- 删除缓存成功,在更新数据库成功之前,有另外的请求构建的缓存,导致缓存错误
- 删除缓存成功,更新数据库也成功,但是在从库数据更新之前,有另外的请求构建的缓存,导致缓存错误
- 解决方案:延时双删
- 在更新数据库成功之后,延时删除缓存。
- 延时时间的要求
- 大于另外线程请求数据库+构建缓存的时间
- 大于主从复制的时间
- 延时时间的要求
- 先删除缓存,在更新数据库会有两个问题
延时双删的伪代码
#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)