这篇文章是读者「帅飞」的投稿。投稿网友给大家分享一下他的秋招提前批面试经历,目前三面技术面已过,hr 面也面过了,正在等消息。由于内容太多,先分享一面的面经。
自我介绍一下吧
面试官您好,我是 xxx 大学软件工程的一名大三学生,从大一开始学习前端,产生了对编程的兴趣,大二开始接触 Java,大二下学期学了 ssm,Spring Boot 等框架,也做了一些项目。后来发现基础很重要,于是从大三开始一直到现在,一直在对基础进行学习。比如:JVM,并发,操作系统,网络等。
看你的项目是分布式系统,那你的上游系统调用你的系统时可能会出现超时的问题,怎么处理?
在我们的系统的话,一般有监控平台,请求超时会抛出异常,会触发企业微信邮件告警,开发人员知道以后去看一下对应的日志中的异常信息。查到具体是调用哪个接口出现的问题,这个接口里是否调用外部系统,定位问题是外部的还是内部的问题。
那如果你看到的日志就是很多请求,你认为这种是什么问题,在外部系统没有问题的情况下核心线程池被打满了?
我觉得可能是有人新改了一个功能并上线,不小心写了死循环导致的 CPU 飘高。
PS:review code 的重要性
您说的线程池爆满的原因是可能一个接口中存在耗时的操作,导致请求这个接口的请求一直占用线程池,线程池被打满,从而导致后续来的其他接口的请求也会被影响。
这种情况一般可以服务降级、限流来处理。
在外部流量没有暴增的情况下,如果你的服务每隔半个小时会出现服务不可用的情况,这种怎么排查?
它这个是突然每隔半个小时还是其他情况?
就是这一天 11 点出现了,以后每隔半小时就会有两分不可用,qps 都保持正常值
我猜这种情况一般出现在,定时任务同步一些数据到其他系统,由于网络的问题,那边服务慢的话就会导致一个超时,然后就会发生这个问题。
正常接受请求,也没有任务跑,你会往哪个方面想?
那它会不会受到部署机器其他服务的影响呢。
没有
想了几分钟…..,这个目前还想不到其他的。
我可以给你个提示,往内存方面想
昂,立马 get 到点,是可能存在内存泄露吗?是不是由于存在内存泄露导致 full gc,gc 太频繁导致的。
对,那这种问题怎么排查解决
如果内存溢出的话,一般可能会有 OOM 抛出,JVM 可以设置参数在出现 OOM 时 dump 下内存的镜像,然后你可以利用一些分析工具,分析这个 dump 文件,有的工具直接可以给你一些优化建议,或者你可以找到哪个类的内存使用情况,找到内存泄露的点,去看代码。一般是 NIO 引起的,因为 Java 8 开启方法区使用的是元空间,不是永久代了。元空间是本地内存,不是堆内存,不受 JVM 管理,由操作系统管理,所以使用不当可能会出现内存泄露的问题。
好,那下一个问题,你那边用的是 dubbo 把
是
是借鉴 dubbo 开发的一个 rpc 框架吧
正常 Java 用的是 dubbo,之前是 php,为了 php 和 java 微服务之间的跨语言调用,实现了一个跨语言的 rpc,现在已经全部转为 Java 了,都用 dubbo 调用。而且微服务架构方面又做了改进,使用了 Service Mesh,面向云原生。
dubbo 服务的启动、注册流程,说一下
首先,有个服务的提供者启动起来后,会先向服务注册中心注册服务,如果是 zk 的话,它就是在某个 dubbo 的目录下注册上下,其他消费者想调用的话,就从 zk 上把对应的提供者的 ip 地址啥的拉下来缓存起来。然后就可以调用了。
那提供服务的提供者 ip 更改了,消费者是如何动态感知服务提供者的改变呢
一般分布式注册服务可以动态感知。如果是 zk 的话,服务提供者在 zk 上注册服务时创建的是临时节点,如果服务 ip 更改了或者服务挂了,服务的调用者通过 zk 的 watch 机制可以监听到服务提供者目录下的节点增加、删除、修改事件。
你用到了很多队列,kafka、rabbitmq 了解吗
我现在这边用的是 nsq 和 kafka,kafka 一般是大数据那边离线处理一些东西,nsq 一般是告警信息,两个系统之间进行解耦,进行信息交互时,发消息到 nsq。区别的话,kafka 对大数据处理能力比较好,nsq 的话一般作为一个正常的消息队列,同步改异步就可以用 nsq。
既然 Kafka 可以处理大数据,那为什么不用 kafka,而用 nsq 呢?
这个问题我之前想过,问过我的 leader。kafka 一般是大数据那边流处理什么的,它那边一般都只接受 kafka 的消息,和大数据集成比较好。至于选 nsq 的话,它是结合当时的业务场景选择的,这个也没有选哪个好哪个坏。
那他当时选型的时候,为什么不用 kafka
因为 kafka 貌似对于延时消息等支持的不太好,事务这些,它虽然对大数据的处理的好,但是它也有缺漏的地方,它有它的专攻方向,比如:吞吐量方面,但是也有它的不足之处,就好比计算机中的摩尔定律。一般业务系统常需要一些延时消息就需要用 nsq 了。
根据我的项目问的一些问题
……
有数据库调优经验吗?对于数据库有多索引匹配时,有什么经验吗
这个匹配的话,比如:ABC 三个组合索引,必须要顺序执行,比如 A = 2,C =2 。这个时候就不会执行,因为它破坏了顺序性。
你说这种情况是完全用不到吗
是的,因为它不满足索引的最左匹配原则。
那比如说,我数据库有多个索引,A,B,BC,一个查询条件 A,B,C 都有,那一般怎么查看呢
这个一般的话是用 explain 去分析一下 sql 的执行计划,它会输出可能走的索引,真正走的索引,扫描的行数,额外的消耗(extra),用没用临时表等。
那它分析出来的索引就是数据库一定会用的索引吗
explain 分析出来的吗
或者说,你觉得它 explain 分析出来的就是最佳的索引吗
一般情况下最佳的,数据库会根据你的 sql,通过解析器生成对应的语法分析树,它对这个树进行一些规则的优化后,会生成一些查询计划,通过基于时间成本的分析算法选出一个尽可能是最佳的查询计划。这个具体合不合适很难说。
你没有遇到建的索引不好,导致走的索引是最差的情况吗
这个一般的话,可能是你对索引一无所知,导致一些索引的规则不去遵守,而且数据库索引的匹配规则很多,很容易走坑。如果你的业务一定要走你设置的那个索引,mysql 也可以通过设置强制走你设置的某个索引。
你对 Java8 了解吗
了解,因为我现在参与的项目就大量用了 Java8 的特性。比如:stream,lambda 表达式,时间 API 等。具体应用场景的话,比如你一个接口要返回 VO List 集合,而你数据库查出来的是 DO List 集合,这个时候你就可以用集合的 stream 去做这个转换。相比于传统的写法,代码会变的很简单和清爽。
流式编写代码的好处和坏处可以说一下嘛
好处的话,写代码的效率快了,看着很舒服。
坏处的话,流式性能不怎么好,并发情况很多的情况下才体现出好。
我觉得最主要的是,之前你自己写的话,就面向过程化了。流式的话,Java8 提倡的是面向函数式编程嘛。编程模型之前最开始是面向过程,然后面向对象,面向元编程,面向切面编程,面向函数式编程,以后 java9 的面向模块化编程。而且把过程封装在函数中,通过函数去转换数据的状态对于线程安全方面也有很大的好处。
如果数据库对一些记录存在热点更新操作,有大量的更新,怎么解决呢
一般可以利用多级缓存去解决。如果数据量太猛增的话,你用 redis 客户端访问 redis 服务端都访问不到,因为带宽被打满了嘛。这种情况可以提前去探测某个 key 是不是热点,然后在本地缓存操作。
你怎么即时同步数据给其他人呢
它会有一个算法提前探测某个 key 是否是热点,然后框架会帮你进行本地缓存的管理。
数据库有单热点,那你怎么解决
这种一般先做一个缓存,然后可以用消息队列削峰填谷。
操作缓存可能会超时,你怎么保证这个数据的正确性呢?因为你加了缓存呀
对对,这个数据库和缓存保持一致性比较难保证。而且大量数据访问更新,也不能加锁,因为数据库通过行锁保证线程并发安全问题。
我要你解决的就是行锁等待导致的性能被拉低的问题,用缓存也是可以的,但是不能保证 100% 的数据一致性,那我的业务场景就是想要 100% 的数据一致性,你现在有大概的解决思路吗
这个可以用多套数据库主从集群来解决吗?通过这种方式来提升数据库的写性能。让多个集群去抗。数据库中间件可以把流量分散到各个主从集群中的主库上。
可以,这算是一种解决方案,那还有其他办法吗
修改数据库隔离级别也不行,因为它并发写的时候就会加行锁。
你打破这个行锁就行了
…… 我再想想。这个 ……
主要是单条记录引起的,它就是频繁更新引起的。
昂,这个是不是可以……… 我看 JDK 源码,频繁更新它一般是:HashMap 是非线程安全的,后来出现了线程安全版的 HashTable,但是它性能比较差,因为它直接就对整个 hash 表进行了加锁。后来出现了 CurrentHashMap,出现了分段锁,降低了锁的粒度,其实就是一种思想,你对一个热点数据的访问的话,就是分而治之,多去搞几个,均摊一下。难道是利用 hash 一致性算法把这些写请求,多分几张表。
差不多吧,思想就是分而治之,只要把单点数据拆分掉,让它变成多条数据,然后去更新多条数据,最后再合成一条。
嗯嗯。现在大数据一般也这样,大的搞不动就拆分。
从和你的对话来看,我觉得你基础也不错,基础我就不问了,我这边没有什么问题了,我看你这边,实习经历丰富,offer 收的也挺多。你有什么想问的
贵公司的技术栈,还有如果我进去以后所在的产品线。
面试官讲述了他们公司的技术栈和一些业务
面试官对我的一些职业规划的建议
多锻炼自己的技术思维 + 业务思维,可以往业务中台方向走。更好的支持别人的业务,技术主要服务于技术,要培养业务架构思维。
总结
我觉得面试过程中要避免自己一直在说,可以多和面试官去互动,去问面试官是不是这样子,这样可以避免你理解错面试官的问题。我们的项目可能大部分是 CRUD,但是我们的思维不可以停留在 CRUD,多去结合业务,也就是结合场景去思考你项目,这可能是一个很大的优势。毕竟技术是用于服务业务,去解决业务需求。
整理面经不易,花了我周末大部分的时间,如果觉得写的好话,欢迎关注公众号、转发,你们的支持是我继续写后续面经的动力。