社招面经:联易融一面2021.04.15
项目介绍
- 项目使用的架构技术体系SpringCloud、Spring、SpringMVC、Springboot、Mybatis、Mybatis-plus(该公司招聘需求上有就介绍了)、Nacos、Redis、Rabbitmq、Kafka等.
- 项目主要业务功能
- 个人负责业务模块
消息队列在项目中使用场景 :
- 解耦和复用: 主要介绍通过消息队列实现不同业务服务间信息变更的通信功能,实现服务层面解耦合,以及一次发送多个下游服务均可获取.例如下单和库存解耦
- 异步: 非核心业务异步执行,保证主业务流程响应速度.例如发送邮件短信/关联日志或者其他信息的记录修改之类的
- 流量削峰填谷: 在流量洪峰时发挥例如水库的作用储存流量,防止打死后端服务
- 使用消息队列做代理消息中继器,实现web及时通讯功能
消息队列消息可靠性如何保证(消息丢失怎么办)
- 开启消费确认机制,Broker收到消息发送到队列中后(开启持久化则是持久化后)向生产者发送接收ACK确认(这不影响生产者发送新的消息),否则生产者重发
- Broker消息持久化,保证Broker宕机后重新启动可加载未被消费的消息(Broker是磁盘节点,消息支持持久化,队列是持久化队列)
- 消费者手动ACK,超时未ACK则会重发,所以消费者要保证消费幂等(版本号),消费者也可以先落盘,消费完修改完消费状态再ACK.定期扫描重新执行盘中未成功消费的消息
消息顺序性怎么保证的
- kafka和rocketmq只保证同一分区/queue是有序的,所以可以通过指定投递算法,让同一业务消息都投递到同一个队列上保证部分有序性.
- rabbitmq可创建多个队列,让指定key的消息投递到固定队列上.保证部分有序性.
- 我们其实有序性只保证这单条订单业务流程里有序即可,不需要保证所有消息都有序
定时任务框架使用的那种
- 我们使用的Spring schedule注解 @Scheduled实现定时任务.没有用特别复杂的开源框架
- 定时任务框架: XX-JOB 和 Quartz可实现任务调度管理
项目OOM排查思路:
- 使用-XX:+HeapDumpOnOutOfMemoryError参数在OOM情况时dump下内存快照.然后通过jvisualvm分析快照内存对象情况反推可能的业务内存占用的情况.也可以通过-XX:PrintGCDetail查看在GC情况分析是那块区域无法释放内存
- 查询是业务上的,减少对象把握时间,将多次序列化的全局列表信息存入JVM或者单条存入Redis
- 还可以查看GC信息分析一下是那块区域内存溢出了/导致频繁FULLGC导致系统卡顿
有几种OOM的情况
- 堆溢出: OutOfMemoryError.(根据可达性分析法没有可回收的对象占满了堆内存)
- 栈溢出: 可通过-Xss设置栈大小.当虚拟机栈进行拓展内存空间无效时会报OutOfMemoryError异常.这里注意和StackOverflowError区分开,这个错误是由于线程栈帧深度大于栈允许的深度,栈深度也和栈大小有关系成正比.这里JVM书上有讲,单线程很难栈OOM,更多是栈溢出.但是可以通过调大内存,减少栈内存分配.创建多个线程时复现OOM.所以栈上OOM可以通过减少堆内存实现(当进程的内存有限制时).
- 元数据区OOM: 不断动态创建代理类;所以日常动态代理生成流程要谨慎
- 堆外内存溢出: 不是很了解,有大佬可以透露一些场景吗
ArrayList数组对象排序怎样操作》使用API执行了哪些步骤
这里询问使用JavaAPI是允许的
- Collections.sort定义函数式接口或者数组元素对象继承Comparable实现排序
- stream流.sort定义函数式接口实现.并在最后.collect(Collectors.toList())
- 获取ArrayList中元素数组,排好序后modCount增加一次.这里应该可能问的是流式执行方式
Innodb行锁(for update)(Mysql)的实现过程
- Innodb行锁通过在索引上的索引加锁实现行锁,所以通过索引检索数据才会使用行锁,否则会使用表级锁
- 因为是在索引上加锁,所以当检索使用到相同索引项,但非同行数据会出现锁冲突(索引对应的所有行都会被加上锁)
- 间隙锁(Next-key): 当进行范围查询上排他锁时,范围内不存在的查询条件也会被上排他锁.防止新增数据导致的幻读.也防止事务执行失败进行数据回滚操作
SQL调优如何调优(这方面经验比较少)
- 联查: 禁止多表联查,可以业务上拓展开或者控制在五张内
- 子查询.尽量不使用子查询,有子查询的可以在业务上拆分开来或者使用联查处理
- 字段约束顺序: 唯一性高的字段尽量放在约束语句前面.避免Null判断,防止全表扫描
- 等值左边不使用表达式.右边尽量使用计算后的常量.函数计算可能会使索引失效等情况,所以尽量可以不在语句中使用函数.否则建议指定索引
- 建议看下SQL优化思路大全
数据库字段设计思路: 空值如何设置的,为什么这么设置
- 满足范式,列属性原子性;保证主键唯一依赖且传递依赖
- 列字段不能太多,关联字段保证关联唯一性高字段.为查询效率可增加冗余字段
- 主键一般使用bigint,布尔类型tinint
- 字段尽量设置默认值.可用来定义一些默认的流程数据状态,也减少业务上查询出来的判空操作或者空指针错误.空值是不占用空间的,但是NULL占用内存空间,并且NULL值还会造成索引失效
- 使用innondb引擎(支持事务,改动的并发高)
- 不在表上定义外键约束,减少维护难度
- 使用逻辑删除,物理删除其实记录还是在表上存在的.但是会产生大量碎片,影响连续读取效率.
- 必须添加注释
Mysql CPU100%应如何排查
- show full processlist;查看sql执行线程(连接)的状态,查看执行状态是否是异常的
sending data(慢sql),copying to tmp table(大结果集sql),copying to tmp table on disk(大结果集sql,超过临时内存,需拷贝到磁盘中),sorting result(大结果集排序),using filesort(非索引的列内存快速排序.最后会回表取查询列值.),locked(锁等待)
.及时kill掉异常连接线程 - show variables like '%slowquerylog%';查看慢sql,分析sql慢的原因
- 调整参数 tmp_table_size、max_heap_table_size设置临时表大小
- 如果是Java服务则先看是否是频繁FULLGC造成的,否则打印下线程信息,查看是否有方法出现问题
- show full processlist;查看sql执行线程(连接)的状态,查看执行状态是否是异常的
Mysql执行计划explain使用过吗?
- Explain与SQL语句一起执行时(在句首),Mysql会将优化器优化过后的SQL执行信息显示出来
- 信息字段: id,select_type,table,partitions,type,possible_keys,key,key_len,ref,rows,filtered,Extra
- id: 标识语句执行优先级(组),当出现复杂语句时会有多条执行信息.id越大越先执行
- select_type: 当前查询类型,主查询(primary)、普通查询(simple)、联合查询、子查询(subquery)、derived(from表临时子查询)、union(union后查询)、union result()
- table: 查询结果集视图名字,可能为表名或者临时表名称
- partitions: 对于是分区表时显示分区信息(不理解,对Mysql知之甚少,惭愧)
- type: 查询类型. system(一行记录时,快速查询)、const(命中主键/唯一索引进行等值查询)、eq_ref(主键/唯一索引进行引用查询)、ref(使用命中非唯一索引)、ref_or_null(命中唯一索引并且额外搜索null值)、index_merge(使用多个索引)、unique_subquery(子查询返回不重复集合)、index_subquery(子查询返回重复集合)、range(范围索引查询)、index(查找索引树遍历,应该是覆盖索引了)、all(全表查询)
- possible_keys: 可能使用到的索引
- key: 实际使用到的索引
- key_len: where查询时使用到的索引长度
- ref: 常量等值查询const, 表达式/函数使用到时func,关联查询显示关联字段名
- rows: 查找到结果所需扫描的行数. 很重要的一个数据展示
- filtered: 符合条件记录占表记录百分比
- extra: 额外显示信息. Using index(使用到覆盖索引)、Using where(未使用索引查询)、Using temporary(临时表存储结果集.排序/分组会使用)、Using filesort(排序操作未用索引)、Using join buffer(连接条件未用索引)、Impossible where(where约束语句可能有问题导致没有结果集)
总结:当查询比较慢时还是先查看语句本身是否非常不规范,然后看是否扫描全表或者扫描行数过多.如果有加了索引还非常慢,则看下是否对索引解析执行有偏差
Maven生命周期Lifecyle(也不是很懂,只讲最常用的吧)
- clean清理上次构建结果
- valide校验工程信息是否正确
- comple编译工程
- test执行工程测试流程(标注的test的程序)
- package打包工程
- verify验证包的有效性
- install安装包到本地仓库
- deploy推送包到远程仓库
- 了解生命周期可以在不同生命周期绑定不同的插件事件,例如可以在package阶段绑定docker镜像的打包推送
<executions> <execution> <id>bind-lifecyle</id> <phase>package</phase> <goals> <goal>build</goal> <goal>push</goal> </goals> </execution> </executions>
参考
不会看 Explain执行计划,劝你简历别写熟悉 SQL优化
数据库设计时的一些细节的东西如何处理?
mysql行锁的实现
大厂必问的消息队列面试热点问题一锅端