美图后端开发一面面经
《面试题目》
八股
- Java HashMap 的 put 流程
- synchronized 与自旋锁的区别
- 一个线程等待多个线程完成,用什么来实现?
- 数据库为什么索引能提高检索速度
- 联合索引失效场景,为什么失效
- Redis 缓存击穿、穿透、雪崩问题,如何解决
项目1(Agent对话)
- Agent 对话链路的设计
- 结构化记忆和长期记忆的内容上的区别
- 模型幻觉或健康风险的规避措施
- 数据来源,如何入库和召回
- 评测数据集怎么构造的,答案打分怎么设计
项目2(图片上传)
- 图片上传流程
- 如何保证上传链路中的文件完整性,确保用户上传的图片和 OSS 中最终存储的图片内容一致?
- 如何保证其他用户无法通过破解接口获取别人空间的数据?如何避免越权访问?
- 双重缓存,如何保证数据一致性?
《参考解析》
- HashMap put 流程:先对 key 计算 hashCode 并做扰动处理,再与
(容量-1)按位与得到桶下标;若该桶为空则直接放入新节点;若已有节点则比较 key 是否相同(hashCode相同且equals相同)决定覆盖 value 还是插入链表/红黑树;插入后检查链表长度是否达到树化阈值(8)及数组容量是否达到 64,最后判断元素总数是否超过扩容阈值(容量×负载因子),超过则触发扩容。 - synchronized vs 自旋锁:自旋锁是一种锁的实现思路——线程获取锁失败时不立即阻塞挂起,而是循环(自旋)不断重试,避免线程切换的开销,适合锁持有时间很短的场景;synchronized 在 JDK6 之后引入了锁升级机制(偏向锁→轻量级锁→重量级锁),其中轻量级锁阶段本质上就采用了自旋+CAS的方式尝试获取锁,只有自旋一定次数仍失败才会膨胀为重量级锁(真正调用操作系统级别的互斥量,线程被挂起)。
- 文件完整性校验:上传时对文件内容计算哈希值(如 MD5/SHA256)并随请求一起提交,服务端接收后重新计算文件哈希并与客户端提交的值比对,或者利用 OSS 提供的
Content-MD5请求头校验机制,由对象存储服务在写入时自动校验完整性,避免网络传输过程中数据损坏或被篡改。 - 越权访问防护:核心是”鉴权到资源维度”而非仅”鉴权到接口维度”——每次访问具体资源(如某张图片、某个空间)时,都要校验当前登录用户是否对该资源 ID 拥有权限(而不能仅凭接口本身的登录态校验就放行),常见做法是在资源归属字段(ownerId)与当前登录用户做比对,或引入统一的权限中间件按资源类型+操作类型做集中校验。