简历针对训练

问题 1:你在“霓裳云枢”项目中提到的“动态版本号”缓存一致性策略是如何实现的?为何不使用如 Spring Cache 的内置机制?

考察点:系统设计能力、缓存一致性思维、自研能力 vs 框架使用的权衡。

面试官您好,关于“动态版本号”缓存一致性策略这个问题,我的设计思路是基于版本号机制,同时借鉴了动态规划中“滚动数组”的思维,在不改动数据库表结构的前提下,实现了一种比较灵活的缓存一致性方案。

具体实现上,我没有像传统做法那样在数据库中添加版本号字段,而是把版本号也放在 Redis 中管理。每次有增删改操作时,就让 Redis 中的版本号加一;查询时我们会带上这个版本号,判断缓存中的数据是否仍然有效。

为了优化性能,我让版本号的失效时间比数据更短。这样如果数据长期不变,缓存命中率就高;一旦频繁变动,版本号会自动更新,保证缓存命中的是最新数据。这相当于用“几块轮流空间”维护状态,避免频繁读库。

之所以没有采用 Spring Cache 的内置机制,是因为它在处理这种“缓存与数据库强一致性”方面比较受限。一方面它缺少灵活的版本控制机制,另一方面对多级缓存和分布式场景的支持也不够完善。而我这个策略虽然简单,但更适合中小型项目的实际场景,比如访问量适中、可接受一定程度缓存延迟的情况。

当然,对于更复杂或者并发量更高的系统,我会考虑使用 Canal 监听数据库的 binlog,结合 MQ 或直接刷新缓存来实现更高强度的一致性保障。

问题 2:请你简单说一下你在“King of Bot”游戏中使用 WebSocket 实现双人匹配通信的架构设计。如何确保通信实时性与安全性?

考察点:网络编程、实时系统开发、服务解耦与安全控制。

面试官您好,关于“King of Bot”这款双人实时对战游戏中的通信架构,我主要是基于 Spring Boot 集成 WebSocket 实现的。在整体架构上,我把通信部分做了独立模块封装,客户端建立连接后,会进入一个匹配池,由后端匹配服务来进行调度。匹配成功后,再由服务端创建一个对局房间,并维护每位玩家对应的唯一连接 ID。

为了保障通信的实时性,我主要做了两点优化:一是使用了异步线程池,避免阻塞影响其他连接;二是通过消息队列来缓冲一些突发请求,提高系统的响应能力和稳定性。

在安全性方面,我主要从三个层面考虑:

  1. 登录鉴权层面,采用 Spring Security 配合 JWT 实现用户身份校验,确保每次通信都有权限验证;

  2. 代码执行层面,因为这个游戏支持用户上传 Bot 脚本自动操控贪吃蛇,所以我引入了沙箱机制来运行这些脚本,防止恶意代码影响主服务;

  3. 对战公平性:这里我把所有的游戏逻辑判断都放在后端来执行,比如蛇的移动是否合法、是否发生碰撞等行为,全部由后端裁定。地图的生成也是由服务端统一调度,再发放给客户端,并通过中心对称设计和洪水填充算法确保地图连通性与公平性。

    这里我也有考虑到游戏类型对逻辑放置的影响:像 FPS 这种对响应速度极为敏感的游戏,为了降低延迟,通常会把部分操作判断放在前端执行,并通过后端进行后续修正。但“King of Bot”属于策略类回合制游戏,对操作实时性要求没那么高,因此完全可以把行为判断放在服务端执行,以最大程度保证游戏公平性、防止作弊。

整体来说,在保证实时性的同时,我也尽可能从多维度加强了系统的安全性和公平性。

问题 3:你提到熟悉 MySQL 索引优化与事务机制,能否举例说明一次你对慢 SQL 进行优化的过程?

**考察点:**数据库调优实战、SQL 执行计划分析能力。

面试官您好,我确实在项目中遇到过一些 SQL 性能问题,也做过一些实际优化工作。比如在“霓裳云枢”项目中,有一个服饰展览的接口,需要支持按关键词模糊搜索和游标分页加载。随着数据量增长,查询响应时间开始变慢,特别是页码越往后,性能问题越明显。

我当时先通过 EXPLAIN 查看执行计划,发现主要性能瓶颈是出在 LIKE '%关键词%' 的模糊搜索上,这种写法前面有通配符,导致 MySQL 无法使用索引,执行的是全表扫描。

当时查找过几种搜索方式的优化方案。最后结合实际业务需求,选择将模糊搜索调整为 LIKE '关键词%' 的前缀匹配方式,这样就可以命中前缀索引,性能有明显提升。这个调整对业务没有影响,因为用户在搜索时大多是从关键词头部开始输入,比如“云肩”“明制”等。

当然,我们也评估了全文索引(FULLTEXT)和接入 Elasticsearch 的方案,它们在数据量更大或需要分词、相关性排序等复杂搜索功能时效果更好。但因为当时项目还处于早期阶段,数据量还不算大,我们更倾向于选一个技术成本低、维护简单的方案。LIKE

  • 前缀索引在性能和复杂度之间做到了一个比较好的平衡。

在此基础上,我们还对分页查询做了优化。原本是使用 LIMIT offset, size 的方式,这种在页码大时性能下降明显。我改为使用游标分页,每次请求带上上一页最后一条数据的主键 ID,这样能避免大 offset 带来的性能问题。虽然底层仍是 LIMIT,但结合条件过滤可以更快定位记录。

最后我们也对查询字段和排序字段重新设计了联合索引,确保索引命中率,并对部分高频搜索结果做了 Redis 缓存。优化完成后,接口的平均响应时间从七八百毫秒降到了两百毫秒以内,用户体验明显提升。