华铁视通面经(一面过)
2年经验,越级面试中级开发岗,纯业务面(50min),没问任何八股。问题如下:
1、介绍你解决过的那件事让你觉得最有成就感?(中间因为耳机问题,说了两遍)
介绍我的pdf电子处方并发生成优化:最开始我们系统的pdf做的单线程生成,一份pdf需要200ms,导致哪怕实例扩容到6台服务器也只支持30份/s的pdf生成。远不够用,因此准备做线程池优化,先当成CPU密集型任务设计线程池,然后使用Jemeter压测。结果发现了诡异问题:线程数量越多,单份pdf生成越慢,当并发线程数24个时,单份pdf生成甚至需要3000ms。
当时花了很多时间理清思路,发现pdf每次生成都需要重新加载字体对象,该对象生成依赖于读取的字体文件流。我之前的做法是每次都重新读取文件流、然后转换为字体对象。但是高并发下文件流读取属于IO任务,Inputstream没有做并发文件读取的优化,导致IO竞争、大幅影响性能。最终查阅资料发现pdfbox(底层的pdf绘制库)做了读取字体的相关优化,它提供了一个中间对象,可以使用该对象生成字体对象。因此只需要做一个预加载,也就是提前把文件流转化为中间对象,该过程只需要弄成一个单例bean,就无需重复读取文件流,从而避免竞争问题。最终单份pdf生成只需40ms、配合三台服务器+线程池,可支持2400份/s的pdf生成。
2、你是如何发现是那个IO读取的问题的?
主要是压测发现的,当时jemeter发现,一份pdf要200ms,两份pdf各自需要接近400ms、4份需要接近800ms。因此就觉得是某个地方有瓶颈问题。我就去梳理我的pdf生成流程:加载字体、绘制。由于字体每次都重新加载,因此第一个就怀疑那里的问题,结果查阅资料发现pdfbox对此场景有优化,才知道果真是那个并发文件读取的问题。查阅资料发现Inputstream对于并发读取没优化,有很多冲突,因此非常影响性能。
3、如果pdfbox没有那个中间对象的优化,你会怎么设计?这是个开放性问题。
(被问的有点懵,确实不太会)我暂时只能想到对字体文件搞几个副本,能缓解一下这个问题。
4、MySQL你负责的数据表中,最高是多少量级?
最高的有两个,一个是30万数据的药品明细表、一个是10万数据的处方表。
5、大表的join查询,你做过什么优化?
两个优化,让数据条数少的表作为被驱动表、驱动表对于关联字段加索引,比如我项目中要查某个订单对应的药品明细,需要联表,因此我就在药品明细表加了一个订单id的索引。
6、这么看来,你们的MySQL还是系统的瓶颈?
我解释我们系统做了MySQL主从复制,能支持一定的并发度。再加上数据量还不是特别大,没有到需要水平分表手段的地步。面试官对此表示认可,觉得我们系统暂时不需要考虑优化数据库瓶颈。
7、MySQL/Redis/MinIO的持久化你怎么做的?
首先Redis我们没有保存关键数据,因此没有做持久化。然后MySQL和MinIO就是做了数据卷挂载,这样数据就会被持久化在宿主机上。同时注意禁用这两者的自动扩缩容,避免数据乱跑。
8、RBAC这一块你们是用SpringSecurity之类的框架还是自己做的?
自己做的,传统的RBAC是用户关联角色、角色关联权限。而我们是做的用户关联角色、角色关联菜单,管理菜单的可见性。关键接口只做了角色校验,因为这是企业内部系统,用户都是公司员工因此这样做的。同时我们系统之前有一个接口表,后面不知为何废弃了,可能试图做过权限校验,可是放弃了。
9、这也正常。因为需要兼顾开发效率。那你们有没有同样的角色,看到不同数据的场景?
有的,就是一个运维经理角色,它需要能看到各自负责的区域代理商的数据,比如说他是湖南的,就看湖南那个区域的代理商,重庆的就看重庆的代理商。这样哪怕角色一样,看到的数据也是不同的。
10、怎么隔离的,隔离查询条件是什么?
首先判断角色是运维经理并且代理商id为-1。然后就加个条件:where代理商id in (绑定的代理商id列表)。因为我们所有数据都在同一张表里,按照代理商id字段进行的区分。
11、场景设计题,一个前端的这个大屏展示,需要展示多个数据图表,数据来源有各种各样的接口,比如说网络接口,或者是说各种不同的数据库接口,需要调很多个接口对这些数据进行一个整合给前端展示,前端最多接受2-3秒延迟,你会怎么设计?
我思路分三步设计,首先这么多数据这么乱,我们肯定不能一股脑地全丢给前端,我们后端需要做数据整合,需要对这个数据做一个整理,让他们格式先统一,要做数据清洗。
第二,这么多接口调用,我们肯定不能够同步地等待,所以所有接口的调用我们需要走异步,然后用消费者去监听他们监听之后处理。(这里其实漏掉了,应该是查出来按照相同格式落库,然后前端调接口只需要查那个统一格式的数据库)
第三,如果中途这个接口调用失败,报错超时,我们需要走重试机制。多次重试失失败了,我们还要记录这个失败情况。
12、如果部分接口调用失败,会怎么返回数据?
我们不能够直接丢前端给丢给前端一个报错,而是要对这个数据进行一些降级的展示,比如说展示一个数据不存在之类的,然后记录失败原因。
13、说一下这个千万级的数据迁移?正常介绍,早就熟记的东西我就不写了。
14、后续迁移之后数据查询的对接你参与了吗?
没有,我组长只给我安排了数据迁移。后续迁移之后对这个表还需要做什么处理,以及对接。这些涉及到比较复杂的业务了,后面我忙别的就没参与了。
15、你这个小程序,是只写了后端部分还是全都写了?
当时由于团队人员配比问题,自己写完了后端所有代码,然后使用trea写前端。先把接口都写完,把接口文档和需求文档一起丢给AI,让它生成一个初版的前端结构。然后再跟它对接接口、并且在页面上点一下,遇到什么bug之类的就再修复,反复处理最终写完。
16、这个Trea工具,是你自己找的还是公司统一使用的?
是领导让我自己找的,因为它一开始免费使用。
17、你的另一个pdf项目是完整的还是部分模块?
这是整个项目的部分模块。当时需要生成那个项目中的培训记录。也是用pdfbox。
18、哦不是小程序的,如果是小程序可能还得考虑屏幕适配问题。
这个其实我知道如何实现,前端把分辨率传过来,我对生成的pdf做等比伸缩即可。因为api操作pdf的宽高还是很容易的。
19、我给你介绍一下我们团队目前情况把(从业务再到驻场再到加班再到团队成立不久都说了)
20、期望薪资有什么要求?12薪和13薪你更接受哪个?还是随便都可以?
(后者是每个月工资会少一点)随便吧。我只是对自己有要求,薪资这块都可以。
21、预计今晚或者明天会有二面安排,会问你规划啥的。你有什么作品集或者运行的东西吗?
作品方面,小程序传在了github。还写了博客,目前访问也有1万+。
结束了,后续在boss上问了我博客链接。已约二面。对我来说,这是首次沉浸式体验了一波中级开发的提问模式,我是没想到纯业务我也能撑这么久。甚至场景设计也能做出来还算不错的方案,确实让我感觉到我能力肉眼可见的提升。也算是首次越级面试并且成功了。