Back End Daily Internship First Round Experience

·interview-experiences
#xiaoetong

小鹅通-后端开发日常实习一面面经

问题

Q:你先做个自我介绍吧

A:好的,面试官您好,我是来自深圳大学 27 届的某某,我目前是大二在读,然后我是在一家主营业务是海外网文平台的公司做后端开发岗位的实习生,我主要是负责公司的几个代码仓的维护和开发一些新接口

然后学校方面的话,我大一是参加了一个创赛相关的社团,大二目前是在华为智能基座的一个软开部(这里我提社团是因为四月初社团有个小鹅通的绿色通道但我错过了哈哈哈,我是在 boss 上随手投的),大概情况就是这样,我目前也有一个游戏项目在自己写,所以说这次简历上面写的也是它的一个后端服务器的项目

然后我个人的技术栈的话我一开始是学 C++ 出身,然后后面开始学 go,然后由于实习的这家公司他们主要是在用 php 在写他们的业务项目,所以 php 我也有一些了解,然后其他非后端的像前端方面也有一点点了解吧,大概就是这样,谢谢

Q:嗯,我看你现在是也是还在实习吗?

A:嗯对

Q:诶为什么我看你这个二月份开始实习也没多久,为什么要换一份实习?

A:额主要是因为那个公司现在写的是 php 嘛,然后我个人还是比较想写 go 和 C++ 这方面的,然后因为后端主要是偏 go 的多一些嘛,所以说我现在还是更想写 go 一些,因为 php 它本身我也不是很熟悉嘛,然后它的一些框架呀然后比如说基本的代码语法,或者说它的一些配套的后端的工具什么的,我个人就是实习两个月下来感觉还是没有 go 来的方便和高效一些,然后我个人后面也不太想往 php 这个方向发展,所以说想要换一下然后看到咱们这个小鹅通主要是用 go 的嘛还是

Q:啊对,主要还是用 go,历史有一些项目是 php,但主要的项目都是用 go,而且 php 的也要同步到 go;好,你是什么时候开始接触 go 的?

A:嗯是从去年的十一月十二月吧差不多,那个时候是我刚把 C++ 的几个,额也是一个那种类似于 http 框架的项目搞完之后然后就开始接触 go 了,然后开始写 go 的一些项目

Q:然后你刚刚说 go 和 php 都有一些接触,像 php 他是单线程的,然后 go 它是可以多线程和多协程的,就是协程、线程和进程它们之间有什么区别?

A:嗯进程是操作系统它分配资源的最小单位嘛,然后每个进程之间它会有独立的全局变量、堆空间栈空间这种,然后每个进程有自己的寄存器,线程呢就是进程往下细分的一个单位吧,多个线程在进程之间是共享进程的内存空间以及全局变量,但是各个线程之间它又有各自的寄存器和栈空间,然后协程的话其实就是线程再往下细分,因为 go 嘛 go 他的协程相对其他的协程来说会更加自动化一些嘛,它主要是用 goroutine 然后相当于会用 go 的运行时来减少平时操作线程切换上下文的一些开销,然后达到更好应对高并发的目的;然后其实像 php 它也有一些框架是可以用多进程多线程这种

Q:像 php 也有协程这个概念,有了解吗?

A:目前我主要就是公司有一个 IM 的项目,是用那个国产的一个叫 gateway-worker 的一个框架,然后它这个框架就相比于像传统的 laravel 还有 workerman,它是更加面向 websocket 和长连接、即时通讯的,它里面就是有一些针对高并发然后来做一些协程

Q:那像除了 go 和 php,像 C 语言也是有去接触过的对吧?

A:嗯我对 C 语言接触的不算多,我主要是学 C++ 的,C++ 它也有协程,主要是在标准库里的

Q:那关于内存管理,比如说像 go 和 php 这种面向对象的高级语言,基本上内存你都不需要自己去申请,然后对应它会有垃圾回收,那为什么它不需要自己去申请内存,它是怎么做到的,以及它的垃圾回收是怎么结合的,可以用 go 来说

A:go 主要就是用 GC 嘛,然后它自己是有一套内存回收的管理机制的,比如说它,比如最主要就是 GC,然后它会有一个三色的抽象,就是黑白灰,比如说我一个程序开始运行的时候,在运行时 GC 就会去走一个最基本的一个检索,然后会去标记我这个程序里面不同变量的生命周期,在程序运行完之后 GC 会做第二遍扫描,这个扫描的目的主要是为了检查前一次扫描有没有漏的并实际去操作和回收这些生命周期到了的变量

然后它主要是通过黑白灰三个颜色来标记生命周期,像白色的话可能就是我还完全没有标记它,灰色的话是我已经标记了,可能我还没有回收,可能还要过一会才能回收,黑色的话可能就是我已经标记了而且我已经回收完了,主要是通过这种抽象的层次以及配合上它本身比较强大的运行时,这两个做一个结合实现了它一个程序运行时 GC 能够并发地去进行垃圾回收,所以说这种高度抽象的层次可以就是比较方便,可以不用让我们程序员就是像手动地像 C++ 那样去管理某个内存某个变量的回收之类的

感觉自己这里在瞎扯

Q:那其实你刚刚主要是介绍了一下它的垃圾回收,我刚刚前面的问题其实其中一问就是为什么不需要自己的去申请它的内存,它是怎么来结合这个垃圾回收的,因为是应该先有前面的才会有这个垃圾回收嘛,所以前面它是怎么做的,这部分能再补充一下吗?

A:就是比方说我创建了一个变量,我并不需要像 C++ 那样像我在创建变量时就去考虑这个变量可能需要占用多少内存空间,或者是有没有堆栈溢出的风险面经相当于 go 语言它本身,如果拿协程来说,一个 goroutine 本身开销就是非常小的,所以即使我写一个程序,我也不需要特别纠结某一个变量它,不管我用的是 new 还是 make,会不会影响到我目前的栈或者堆,而且它本身对栈的管理也是非常高效的,所以它才配合这个 GC 回收一起来实现这样一个高效自动的内存管理机制

还在瞎扯,主要是内存管理这一块我的了解太浅了,没有深入去看底层实现机制

Q:所以垃圾回收主要回收的是堆的还是栈的?

A:都有吧,像 C++ 里面可能是要自己来回收堆嘛,然后栈由操作系统来回收,但是像 go 里面 GC 其实栈和堆它都是不需要程序员自己手动去操作的就是(被打断)

Q:我就是说 GC 部分就是垃圾回收部分主要回收的是堆还是栈,(再次打断)包括你刚刚的说的三色标记法,它标记的是全局对象还是调用栈

A:这个我有点不太确定,但我推测标记的应该是堆里面的,因为它更多的是不用操作系统去做一个系统级的回收,然后以此来减少开销的

Q:那像 go 里面协程间通信或者数据交互的话我们一般用些什么结构?

A:go 里面主要是用 channel 来实现多个 goroutine 之间的一个通信和同步,然后 channel 又分为有缓存和无缓存,就会看实际业务需求来选用,反正我个人开发的话(被打断)

Q:用 map 可以吗?

A:嗯 map 我没有用过,这个我不太确定,应该不行吧,我感觉更多还是用 channel 一些

Q:噢就是没用过所以也不太了解,是吧

感觉他是理解成我不知道 map 是什么了

A:嗯因为早期 go 里面的 map 它不能保证线程安全嘛,现在的 go 里面如果想要保证高并发安全的话就要用那个标准库里面的那个 sync嘛,或者是自己用锁去写一套来保证线程安全,所以感觉还是用 channel 更方便一些

Q:嗯用 channel 更方便,但 map 也能用,主要解决你的并发安全,得加锁,对吧?

A:(我一直点头)

这里面试官对我简历上的项目表示了困惑,因为我写的开发时间跟实习时间是一样的,他以为是游戏公司的项目,我澄清是我自己独立开发的之后就开始围绕项目问了

Q:你的项目应该有对应的游戏端或者说客户端吧?

A:有的,客户端的话我目前主要是用前端的一套框架在写,也有在考虑要不要用虚幻五,主要是虚幻五(学习)成本比较高嘛,所以我目前是在边学边写这种状况下

Q:你这里主要和客户端交互是用 websocket 来做的是吗?

A:对的,主要是用 websocket 来实现状态同步,然后主要是用服务器来实现端到端的逻辑运算,然后再发到端,端只要负责渲染就可以了

Q:你这个游戏是个什么类型的游戏?

A:是个卡牌游戏,是我自己独立设计的

Q:你刚刚说的 websocket 是状态同步,那你这里面涉及哪些协议,会有哪些交互逻辑?详细介绍一下你这个项目

A:我这个项目主要是一个卡牌游戏,用户进来会先注册然后登录,然后创建房间,之后匹配,进入到游戏界面之后会有抽牌打牌然后以及分数计算等逻辑,这个服务器主要是用 websocket 来保证各个客户端进入房间之后它的状态是一样的,它能够拿到,比如说对局开始之后,各个客户端都能够获得到这个对局中用户的信息以及其他玩家的信息,主要是用 websocket 然后写了一套 protobuf 来实现这个长连接,websocket 它本身就是这个 http 升级而来的嘛

另外的话注册和登录方面的身份认证主要是用 JWT 来实现的,具体的话就是用户进来之后先注册,注册成功之后会要求用户先登录,如果登录成功,用户密码跟数据库里的密码哈希是一致的话,服务端就会返回一个身份令牌给客户端,客户端在后续的请求中就会附上这个身份令牌,服务器端有一个这种中间件来拦截对于这种有需要认证接口的访问,然后如果说这个身份令牌它上面的信息是一致的话呢就可以实现这个接口的请求

然后服务器还有一个最主要的就是实现刚刚所说的这个分数的计算,因为一些游戏机制它会有这种比如说相对复杂一些的分数计算,或者说这种路由方面的,因为我这个游戏,我要把一张牌放到一张地图上面,地图上有很多格子,我要把牌放到格子上面不同的位置,然后其他玩家也会把牌放到不同的位置,那地图上面这个格子的坐标信息以及牌与牌之间作用得到的分数信息,这个逻辑计算都是由服务端来进行的,然后服务端这边计算完之后还是用 websocket 来返回,当然还是要先压入消息队列里面,然后尽量避免高并发的时候那种压力过大嘛,然后再逐步返回给客户端,然后让客户端实时渲染,服务器端主要就是这几个功能

Q:那像你这种卡牌游戏每个玩家应该是轮流行动的对吧(我表示是的,每个玩家有各自的回合),那你的回合有倒计时这种概念吗,没有操作时间的限制吗?

A:多人联机版本的话是有,但目前不会太强制因为我不太想让玩家有这方面的压力,因为可能有些游戏机制还是比较复杂,我怕加上这个之后会影响玩家的游玩体验

Q:那如果一个玩家因为某些原因一直没有执行某个动作,那不是所有人都晾在那了吗?

A:嗯其实有一个检测机制,就是 websocket 的心跳检测,就是如果看他长时间都没有操作,其实也算是定时,就是发一个请求看他到底是在线还是不在线还是断连了或者单纯没有操作这种的

Q:你刚刚说的是检测客户端的活跃状态,那如果是要增加这种定时机制,比如每个玩家的回合限制为一分钟,你会怎么做?

A:如果要我加的话我应该会用 redis,因为它有一个 stream 和 pub/sub 机制,我可以以刚才的那个检测状态出发,比如拿一分钟为例,我在 55 秒的时候可以发一个状态检测,如果他没有任何操作也没有回应的话,redis 会先获取玩家目前状态的一个快照,然后在服务器端比较之后,就相当于 5 秒内我可以一直请求玩家目前的状态,如果他还是一直没有打牌的话服务器端可以强制更新这个玩家的状态,再下发给每个客户端,来实现计时然后强制结束的效果

答得巨混乱,但面试官还是点头了

Q:你这个游戏同一时间应该只有一个玩家能操作对吧,那你是怎么实现其他玩家不能操作的?

A:这个我主要是前端方面做的限制,我没有考虑鉴权那一套,就比如刚刚那个检测,如果我检测他的状态在某个时间内没有变动,那我就指定某个玩家他的下一个状态为可出牌,然后再由前端去做对应的 UI,就相当于比如当前一个玩家能出牌,那其他玩家那里是没有能够交互的机制的,就比如拖不动牌那种

Q:我明白你这种机制主要是前端来做约束,那如果别人通过抓包知道了你整个的通信协议,比如现在应该是 A 在出牌,那 B 如果通过比如重新发包或劫持数据,然后修改之后直接向你的服务端,也是通过 websocket 来告诉服务器我要执行一个动作,那不就相当于两个人在同时操作吗?甚至可能是网络问题前面那个人的操作卡住了,然后到了下一步另一个用户又直接去操作了,那这种竞争冲突你该如何解决?

A:嗯这种我觉得主要还是服务器端那边要去处理,如果是说恶意伪造的话那可以考虑加密协议,比如走 https,因为我目前本来也是网页端,我加密的话他抓包,反正我是觉得现代的公钥私钥一套加密算法下来我觉得还是挺安全的

然后如果是玩家的网络问题的话,我觉得是涉及到玩家的断线重连机制,就可以用我刚刚说的检测机制,就是心跳,我可以看他在某个时间段内一直没有操作的话,我先看一下他目前的状态,然后服务器端约束,等他网络恢复过来肯定会有一个重连的过程嘛,那他重连的时候就由服务器端给他下发一个新的状态他来接收,而不会继承他在网络断掉之前的状态

Q:你刚刚说的用户操作限制一直都是基于对端的,那你的服务端能不能做互斥?

我其实没太明白具体他想问啥,但想到啥就说啥了

A:服务器方面做互斥的话就要考虑鉴权方面的吧,就是我多加一个用户状态,也是限定在某个时间内,如果你出牌我就先升级你的权限,如果你不能出牌的话我就自动降级你的权限

Q:嗯,最简单的是不是可以用一个 key,这个 key 里面存的是谁,谁就能出牌,然后过期自动清掉,清掉之后如果 key 不存在,那就是谁先来谁先出牌,这样你就保证比如说五分钟有效期,那五分钟内谁都不能更新它,只有他能出牌,别人来了判断不是他就不能出牌,而且基于 redis 的话他的整个效率也会比较快,并发能力也比较好

A:嗯这个确实比较方便一些,但我还是更偏向于状态同步一些,您说的可能还是更偏向于本地的帧同步一些

Q:啊我刚刚只是说一个最简单的,它再往上也可以扩展,解决办法有很多;你项目里说你有用到 MySQL,那 MySQL有哪些索引类型?

A:MySQL 索引类型主要分为最基础的主键索引,比较常用的 B+ 树索引,然后全文索引,还有那种比较普通的,或者我想效率高一些的覆盖索引,以及如果我想要按照地理去区分好像还有一个什么 geo 索引,大概最主要用的应该就是这几种,或者是聚簇索引和联合索引,我把多个字段组合在一起方便检索这种

Q:刚才你说的这几种索引类型比较混乱,B+ 树索引是存储索引最底层的数据类型,聚簇和非聚簇是再中间一层,再就是给用户用的主键什么的,你再重新组织一下重新说一下

A:好,存储来说的话最常用的就是 B+ 树索引,再就是全文索引,我去索引库里面目前存储的,就相当于有点全表扫描的感觉,用户端方面的话就是主键索引和联合索引,或者是聚簇索引和覆盖索引,不过覆盖索引也是为了能覆盖表里的数据,有点偏存储那方面的感觉,然后还有一个分类我一时半会想不太起来,对

Q:聚簇索引对用户来说应该接触不到,你设置的时候应该只有单列和组合这些,你也没办法定义它是聚簇还是非聚簇;k8s 容器有去接触过吗?

A:有稍微了解过一点,但还没有了解过它底层的一些东西

Q:自己也还没搭过是吗?

A:嗯,对,主要是我是想先把 docker 用熟练然后再接上 k8s 一起用

Q:那 docker 自己有去跑吗?就它怎么工作的这些

刚说完 docker 就后悔了,真是自己给自己挖坑

A:docker 我目前也只是把它在服务器上面跑起来了,然后也没有像 MySQL 这种去看过它背后的实现什么的

Q:那你业余时间除了像你说的做这个游戏的后端项目,还会做些什么?

A:目前我最主要是在看各种我不了解的技术的官方社区的那种文档,因为我目前自己的学习模式是以兴趣和需求为导向的,就是比如说我的项目想解决某一个问题,或者我对于某一个方向某个细分领域感兴趣,我就会先去看它这方面的产品,然后我自己去用一下,然后我再去看它背后具体官方文档的实现,然后进一步我才会去深挖,目前除了做项目的话就是在学一些新技术,比如刚刚说的 docker 和 k8s,以及我自己也会去学虚幻五这种,因为我感觉我对各个领域其实都稍微有一些兴趣,虽然我目前主要还是针对后端在去学习的

Q:那你对你后面的技术方展规划和职业发展规划有什么想法吗?

A:我目前想的还是以后端为主,其实这个事情我之前纠结过挺长一段时间的(最近也在纠结哈哈),因为目前中国的游戏市场来说,做游戏开发方向竞争还是比较残酷的,然后风险也比较高,所以我目前还是比较想先把后端这一块(学好),因为游戏也有很多方面会涉及到后端嘛,所以说我目前想法是先把后端这一块搞的相对精通一些,不要到时候就是什么都会一点但都不深的情况,然后后端发展起来之后,比如可能五年十年以后,如果有好的机会的话我会再去考虑往游戏方向发展

下面是反问环节

Q:我这边都问完了,看你这边有什么想了解的

A:我想问一下咱们项目目前主要用到的技术栈有哪些,就是我现在在面的这个部门

Q:我们技术栈刚刚前面说了主要是 golang,然后会有少量的历史业务用的是 php,但那部分也会迁到 go,然后我们主要是后端,前端会有专门的前端

A:那我们部门现在主营的业务是哪方向的大概?

Q:小鹅通官网有上去看过吗?

A:我有上去看过,但上面业务方向好像还是比较广的,好像主要是 to C 的?好像主要是做服务的是不是

Q:我们主要是做 to B 的,就是类似于淘宝这种,我们是 SaaS(Platform as a Service,平台即服务)平台,比如商家你要卖货,博主要卖知识付费课程,你可以在我们平台上面买个店铺,然后卖这些商品,包括你可以开直播,做你的营销活动去引流,业务上叫 B to C,技术上其实就是个 SaaS 平台,我们做的是淘宝一样的东西,我们做的就是迭代这个平台,但我们更多的是客户与客户之间的隔离,然后这是整个公司的业务,公司往下就到部门,我们部门是技术安全组,是属于技术平台中心,属于整个公司的基础架构的位置,就是给上游的业务需求提供各种功能,比如审核、检测识别,然后就是一些数据安全的业务,比如识别敏感数据然后交易上的安全等(还有一些业务我不太感兴趣懒得打了👉👈)

A:那如果我有幸能入职的话,就以我目前水平来说,您觉得我还需要去学哪些技术比较好呢?

Q:因为我们主要是用 go、MySQL 和 redis,还有就是刚刚说的容器,因为目前大部分公司都是基于容器上去运行的,开发的代码不只是开发完了,包括怎么运行怎么给用户,就相当于做完了还要交付提供服务,这个是一个比较重要的一个事情,可能运维团队会去搭建技术平台和 QAS(Quality Assurance System,质量保证系统,主要用于集成测试),但我们也要知道它是怎么来的,如果真的出问题要去怎么优化,不单单是运维团队的事情

反思总结

这是我在三月份改完简历之后第一次遇到这种强度这么大的后端面试,之前面的都是小厂(虽然小鹅通也只是中厂而已哈哈哈)然后也没什么压力,也不会有这种这么深的拷打项目,刚面完的时候只感觉特别疲惫啥都不想干😢

整体下来感觉自己还是有点半吊子,我是 4.18 下午五点在工位上收到的面试邀请,然后 4.21 下午五点进行的一面,周末一直在突击看各种八股(因为我之前没怎么看过 go 的八股,其他也只是看完了还没有自己总结)也没有休息,面了四十多分钟吧,然后大概在六点多 hr 给我打电话约的二面(二面挂了😭😭)

结合我自己这几天高强度看的面经和面试经历来说,小鹅通就是那种如果你有戏基本上流程推进会非常快,也就是说如果面试完当天还没有推下一步那就很可能是凉了

我是在 4.23 上午十点面的二面,然后 4.24 上午又在教室上课呢收到了下午五点腾讯光子的面试邀请(还是游戏客户端开发,之前有发过天美的一面凉经),相当于四天三场高强度面试,中间还是一直在突击准备各种看八股和面经,也算是提前感受到找暑期实习的强度了😓

小鹅二面和光子一面的凉经都会发,只是这个整理面经的过程确实有点痛苦,因为我是把我的回答也打出来的,我是觉得这样也方便我自己复盘所以才这样,写完这篇也感觉自己对于八股的熟练度以及一些表达能力还是需要进一步提升,虽然面对一些不知道什么回答的问题我也能扯出不少东西来哈哈哈哈哈

反正这三场面下来之后我是准备先好好沉淀一下了,感觉这种高强度面试最大的作用其实就是能帮助你或者是逼迫你对你自己的知识体系进行一个多角度的梳理,包括拷打项目或者实习经历都能让你清晰地看到自己哪里不足,虽然道理是这样但我收到这俩又都凉了的消息的时候还是有一点点沮丧的,因为我是真的不太喜欢我自己目前实习的这家小厂,不喜欢 php 也不喜欢三个在工位上抽电子烟的同事(公司一共才八九个人)

所以大概就是这样啦!我预计在五月底辞职(这样刚好实习了三个月),准备这两天就跟我 mentor 提了,我本身的规划也是三四月改简历,然后四月到六月骑驴找马,六月准备七月的期末考试,目前来看当务之急还是先把八股的知识体系自己重新搭建好,不要每次在面试前都是特别高强度突击准备,然后算法题一定要继续好好刷一下

继续加油~

(btw,小鹅通给我唯一的好感就是它没有算法题🥲)