BAT程序员面试必问之:《项目中解决过哪些复杂的问题?》(标准回答模板来了)
面试官都爱问项目中解决过哪些问题?希望我这个回答能帮助到你。
前言
刚毕业那会参加校招面试,面试官都爱问:“在学校做了哪些项目?遇到过哪些问题?怎么解决的?”
结果到了社招,熟悉的场面又来了:“在项目中解决过哪些比较难的问题?解决思路讲一下?有哪些亮点?”
这种没有标准答案,并且一不小心就容易掉坑的问题,是面试官最爱问的!!
去年跳槽时,在阿里一面、二面、三面,网易一面、二面中,就都被问到过这类问题。
怎么回答好这类问题,不至于冷场而给面试减分,希望大家能在文章中有所收获。
1. 战术分析
首先针对提问的时间来做区分。
1.有的面试官是在听完自我介绍就开始问。
这种就属于常规模式,大家可以详细介绍一下项目的技术栈,尽量引入自己熟悉的技术点来回答这个问题。熟悉jvm就说解决过jvm相关的xxx问题,熟悉redis就说解决过redis慢查询等等。
2.有的面试官是先进行一番技术提问,最后再问这类问题。(比如阿里一面)
这种时候就要结合自己前面的表现和面试官提的问题来回答,尽量就选择前面没有交流过的问题来展开,或者可以选择前面没有回答的很好的知识点做弥补。
开发中我们解决过无数的bug,但类似于变量赋值错误,配置错误,死循环这种问题,也没办法拿出来说,面试官也很难展开提问。
如果项目业务单一,确实没遇到过复杂场景的问题,此时也要稳住气场,依然要表现出自信。
2. 从容应对
以我在生产上实际遇到过的一个问题举例:Mysql死锁问题。之所以选择该问题,是因为比较典型,死锁问题也不局限于业务,大家基本都能带进自己的项目。如果能讲的全面,能体现对数据库理解的深度和对并发的思考,是很加分的。
问题描述:
现在主流的直播间送礼物场景大家应该都熟悉,粉丝A给主播B打赏,粉丝A账号被扣钱,主播B账号增加收入,在我们这个案例里主播也可以打赏粉丝。
数据库中有张资产表asset,两个字段:uid(主键,用户标识),num(用户余额)。
用户A和B分别存在一条资金记录:
此时,直播间内,A送礼物给B,先扣A的钱,再给B加钱。
同一时间点,B也送礼物给A,先扣B的钱,再给A加钱。
在JAVA服务中,这两个事件是两个线程同时在执行,并且扣钱和加钱肯定是在同一个事务中。
当两个线程同时执行完扣钱的操作,问题就出现了。
线程1:事务中已执行完扣A的钱(线程1已拿到了A的资产表记录行锁),等待给B加钱。
线程2:事务中已执行完扣B的钱(线程1已拿到了B的资产表记录行锁),等待给A加钱。
这时死锁出现了:两个线程分别拿到了A和B的行锁,但事务没提交,都在等待处理后面加钱的操作,但是待加钱用户的行锁都被另一个线程拿着不放。
两个线程都没办法往下执行,就会报错了,给用户最直接的体验就是礼物没有送成功。
如果数据库设置的事务超时时间过长,加上并发很大,用户频繁点击,线程大量积压导致数据库和服务挂掉也是可能的(我们线上确实出现过)。
这是一个很典型的数据库死锁问题,该问题可转换成各种版本(大家可以参考插到自己项目里):
- 转账,A转给B,也是先扣A的钱,再扣B的钱。两个人同时互相转账就可能会出现死锁。
- 如果项目中没有转账业务,哪怕简单的在同一事务中更新两条记录,也可能会出现死锁。
- 也可以跟面试官说:“我在写代码时发现,在不同的事务中,如果出现相反的顺序更新两条不同的表记录。那么当这两个事务同时发生时,可能出现死锁。因此在写代码时务必要注意,严格按照相同顺序更新不同的表记录。”这样的话,哪怕项目中没解决过难点,但能以经验总结的方式讲出平时的积累,也是会让面试官眼前一亮的。(哪怕大家不说这个死锁的问题,讲讲自己的踩坑经验都是可以的)
3. 如何解决
解决Mysql死锁问题,可展开很长的篇幅,为了避免跑题,这里只列出主要的回答思路。想深入了解mysql死锁的同学可以在其他文章中继续学习哈。
- 描述现象,比如程序卡顿,送礼物长时间无响应,告警系统报错:“Deadlock found when trying to get lock...”
- 查询mysql死锁日志,命令:SHOW ENGINE INNODB STATUS。
- 分析死锁日志,定位到具体代码,发现是送礼物逻辑出现死锁。
- 讲出死锁原因,简而言之是因为两个事务中交叉获取行锁导致。大家在这里可以展开来,比如行锁、gap锁、Next-key,都可以详细介绍一遍。show variables like '%tx_isolation%'查询本身mysql的事务隔离级别,讲一下事务隔离级别与锁机制的关系,等等。
- 解决思路。如果是线上问题,当务之急是保证线上的稳定和用户体验。讲一下使用了哪些措施将线上报错率降到最低。
- 本例中的问题,最快的解决方法就是打破死锁的条件之一:交叉获取锁。可以根据uid排序,严格按照从小到大去更新账号余额(不管是加钱还是扣钱)。也就是将A与B之间的打赏行为控制为串行,比如A(uid是1)和B(uid是2)互相打赏,A打赏B的线程1中先进行uid排序,先扣A的余额,再加B的余额;在B打赏A的线程2中也是先进行uid排序,先加A的余额,再加B的余额。这样保证两个线程获取A和B的锁顺序相同,不管哪个线程先拿到A的行锁,另一个线程只是正常等待,不会出现死锁。
- 关于该问题有很多种解决方法,控制顺序只是最简便的方法。也可以将扣钱的操作执行完,加钱的操作放在mq异步去执行,等等。
4. 总结
如果工作中有记录和总结的习惯,这类问题是很好应对的。如果面试迫在眉睫,平时没有积累,大家可以参照文中给出的问题再结合项目去讲。或者将自己掌握的比较好的知识点,反向结合到项目中,再来回答这个问题。
比如有的同学对线程池底层原理很熟悉,可以讲;”项目中由于某个实习生(哈哈)滥用了线程池的参数,导致线程创建数量不受控疯狂飙升,导致内存溢出。“
总而言之,关键时刻不要蒙,大家加油。
面试专栏持续更新,希望大家多多关注!谢谢!
更多推荐
所有评论(0)