面灵AI→

某金融小厂 Java 一面:性能瓶颈、实时行情与降级的边界

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 在达到性能瓶颈之后,怎么进一步优化效率?
  2. 追问:实际场景需要一直重复获取实时数据,你消息队列做不到,这要怎么实现?
  3. 追问:你限流了,那如果我刚好喜欢冷门股怎么办?数据精度降级,那我刚好要用这个数据呢?
  4. 你说有解析式,那为什么要让用户写公式,直接让用户输入 Python 代码不是更好?你这个比现有代码好用在哪?
  5. 你支持哪些数据?如果我要精确使用旧的某时某刻的 MA 参数作为输入,你要怎么办?
  6. 你在测试直播功能的时候,怎么确定是直播延迟还是播放器延迟?
  7. 你在多个设备上测试过吗?
  8. 反问环节。

《参考解析》

性能瓶颈之后怎么继续优化:先承认一个前提——优化必须可度量,没有 profile 就没有方向。定位手段按层来:应用层用火焰图看 CPU 热点、用 async-profiler 看锁和分配、看 GC 日志确认是不是停顿主导;存储层看慢查询日志、执行计划、索引命中;链路层看 P99 延迟分解,确认时间花在计算、序列化还是网络。优化顺序也讲清:先砍掉不必要的调用和重复计算(缓存、批量、合并请求),再减少数据搬运(少序列化、按需取字段、压缩),然后才是并行化与异步化,最后才是加机器和分片。金融场景还有一个特殊约束:正确性与可审计性优先于吞吐,不能为了快牺牲可复现。

实时数据为什么消息队列不够:MQ 是「推」+ 异步,适合解耦和削峰,但对「每个客户端都要最新的某只股票某一秒的价格」这种订阅式实时场景不合适:消息堆积会带来延迟、客户端重连后要补历史、不同标的更新频率差异极大。更合适的形态是推拉结合:服务端维护一份最新快照(内存 + Redis),客户端订阅增量(WebSocket 长连接只推变化),冷数据按需拉取;再加一层聚合——把同一标的的高频更新在服务端合并成固定频率(比如 200ms 一次)再下发,客户端看到的还是流畅的行情,但压力降一个量级。

限流与降级的公平性:限流不能无差别,否则冷门标的的用户和热门标的的用户承受同样的后果。可用的做法是按订阅关系分配配额而不是按连接,热门标的分到更高频的推送通道,冷门标的走低频轮询;精度降级要有显式契约——接口返回里带上精度/时效标记,前端展示「延迟数据」而不是假装是实时的,用户能自己判断能不能用在这个决策上。这题考察的是「你有没有想过降级对业务语义的破坏」,只答技术手段不够。

公式 DSL 与直接跑用户代码:两者是安全性、表达力、性能的三角取舍。允许用户写 Python 等于把执行环境交出去:沙箱逃逸、死循环、内存爆炸、任意 IO,任何一个都是生产事故;而且用户代码不可静态分析,没法做依赖检测和增量重算。公式 DSL 的代价是表达力受限,但换来可解析、可校验、可缓存、可并行、可精确回答「这个指标依赖哪些数据」。真要做扩展性,路线是「受限表达式 + 白名单函数 + 有向无环的指标依赖图」,而不是开放任意代码。面试官追问「好在哪」时要能给出量化对比:编译一次多次执行、可以预计算中间结果、能定位到具体哪个参数变了。

历史时点的指标怎么算:这是时序正确性问题(point-in-time correctness)。要做三件事:数据带版本或有效期(bi-temporal 建模:业务时间 + 记录时间),查询接口必须接受 as_of 参数,缓存与预聚合要按时间分片存而不是只存最新值。做不到的话,回测和实盘会用两套数据,结论不可信。答这题能提到「避免未来函数/前视偏差」会显得懂业务。

直播延迟归因:先拆链路——采集端编码、上行网络、服务端转码与分发、下行网络、播放器缓冲与解码、渲染。定位靠同源时间戳:在画面里叠加一个由服务端下发的时钟(或规律变化的数字),同时记录本地发起时间,就能把「端到端延迟」拆成「服务端之前」和「端到端」两段;再用控制变量法换播放器/换网络/换设备复现。如果换播放器后延迟同步变化,问题在播放器侧(缓冲策略、首帧策略);如果所有播放器都一样,问题在链路或服务端。多设备测试的意义是排除单机性能与网络差异,只有单台机器测出来的结论不能推广。