这次面试的是小公司,深圳计通智能,面试分为初试和复试。使用腾讯视频会议完成。相比与上次面试,这次有所进步,进复试了。当然,这可能也与面试风格有关。这次面试着重与项目经历和技术,因此回答比较顺畅。
这一周干了什么
我先是研究了上次面试没回答出来,或者回答得不好的技术问题。然后顺着简历上的技术,又复习了一下asp.net core,wpf。因为对mvc模板和webform模板不太熟悉,因为以前只做过维护。因此又花了一个周末半学习,半重温式的学习了asp.netcore RazorPage和asp.netcore mvc两个模板。最后是根据之前问到的问题,总结之后面试可能遇到的提问。
在这一周还投了几个简历,收到了3个面试邀请。其中1个深圳,2个成都。星期一请假面试了深圳的那一家。因为他们要求上班时间面试。之后的面试也要求上班时间,麻烦了,短时间内不好请假了。而且面试之后的总结学习也需要时间。我是想缓一周的。投简历麻烦之处在于,我不知道对方是否会邀请面试。看来之后应该面试完一家,再投一家。
初试
在初试之前,人事微信询问了公司、收入、婚姻、家庭、籍贯。我逐一如实回答。
初试要求我打开视频。对方使用语音。一个年轻人事,一个中年技术总经理,还有一个广东中年人,听声音有一定年纪,不清楚角色,但也是能提技术问题的。听hr介绍,都是担任职位。这次面试不同于上次,基本是看着简历的项目经历和其中的具体技术问题问下去的。
首先是自我介绍
我叫xx,今年27岁,四川人。2020年毕业于西南石油大学,到现在有4年了,所学专业是软件工程
毕业后从2020年至今一直就职于目前这家公司。
最开始的1年在做winform,主要进行采集软件维护,也开发过几个页面,之后主要进行asp.net framework webform和mvc维护,以及web开发,后端主要是写sql。近两年则开始用asp.net core进行后端开发和layui+vue进行前端开发
最近完成的项目中扮演什么角色,做哪些工作
这个项目已经完成,我现在负责维护。开发的时候,由工程人员整理方案,和小组长讨论之后,他会搭建好项目框架和部分基础设施,然后把我们小组成员叫过去划分任务。我们完成之后提交。经常遇到需求不清楚,就要自己和工程人员讨论。这个项目的大多数地方我都参与了。
项目总结总感觉不太好,之后还得再回忆修改一下。
asp.net core项目搭建流程
首先是webapplication创建一个builder,然后注册托管服务,比如身份认证服务,efcore、各个业务逻辑服务、swagger服务之类的。然后是配置中间件,有静态文件访问中间件,swagger中间件,不过这个在生产环境中一般是注释掉的。然后还有404中间件、异常处理中间件。如果有用到websocket的话,还要注册websocket中间件。还有appsetting中需要配置一些信息。
我翻一下项目,还有终结点中间件,跨域中间件,路由中间件。服务还有memorycache服务,redis服务,automapper服务,httpclient服务,mvc服务(但我们没写mvc页面),总之挺大一堆
.netcore中日志分为几个等级
日志在appsetting中配置,大概分为info,debug,warn,error,trace几个等级吧。一般是注册日志中间件,在里面打印日志。controller中遇到错误大部分情况下会直接抛出去,也有时候记录一些信息返回前端,阻止异常抛出。
日志这方面真的是我的弱项,接触太少了。
数据安全传输
主要是要数据加密吧。这方面没有多少了解
项目中你们怎么做身份认证的,身份认证有几种
我确认了一下,你是指架构schema吗?他说说下去。我说最基础的是basic架构,但是basic使用明文传输认证字段,basic所有最好是和https加密结合使用。然后常用的是bearer架构,这种token是加密过的,比较安全。
token的原理是什么
token生成过程中使用数字签名对信息进行了加密,客户端仍然可以查看token信息,但是没法篡改。篡改了信息的话,服务器中间件那里使用签名验证token时会报错。
你说一下jwt身份认证流程
身份认证首先是登录方法那边用数字签名结合相关信息生成一个token,返给前端。前端我们通常是存放在localstorage中。发起请求的时候将authorization字段设置成这个token。然后后端会加一个身份认证中间件,在这里验证token。
我们通常还会建立一个currentuser对象存放token解析出来的字段,比如用户id,系统信息,业务信息
怎么让token过期
首先是等待token过期。他问,还有呢?我想了会,哦,还有可以设置expire字段,控制过期时间。他问,那过期时间设置为多久合适呢?我回忆了下说,不能设置太长,这样使用token就失去意义了。应该是分场景吧。比如电脑上,我经常发现头一天登录了,第二天打开不会跳转到登录页面,看起来token过期至少设置了10多个小时。如果是手机端的话,可能几十分钟比较好吧。
你能说下越权访问吗
我说不了解这个。
网上搜索了下。越权包括水平越权和垂直越权。这个两年前安全培训,靶场演练讲过,不过我忘了。水平越权指的是,A用户修改请求参数ID,获取B用户的信息。垂直越权指的是普通用户获取到了管理员的权限。水平越权应对方法是将id和token进行比对。然而我们靶场演练时服务器是php,使用查询参数代表用户,我不记得头部有token。然而我们现在使用的.net,开发时把用户id放在身份认证的token中,通过数字签名防止篡改,这没法水平越权。垂直越权我也不知道要怎么才能做到。
不同平台的系统有哪些通信协议
最见的就是http了,然后如果是和浏览器通信的话,还可以用websocket。然后还有socket通信。不知道webservice算不算?他说算。
webservice应该属于远程过程调用rpc的范畴了。rpc只是一种手段,就是用网络传输函数调用信息。vs中连接的服务那里就提供了能把openapi接口做成远程调用的功能。
你在开发过程中遇到过并发问题
有遇到过几次并发问题。是在做签到功能的时候遇到的。由于数据库设计得不好,设计了一个多值属性。然后签到的时候很多个请求同时去修改这个字段,就导致修改得不准确。最后只能去用lock关键字加锁解决。他问用lock有什么需要注意的?我说lock会导致很多线程阻塞在那里,lock里面尽量不要进行太多耗时操作。他问还有什么要注意的吗?我说还有就是lock中要使用静态变量,否则每个线程都使用不同的对象,lock就没用了。
现在想想,实际上lock代码块中的耗时问题应该交给缓存中间层处理,既能避免数据不一致,也能避免访问数据库耗时太久
其实我碰到过一个比较严重的问题,在异步方法中使用lock,结果lock失效,结果只能逼着使用同步方法。现在我能简单猜测一下是同步上下文导致的。因为异步同步上下文的机制是把变量复制到新线程上面去,结果被lock的静态变量就和临时变量没什么区别了
资源是怎么回收的
这个我比较疑惑了,就问,你是说托管对象吗,这个是clr负责的,如果是非托管对象。他说就比如文件这些。这下我明白了,就说使用后调用close方法关闭。但是更好的做法是放在using中,这样代码跳出using范围后,对象就会被回收了,避免忘记调用close。
我记得using是一个语法糖吧,似乎是被会被转换为为调用dispose方法?但说实话,没怎么用过dllimport调用C++代码,不是很熟悉非托管这块的资源释放的实现。但我猜主要是C++里面的mlloc申请的内存空间需要释放吧,这个大一学习链表的时候第一次接触这个函数。那对应的应该还有个freelloc函数才对。也就是说需要我们在C++中封装这两个函数,在C#中手动调用封装的方法,代替clr申请和释放内存。在C#中调用自定义的C++函数我有测试过,要说到内存的话,我只想到这个玩意了。
小组有多少人
有8个人
我还要计数才知道,就直接按照印象说的
组织架构
按照业务横着切分,分为钻井和井下。按照职责竖着切分,分为工程部和软件部。一共可以分成四组人员。
去过现场吗
没有真正去过现场。距离最近的一次是去新疆出差。平时也经常远程到现场电脑上部署和解决问题。有些软件是由工程人员带到现场安装的。他问,所以说你并没有去过现场,我说是的。
用到了哪些orm框架
我们常用的框架efcore和sqlsuger。efcore用的比较多一点。efcore的话,我们的数据库是多个应用共用的,所以都是以反向工程的方式生成模型,没有用到codefirst。对方问,这两个框架的优缺点是什么?我说efcore的linq操作比较方便一点,但是sqlsuger的外连接,数据分组聚合比较方便。
我还发现了efcore可以跟踪模型,这在单例模式下比较有用,但webapi中通常都是注入的socpe作用域,跟踪功能意义就减少一半。主要是我用ef写过长度上百行的linq,用三元运算符和嵌套linq处理聚合以及开窗的问题。sqlsuger还没这样用过。
数据库查询速度慢的问题怎么解决
最快捷的方式是加索引,比如日报表这些,数据达到几百万行或者上千万行后全表扫描速度会很慢。加了索引之后连接到索引列上面去就会很快。在后期优化sql时一般会注意这方面。对方问,除了索引之外,还有呢?我想了写说,还有物化视图吧,用物化视图把一些数据预先查询好,这样也能加快查询速度。
物化视图是常用的,我们这里大量使用。我观察米游社的数据统计有延迟,应该也是用的物化视图。查看查询计划看哪些大表走了全表扫描也是一个常见的方式,至少在dbeaver里面还挺方便,就一个按钮。
设计模式
设计模式本身在.net的各个框架中就大量使用。比如asp.net core的webapplicationbuilder使用了建造者模式,wpf中的命令使用了命令模式,C#中的事件使用了观察者模式。我们在一些处理有些数据时还可能用到一种和树形相关的结构模式,但具体名字我记不清楚了。工作中并没有专门去关注设计模式,只是遇到相关问题,需要使用设计模式时,会去查一下。
依赖注入容器中还经常使用工厂模式,使用匿名func委托作为工厂,比如各种provider
你从哪些地方学习新的知识
学习的途径主要是看技术博客和一些视频。工作中接触到的技术是一个重要的方面,比如asp.net core这一块。然后平时的兴趣也是一个方面,比如我会学习一下像webrtc音视频的技术。还有就是有意向的方向,比如wpf,maui这些。
怎么看待加班的
该加还得加啊,不然赶不上进度
他能问出这个问题,意图是什么已经明显了,要么加班,要么走人。不管我想不想进去,要想继续的话,这里只有这样回答。
职业规划,技术规划、工资规划
asp.net core本职工作这边还是打算继续精进。还有net aspire云原生开发也打算去学习一下。然后桌面的话,wpf还是要继续学习,毕竟是第一个现代化桌面框架(也是最成熟的)。工资还是希望比目前高几千,因为这4年就涨过一次工资,而且很少。
有什么想问的
我没看出来什么动向,就说没什么想问的了。
复试
大概1个小时后,人事叫我做了一个MBTI性格测试,下午2点多,大概3个小时后,人事发来复试通知。这时我在上班,协商了时间后,复试在晚上8点开始。复试由年轻人事+40多到50中年技术总经理组成。双方通过腾讯视频会议进行。令我比较意外的,他很瘦。
复试比较少谈论具体技术,感觉主要是个人的经历和综合能力提问。
首先人事介绍了一下他,然后让我再自我介绍一下
我再复述了一下。他问,你毕业以后,包括实习,一直都在这家公司吗?我说是的。
你对我们公司有什么了解
我不是很了解。就只有上午发了一个公众号过来时,进去看了一下。但是我看不懂那些业务。对方问,也就是说你对我们公司没有多少了解是吧?我说是的。
怎么评价直接上级
在他之前有一个老的组长,他比前一个组长年轻。他使用新技术比较多,来了之后我们就转向了asp.net core。对方问,更立体一点,我说,可能他是后面来的,不是很关心我们吧。
其实我是想很隐晦的说,他只顾让我们加班完成他的业绩和工资,克扣我们的补休和假期,对我们没有任何好处。前一个组长我提出这件事之后,他就不再叫我们加班了,但后面这个,不知道他是察觉不到,还是天降系地位不稳怎么回事,对抗了好几次,仍然没有变化。
你所在小组有多大
大概有8人吧。开发有60-70,工程有50-60人左右。他问你们小组有多大,我说有8人。我们小组比较小,重心不在这边。估计得等以后甲方这个业务专业的上司上位。
你怎么看待AIGC
AIGC我用openai比较多。国内通义灵码前几周大幅度降价,我也去调了一些sdk。结果发现GPT和想象中的人工智能差别有点大,算不上人工智能。因为GPT服务器只是根据我们的请求和历史对话数据给出响应,而对话的历史数据则需要我们保存在本地,或者另一个服务器,询问时一起提交。GPT给出什么回答,取决于我们提交多长的历史数据,这看起来更像是以前机器学习用贝叶斯概率来给出回答。不过实际上还是挺好用的。平常用得很多。
对方问你觉得那个好用一些?我说openai好用一些。对方问你怎么判断?我说,有时候我有疑问,openai解答得的更准确。我需要他完成一个任务的时候,openai完成的更完善,效果更好。
对方问你只用过这两个吗,还用过其他的吗?你有了解DLLE吗?我说不了解这个。对方说这个也很厉害。
通义最大的问题应该在于要求完成某个功能时输出牛头不对马嘴,而且幻觉严重一点。AIGC确实很厉害,但是从我调用api接口的过程来看,这和我们想象中的人工智能差别有点大啊。估计机器人老婆是没指望了
你的简历里面说了modebus,你简单说一下吧
modbus主要是硬件小组在使用他们采集传感器数据,上传到数据库。我只是因为有相关性,下来了解了一下。modbus主要是分为两个,一个是modbustcp,一个是modbusrtu。modbustcp使用网络来传输。modbus把设备分为主机和从机,主机通过请求码读取从机的数据。除开异常码的话,好像是有8个。然后从机的数据存储分为4个数据栈。分别是线圈、开关、只读寄存器,可读可写寄存器。线圈和开关用一个bit保存数据,寄存器则是16位的。modbus协议报文比较长,最大好像是允许2的32次方个数据存储,每个数据类型都是。但实际上一般都是每个数据类型只有10000个数据存储空间。
这里我不能说答得很好。因为我没在工作中用过modbus协议,所知完全是自学的,记忆不是很牢固。这两个协议我自己都手动实现过,用起来应该不成问题 基于WebSocket的modbus通信合集 。我是否应该去买个单片机实践一下呢?modbustcp还好,可以用网络操纵,但modbusrtu就麻烦了,我的电脑没有串口。
你第一个简历写了winform,里面应该涉及一些硬件、传感器数据采集
实际上硬件数据采集是我们这边的硬件小组做的。winform数据采集软件其实是用来给技术员填报数据使用的。他们填报之后,会通过消息队列把数据上传到数据库。
我感觉这可能是他比较失望的一个点,毕竟我没真正做过硬件数据采集
你最新的那个项目分为前端,后端,实时数据3个端,你主导哪个
我并没有主导哪一个,这都是组长主导。但是我3个端参与都比较多,参与最大的是组长,我算是参与第二多的吧。
不知道他是不是想找一个负责过项目开发的
这个项目你有什么收获
最大的收获应该是实时数据那个程序遇到一个webapi托管服务内存泄漏问题。我写了一个后台托管服务,每秒钟运行一次,从redis取字符串类型的数据,经过计算后,利用滑动窗口进行预警判断。10秒内数据由有5次超过界限值就预警。但是运行之后内存就一直往上涨。我判断是内存泄漏。最开是以为是在while循环内建立了太多对象,因为这没有跳出当前函数,对变量的引用一直存在,对象无法释放。然后我将计算放进一个新的函数,在循环内调用那个函数。这样应该能解决问题。但问题还在。然后我就去找关于GC的资料。然后了解到GC分为0,1和2,供3代托管堆。我以为是对象慢慢从0代提升到2代,在2代堆积。就在每次循环结束手动调用GC。问题确实解决了,但GC会占用5ms左右时间。这总是不太好。实际上这是误打误撞,我的分析不完全对,但真正原因不是这个。
然后我到网上提到这个问题,遇到了一个学习了.net高级调试的人。就转储了一个fullDump文件和pdb文件给他,他分析之后,找到了原因。是固定对象堆没有回收的原因。因为redis那边使用的是字符串存json,所有我只有一次性取出那个键,返回的数据大概90KB,超过了固定85000字节,对象就被分配到了固定对象堆,只有2代GC发生时才会被回收。然后我这个程序基本没有小对象能存活到第二代GC,所以这些大对象一直得不到回收。这不算经典意义上的内存泄漏,但结果还是只能手动调用GC来解决。
他问你是怎么找到的人的呢?我说是在看一线码农的视频,然后刚好遇到相关的事情,就留意上了.net高级调试技术,在网上发了相关博文(实际是上一篇面试里面提到的),然后有人就来问。
他问,所以说这是在项目中令你映像比较深刻的事情吧?我说对。
可能在网上实时交流技术这种事情比较少,可遇不可求?还是他在想公司的技术问题有哪些渠道找人解决?
最后人事问,你现在还在职,假如录取的话,多久能到
不太确定,可能交接1周,回家花三四天看望一下家人就没什么事了。
你还有什么想问的吗
我说目前没什么想问的。
我感觉这个问题很突兀,可能不算什么好消息,就这样回答了。我之后从同学那了解到,对方有意向的话,结尾应该会问期望薪资。所以这是凉了
总结
自己这半年的学习还是有效果的,应该说技术追上来了
这次聚焦于项目和技术经历,所以比较顺畅
按照对方技术和人事私下以及面试的提问来看,他们可能时想找一个没结婚、家庭没多大负担、能够加班、能做项目、能到现场的人。(谁说的.net不加班的?)
我应该专注于简历上已经写明的技术和经历。他们是按照这个提问的。
modbus的问题需要解决一下,最主要是怎么实践。
日志也要研究一下,日志平时用的太少了
要主导项目开发的经历,这点是个问题。没有机会啊
面试提纲、技术总结、项目总结还是要多想多写多读,做到熟悉
简历不能包装,要不然万一跨省工作,试用期的处境就不利了,很难退回来。
之后一周要消化一下这次面试
最后,这次面试我感觉还是展示出了自己的已有的能力,但是倒在了复试。也看到了技术以及项目上缺乏之处,接下来还是要补足这块。听说互联网已经卷成红海了,我在想还要不要找互联网的?或许我现在还并没有多大的选择能力。年龄问题,这次他们似乎就想找没结婚的。所以没结婚工资天然有更低一等的潜力,但是现在社会并不爱婚姻,婚姻也不爱成员,我很迷茫。
追加
我弄错了一个名词。"内存泄漏"那个地方,应该是对象配分配到了大型对象堆,而不是固定对象堆,@successgo指出了这个问题。我到MSDN翻阅了一下,确实是记错了。固定对象堆这个概念也是存在的,不过我没接触过。
如果对象的大小大于或等于 85,000 字节,将被视为大型对象。 此数字根据性能优化确定。 对象分配请求为 85,000 字节或更大时,运行时会将其分配到大型对象堆。