Touka Games Golang 后端实习 一面二面已 OC
- 轮次
- 一面、二面
- 结果
- 已OC
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
一面(约 31 分钟,技术面)
- 你先介绍一下你自己。
- 你第一个高并发秒杀系统就是你自己做的吗?
- 你是部署到哪里跑测试的?
- 压测脚本是用什么做的?
- 你是怎么测的?跑了多少个 Goroutine 同时测?
- 为什么并发两千多的时候,QPS 只有一千多?
- 现在请求某一个商品,它在 Redis 里缓存的数据可能需要刷新,你是怎么做的?
- 并发有很多请求要查询某一个商品,发现 Redis 里没有,你是怎么操作的?
- 100 个请求都要请求这个数据,是去 MySQL 里查 100 次吗?
- 最后 MQ 怎么打给 MySQL?100 个请求同时来了,Redis 里都空了,这 100 条消息都是做同样的事情吗?
- 我现在是去查一个数据、不是往里面插入,你说一下应该怎么操作?
- 你的 Golang 是自己自学的?
- 一个空的 interface 和一个空的 struct 该在什么地方用?
- 说的是空接口,你在什么地方有用?
- 自己尝试封装过 error 吗,就是自己去封装一层错误处理?
- 封装之后,外面拿到这个错误,你怎么判断这是哪个错误?
- 写代码时想判断错误是什么错误,然后可能在服务器这边做不同的处理,你知道该怎么判断吗?
- 你用过 Linux 系统吗?
- 服务部署上去之后,你是直接用 IP 去访问它的服务吗?
- 部署服务都是用 Docker 在上面吗?你写的那些功能都是直接丢到服务器上跑?
- 比如自己生成一个可执行文件,然后上去跑那种,你试过吗?
- 我现在要部署到服务器上,Golang 写的代码要用一个可执行程序部署上去,你跟我说一下该怎么做?
- 现在随便给你一个数,我想求它对 1024 的余数,有什么很快的方法能够算出来?
- 开学是大三了吧?大三就不用上课了吗?
- 你实习是希望以后就留在这里,还是说就想来练手就走?
- 假如你转正了,你期望的薪资大概是多少?
- 你现在开发过程中,对 AI 大概是怎样的使用方式?
- 你做一个项目,AI 做的东西和你自己做了多少,AI 做了多少?
- AI 写的代码你有觉得有什么问题吗?你有看过吗?
二面(约 22 分钟,业务面)
- 咱们先做一下自我介绍。
- 上一轮的面试有没有跟你讲我们做的业务大概是哪块的?
- 你平时对海外的业务有了解吗?
- 你说到了广告,你对广告有了解吗?无论是国内还是海外。
- 后端分为游戏后端、变现侧后端、风控后端等方向,你对这些有了解过吗?或者更想尝试哪个方向?后续的职业规划是什么?
- 你们这个中台,参与的是有几个人呢?
- 你主要负责哪一块?
- 你接手的这期间,这个中台有做一些新的开发吗?还是主要就是做维护?
- 咱们有比如说自己独立地做过一些中台的模块或者是项目吗?不一定是上线的。
- 你能帮忙分为几个模块,简单介绍一下你的这个系统吗?为什么做它、需求怎么来的?实现是你全部参与还是有人一起?你分了哪几个维度去实现它的目标和需求?
- 你用 AI 用得多么?
- 你现在用 AI 的话,你都会用到哪些?就是你在什么时候会用 AI?
- 【场景题】比如我现在需要你帮忙开发一个短剧维护中台,要在这个中台上显示当前所有短剧、所有短剧需要热度排序、可以预览短剧并展示一定的数据、支持上传下载,以及与前端 APP 的一个交互。如果让你做这样的一个后台,你会在哪些阶段用到 AI、怎么用?
《参考解析》
秒杀系统的压测与缓存击穿:QPS 只有一千多,通常不是「并发上不去」,而是瓶颈在别处:压测客户端自己先到极限(Goroutine 数不等于有效并发连接,压测机和被测服务抢同一台机器的 CPU 与网卡)、HTTP 连接没有复用导致握手开销占满、日志和 JSON 序列化这类同步开销、全局锁竞争、以及 Redis 单线程命令排队。排查顺序是先看压测机与被测机的 CPU/网卡/连接数,再用 pprof 看火焰图,最后才怀疑业务逻辑。缓存刷新有两条路:一是写 DB 后主动更新缓存(简单但并发下可能写入乱序),二是删缓存让读请求回源(更常用),配合逻辑过期避免热点 key 同时回源。缓存击穿(key 不存在或刚过期、100 个请求全部打到 MySQL)的正解是「只放一个请求过去」:用 Redis SETNX 加锁让单个请求重建、其余短暂自旋或返回旧值;或者逻辑过期 + 异步刷新,读请求先返回旧值;再用布隆过滤器拦住数据库里根本不存在的 key。100 条消息打给 MySQL 也不该是 100 次写:把请求合并成一条重建任务,消息带唯一业务键做幂等消费,消费端只让第一个成功、其余丢弃。
Go 空接口与空结构体:interface{}(Go 1.18 后可以写 any)用来承载任意类型,常见于 JSON 编解码的中间结构、日志字段、容器类库和反射场景;它的代价是装箱与类型断言的开销,能用泛型或具体类型就别用它。struct{} 是零大小类型,不占内存,典型用法是 map[string]struct{} 做集合(value 不占空间)、chan struct{} 做信号通知(只关心事件不关心数据)、以及没有状态的方法接收者。两者的区别是:空接口表达「什么类型都可能」,空结构体表达「没有数据」,面试时把使用场景和代价一起说清就够了。
error 封装与判断:封装用 fmt.Errorf("查询订单失败: %w", err),%w 保留错误链。上层判断不要比字符串,用 errors.Is(err, ErrNotFound) 判断是不是某个哨兵错误,用 errors.As(err, &target) 提取具体错误类型再读它的字段(比如 code、httpStatus)。自定义错误实现 Error() string 接口,需要携带上下文就定义结构体错误类型,并在跨层传递时始终用 %w 包一层而不是新建一个错误,否则错误链就断了。业务码不要塞进错误字符串里靠前缀匹配,那是典型的事故来源。
部署与交付:本地 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o app 交叉编译出静态可执行文件,scp 或发布系统推送到服务器,用 systemd 托管(Restart=always、限定运行用户、日志交给 journald),前面挂 Nginx 做反向代理与 TLS 终结,配域名而不是裸 IP 加端口。更规范的做法是多阶段 Docker 构建(构建阶段带 Go 工具链,运行阶段只留二进制和时区文件),配健康检查、优雅退出(监听 SIGTERM 后停收新请求并等待在途请求结束)、灰度与回滚。别用 root 直接 nohup ./app & 这种跑法。
位运算求 1024 的余数:1024 是 2 的 10 次方,对非负整数而言 x % 1024 完全等价于 x & 1023,位与比取模快,也是面试官想听的点。负数要先取绝对值或用补码语义处理,Go/Java 里负数取模结果符号跟被除数走,直接位与会得到不同的值。推广一下:任何 % 2^k 都能转成与 2^k - 1 的位与,反过来「判断能否被 2 的幂整除」也是同理。编译器对常量 2 的幂本来就会做这个优化,但面试里能主动指出来是加分项。
短剧维护中台的 AI 使用场景:分阶段说更清楚。需求阶段用 AI 把一句话需求拆成用户故事和字段清单(短剧名、封面、集数、状态、热度分、上传人),自己再核对业务口径;设计阶段用 AI 出表结构草稿、接口契约草稿和状态机图,热度排序的算分口径必须自己定(播放量、完播率、时间衰减怎么加权);编码阶段用 AI 生成 CRUD、分页、热度排序的样板代码,上传下载改成对象存储的预签名 URL,AI 辅助写转码与截图预览的调用;测试阶段用 AI 造 Mock 数据和边界用例(超大文件、断点续传、并发上传同名文件);上线后用 AI 读慢查询日志提优化建议。要明确说出 AI 不负责的部分:权限模型、与 APP 的接口契约、存储与转码选型、以及任何涉及数据口径的决定,这些都是人来拍板。反问环节可以问业务方向、团队是传统编程还是 AI coding 为主、公司是否提供 token、以及前三个月对新人的预期,这些问题能显示你在认真评估匹配度。