6月底离职了,在上家公司期间经历了各种各样的线上故障,处置过各种各样的问题,从刚开始的掉头发到后面的游刃有余。这三年半对我职业生涯而言还是非常重要的一段,公司虽小,但也有了典型互联网公司的技术架构,从而让我有机会去面对各种各样的技术问题。离职找工作,这里记录下最近的一些面试。

字节-飞书组织架构管理

这次面试是还未离职的时候,很多东西没有好好的准备,比如面试官问到的redis key的过期淘汰策略,redis的实现我整本书都看过,没有准备的情况下很多东西确实是忘了,还问到了go的GPM模型,当然我的回答是不太了解,后面去看了下,跟tornado做了下对比,思想上是类似的,有epoll,有就绪队列等等。问如何理解依赖倒置原则,有点懵,因为依赖倒置这个词我早就忘了啥意思了,面试官提示了下就是依赖于抽象而不是具体的实现,我看过设计模式、代码大全,在生产中也写过非常优雅的代码,用到过一些设计模式,对于抽象我认为自己还是理解的比较深刻的,举了个案例叭啦叭啦了一堆。
算法题都没做,面完就估计自己应该挂了,后面吸取了教训,对于各种各样的技术栈做了一次系统的回顾。
友情提示:阿里字节等有hr约的面试基本都有面试评价记录,所以在没有准备的情况下不要贸然约面试,不然不好的面试评价可能会影响到筛简历。

智云健康-python技术专家

面试问到了flask的request,大概考的是线程隔离,我的回答是ThreadLocal,问我让我自己如何实现,我回答用dict,key是threadID,这样可以隔离不同线程的数据,python问的挺多的,其它的诸如数据库、linux基本没有问过。
总体面试的感觉比较草草了之,后面反馈一面未通过,原因是在工具和框架的深入度上以及Python高级语法和使用上有所欠缺,内心os:这是我三年前的水平啊!

帷幄-后端工程师

这次是到现场面的,公司尽可能让候选人只跑一次,一上午走完整个流程,非常nice,HR也很亲和。
技术面有两轮,首先做了自我介绍,然后问我项目中各种各样的点以及解决的一些问题,中间有一些波折,面试官对于项目的一些质疑感觉未经过大脑,其实项目中各种各样的解决方案是基于当时整体的技术业务架构背景下的,并不是想象中那么简单,算法题是两个有序链表的合并,技术面和HR面都通过了,最终薪资未谈妥。

长桥-后端工程师

本次面试主要考察的是go,问到了如何让一个协程正常退出,我的第一反应是代码段执行完了不就退出了么,没有get到面试官的点,后面做了下功课,原来面试官要考察的是select,如果以自顶向下的思维来思考这个问题,select只是一部分,不是全部,如何保证一个协程能够执行完所有的代码段并退出,那只要保证协程有退出的机制且不会被永远挂起,1是不能有死循环,如果当前协程有死循环那么就退出不了,如果其它协程有死循环,那么非抢占式调度的单核cpu情况下,当前协程不会有运行的机会,2是不能有死锁,如果两个协程相互死锁,就会被永远挂起,不会有任何执行的机会,3是对于channel的读写需要有正常退出的机制,可以用select配合default、context或者超时的机制。这个问题我后面有和面试官探讨,不过没理我。问用到sync里面哪些东西,回答Metux、WaitGroup、Once,问还有其它的么,答没有了,问到了字典是并发安全的么,有什么解决办法,回答有用到过并发安全的字典,具体是哪个忘了(sync.Map)。问sync.Once的机制以及会不会重复执行,我的回答是不会重复执行,然后面试官说有的情况下会重复执行,后面我查了一些资料,没有发现有重复执行的bug相关帖子,所以我的感觉是可能使用者写的代码有点问题,以我的经历来看,标准库出问题的概率还是非常非常小的。问slice内存分配的大小是多少,有点懵,当时回答了扩容机制,没有了解内存的大小,答案应该说的是类型字节乘容量然后向上取整(优化内存碎片的机制),其它的诸如数据库、linux、kv存储没有问到过。
本次面试一面未通过。

滴滴-后端工程师

上来问我做了哪些事情,我说主要工作是需求开发,然后解决线上面临的各种各样的问题,还做过很多运维相关的事情,面试官让我介绍项目,叭啦叭啦介绍了很多,然后他来了一句所以整个项目中你就做了这点事情对吧(傲慢的语气)?挺恼火的,很多东西都没在简历里体现。问到了发红包功能的细节,支付是所有系统最轴心的功能了,从分布式事务的词面意思来理解,本地扣除打款账户余额,然后调用第三方支付打款是一个典型的分布式事务,需要解决的是中间状态中可能出现的各种异常,状态是最终一致性。最后编码提是让两个go协程交替打印数组元素,稍微卡了下,最终实现了,但是可能跟他心中的标准答案有些差距吧。
结果是一面挂了,问hr哪里的问题好改进,答综合过往背景和面试的结果和职位不太匹配,没有具体说哪一方面。

图菱视频-后端工程师

一面有两个面试官,问python有GIL,为什么还是并发不安全,答线程调度是操作系统级别且无序的,问装饰器知道么有什么作用(太基础了,我觉得如果招资深的可能这么面不合适),叭啦叭啦,问知道装饰器的底层原理么,没有get到面试官的点,我问面试官是否说语法糖的事情,我再仔细想了下,问到是否是指针指向装饰器返回的函数(应该是回答了他的问题),问go的slice扩容的机制,这个比较简单。问红包打款模块的细节,叭啦叭啦,问为什么不能第三方打款成功之后再扣除本地账户的钱,这样也能解决事务一致性的问题,有点懵,但是抽象出来就是A和B事务之间的顺序性,红包打款这里账户扣减是必要条件,不然会出现超发的问题,也就是B发生的前提条件是A。问有用到过设计模式么,我提到了python的logging模块的handler设计,这里虽然没用到固定的某个模式,但是我觉的最重要的还是抽象本身。问mysql如果有两个单独的列索引a和b,查询的语句是where a=xx and b=xx,mysql会用到哪个索引,答有可能用到有可能用不到(可能跟面试官的答案有点不一样,顿了一下),还是自顶向下来思考这个问题,mysql的本身是为了高效的查询,所以不管用不用到索引,用哪个索引都是为了达到高效的目的,一个查询如何执行是由cpu和io的代价来决定的(cost base),假定a和b列的区分度都非常低,那么扫全表的效率会更高(顺序io),如果区分度都比较高,那么会倾向选择区分度更高的索引(可以扫描更少的行),高效查询是本质,掌握了本质就不会在各种各样的问题里迷失。算法题是二叉树每层的和,层序遍历的变种,很快写完。
二面也是远程视频,问有个接口返回n行数据,数据从数据库查,这个接口rt随着n线性增长,比如请求10行消耗100ms,请求20行消耗200ms,猜可能是什么问题导致的,技术上的猜谜还是挺有意思的,我解决过的很多问题也是通过猜的形式来一步步推导出来的,这个面试题在现实中你首先得发现这个线性增长的规律才能一步步猜测推导(发现规律是第一步,很重要),答不太可能是因为查10行数据导致的,因为如果这些数据在磁盘上在一个页内,那么读10行还是读20行都是一次IO,不会导致线性增长,那么有可能是在组装最终的返回数据里做了一些操作,导致rt增长,那么时间都花在哪去了,自顶向下思考,无非是cpu、网络io等待、锁等待等等,这里面最有可能的是网络io操作,当时我给的答案是可能遍历列表的时候每次循环都请求了外部接口,面试官提示说是在django的项目里,假设没有第三方接口调用,其实django我初期用过,现在不是很熟,面试完之后我想了下,也有可能是ORM内的一些机制,在select完列表时又遍历做了一遍关联的查询,本质上还是io等待上,最终我说一个接口的完整的性能诊断还是要做apm,看看时间都花在哪去了,再做优化。第二个是编码优化题,业务同学写的代码可能会爆栈,代码里做了递归,但是递归的判定不严谨,特殊的情况下(可能发生的事在未来某个时间一定会发生)会导致栈溢出,做了一些优化,应该还ok。第三个问题是典型的goroutine泄露的问题,做一下优化就好了。最终还想问django orm的一些细节,但是这些细节我真忘了(tornado我还能掰扯两句)。整体上这次二面跟之前还是不太一样的,不拘于某个固定的答案。

声网-后端工程师

一面面试官更偏向于运维工作,谈下来感觉跟我之前在团队内的职责类似,也是个trouble shooter。先做了自我介绍,问简历里提到的golang high cpu问题是如何诊断解决的,那就从监控发现high cpu说到pprof,再说到flame graph(性能诊断利器),发现了pprint使用反射的机制来输出pb结构,问怎么优化,答pb直接输出是看不了的,是二进制,看了pb相关的库,发现有pbToJson的实现,采用上线之后解决了high cpu的问题,问pbToJson的实现原理,我没太了解过,但是根据自己的理解作出了答案,pb其实已经定义好了,在生成pb到go文件的时候就已经知道,pb字段对应到json的字段了,没必要再通过反射来获取。问对k8s的整体架构的了解,多大的集群,答5个节点,架构从namespace、ingress、service、deployment谈到hpa等。问镜像如何打包,怎么优化打包时间,答使用docker build,引用初始公共镜像作为一层,然后拷贝,执行安装依赖、C库的命令,设置启动命令行最终构建出来一个镜像,优化(优化可以很泛,但是本质上脱离不了cpu、磁盘io、网络、算法几大类)的话我只答了依赖的镜像可以使用小版本的。问k8s日志如何采集,答用相关的k8s组件捕获pod标准输出发送到日志服务,然后再切分持久化建索引等等,问prometheus的语法,答虽然了解点,但用的很少,忘了。问k8s集群如何诊断问题、如何抓包,答我们应用集成了错误采集的服务,所以应用层的问题直接就知道了,但是更底层的需要通过抓包来解决的我们暂时还没遇到过。最后聊到了语言的问题,他们公司用的node,我虽然也写过js,但也仅是写过,另外我也诊断优化过java写的搜索引擎性能问题,虽然当时有点令人头秃,对于语言我还是开放性的。一面过了。
二面视频面试,习惯了问各种语言的语法和库的面试,这次有点不一样。问如何计算一个点是否在椭圆内,这个比较简单,按椭圆定义的公式就好了。问如何确定一个点是否正好在椭圆的边上,这个跟面试官做了一些讨论,包括用一个大椭圆一个小椭圆中间的阴影来确定这个点,小椭圆可能需要重新计算焦点,也可以用其它近似的算法来确定。三问有了解过哪些内存管理相关的知识,无关语言的,和面试官从栈内存聊到堆内存的分配、内存逃逸、逃逸的条件、为什么优先分配栈内存、引用计数和标记清除各自解决了什么问题以及优缺点、循环引用的解决方法、内存碎片的解决方案内存对齐、小对象的堆内存管理、通用对象预分配内存、python和go各自的内存管理方案,这次面试关于内存相关的技术全部抖出来了,体验还不错,还想和面试官聊下其它如linux、数据库相关的技术,时间不够,就先这样了。本次面试官在内存管理方面所掌握的技术应该是比较深刻的,有的细节我都没get到。二面应该是过了。

字节-飞书考勤

首先做了自我介绍,然后针对我的项目问了很多问题。问简历上提到的搜索引擎优化是如何优化的,答首先描述了下我们线上的问题,随着公司服务用户增多,某天晚上做活动的时候由于请求过多导致搜索服务挂掉了,我搭建了副本做了压测,然后通过jstack诊断到solr阻塞在fieldCache读写上了,做了一些优化,1是调整每分钟hardCommit一次,这样不用每次提交都打开IndexSearcher,所以频繁重新打开IndexSeacher会需要频繁预热缓存,2是在打开新的IndexSearcher并使用前,对Searcher执行几次查询,预热缓存,3是优化搜索语句,如fq=A and B 与fq=A&fq=B是不一样的,如果A条件比较通用B条件变化较大,可以使用后面的查询最大化利用filterCache。问数据库优化的案例,答线上的数据库问题其实很复杂,并不是单纯的优化慢SQL就好了,当然慢SQL的优化也经常做,一个实际的案例是某天做活动线上挂了,发现mysql CPU很高,通过采集查询语句分组分析,了解到是某个查询在10分钟内扫描了上亿的行数,这种单个查询命中了几十到上百行左右,并不是慢查询,但是活动期间的扫描行数的总量是非常恐怖的,当时处理的方式先block住这条查询,让线上服务其它功能正常下来,然后加缓存(适合的就是好的)上线,移除block,面试官问每次取到了上百行的数据那索引是不是建错了,区分度不高,当时没回答这个问题,详细的查询语句其实已经忘了,但是后面想了下如果对于百万行级别的表,查到上百行的索引区分度还是可以的,如果不建索引走全表那肯定是不能接受的。然后还谈到了优化应用层扫全表的效率,通过id来偏移,问如何优化复合索引的扫全表,答二级索引也是有序的,直接用上次查到最后的一条记录做偏移就好了。问context包有用到么有了解他的数据结构,答有的,大致了解过有父子context,父取消,所有子取消,里面还是用了channel,后面还问了一些问题,但是有的我没get到面试官要问的点,有的点可能也没给到面试官想要的答案。算法题是层序遍历的变种,卡了我一段时间,有点慌,不过最终还是解决了。一面未通过,不知道是不是因为算法题卡了很久。

文章来源于互联网:近期面试回顾

发表评论