面灵AI→

拼多多服务端一面:慢 SQL、消息积压与防 DBA 篡改

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

《面试题目》

  1. 自我介绍。
  2. JVM 内存模型。
  3. MySQL 主从同步模型。
  4. 某条 SQL 一直都是正常的,某天突然慢了,是为什么?
  5. Redis 用过吗?基础数据类型?
  6. Redis 除了缓存还有什么用?
  7. 分布式锁命令。
  8. MQ 消息积压怎么处理?
  9. 场景:现在有个订单服务,这个订单插入后用户能看到,商家也要能看到,数据量太大了,要怎么做?
  10. 分库分表用什么键值来分?
  11. 有其他做法吗?(提示用 ES,天然支持)
  12. 算法:给定长度为 n 的数组、整数 s,求最小的长度 k 使得长度为 k 的连续子串和大于等于 s。
  13. 二分答案有更好做法吗?滑动窗口。
  14. 场景:有金融服务涉及金钱,DBA 能操作这个数据库,怎么做可以防止他修改某个订单的金额导致服务或者记账出现错误?
  15. 有人提出「update 设置钩子、弹出链接要主管审批」,面试官表示 DBA 是能直接 update 的、不用审批,有更好的做法?

《参考解析》

JVM 内存模型与 MySQL 主从同步

JVM 部分要分清「运行时数据区」与「Java 内存模型(JMM)」——前者是内存怎么划分(程序计数器、虚拟机栈、本地方法栈、堆、方法区/元空间,外加直接内存),后者是并发下的可见性与有序性规则(主内存与工作内存、happens-before、volatile/synchronized/final 的语义)。答运行时数据区时每块说清「存什么、线程私有还是共享、可能抛什么异常」;答 JMM 时讲清「每个线程有自己的工作内存、变量从主内存拷贝、volatile 强制刷新与禁止重排、happens-before 的几条规则(程序顺序、监视器锁、volatile 写读、线程启动与终止、传递性)」。很多候选人会把两者混着答,能主动区分是加分点。

MySQL 主从同步:主库把变更写进 binlog(STATEMENT/ROW/MIXED 三种格式,生产上多用 ROW 保证确定性),从库的 IO 线程拉取 binlog 写入本地 relay log,SQL 线程(或并行复制的工作线程)重放。复制模式有异步(主库不等待,故障可能丢数据)、半同步(至少一个从库确认收到才算提交成功,降低丢数据概率)、全同步(组复制/MGR,强一致但代价大)。要能讲清几个常见问题:主从延迟的来源(从库 SQL 线程单线程重放、大事务、DDL、从库负载高)与影响(读写分离下读不到刚写的数据),解决手段是并行复制(按库/按组提交)、拆分大事务、关键读走主库(或强制走主库一段时间);以及复制中断的排查路径(看 SHOW SLAVE STATUS 的 Seconds_Behind_Master、Last_IO_Error/Last_SQL_Error、主从 server_id 冲突、GTID 缺失)。

一条 SQL 突然变慢:按「数据、统计信息、锁、资源、发布」排查

这题的答案要体现排查路径而不是单一原因。常见原因分五类:一是数据量与分布变化,比如某张表从百万涨到亿级,或者某个值变成了热点(性别、状态这类区分度低的列占比改变)导致优化器改选了全表扫描;二是统计信息过期或采样偏差,ANALYZE TABLE 之后计划可能又变了——优化器是基于代价选路的,代价估算错了计划就错了;三是锁与并发,被长事务、DDL(ALTER TABLE 加元数据锁)、或间隙锁阻塞,表现为等待而非慢;四是资源与配置,缓冲池被其他查询挤掉导致命中率下降、磁盘 IO 抖动、连接数打满排队、临时表落盘;五是变更引入,比如上线了新版本、加了索引反而让优化器改选、或者只在部分实例上慢(数据分片不均)。排查动作:先看现象(是偶发还是持续、是所有实例还是个别、耗时分布是 P50 慢还是只有 P99 慢),用 EXPLAIN/EXPLAIN ANALYZE 看执行计划与预估行数(与实际差很多就是统计信息问题),看慢查询日志的扫描行数与返回行数,查 performance_schema/innodb_trx 看锁等待,必要时对比历史计划与最近发布。答题时说「先区分是计划变了、锁住了、还是资源不够了」,比罗列十条原因有用。

Redis 用途、分布式锁与消息积压

Redis 除缓存以外的用途与原帖里字节那道题高度重合:分布式锁、限流计数、排行榜、会话与 token、去重与布隆过滤、延时任务(ZSet)、以及轻量消息队列(Stream)。分布式锁的加锁命令要写准:SET key value NX PX 30000(NX 保证只有不存在时设置、PX 设毫秒级过期防止死锁),value 用唯一值(如 UUID + 线程标识)以便安全释放;释放必须用 Lua 保证「比对 value 相同才删除」的原子性,否则可能删掉别人的锁。要主动讲清局限与延伸:单实例 Redis 在主从切换时锁可能丢失(主库写入未同步就宕机),所以对正确性要求极高的场景要用 Redlock(多实例多数派)、或用 ZooKeeper/etcd 这类基于共识的实现,更稳的做法是「锁只作为减少竞争的优化,正确性由数据库唯一索引或版本号兜底」。续期问题用看门狗(Redisson 的 watchdog)解决,同时注意业务耗时要小于锁过期时间。

MQ 消息积压的处理要分层:先定位原因(生产突增还是消费变慢——看生产速率与消费速率、消费 lag 曲线),再对症。消费变慢的常见原因:单条处理耗时高(慢 SQL、同步远程调用)、消费者实例数不够或分区数限制并行度(Kafka 里并发上限是分区数)、消费逻辑里串行、以及消费者被 rebalance 打断。手段:先扩容消费者(Kafka 需要同时扩分区且不能再缩、扩分区要评估顺序性影响)、把批量处理改成并行、把非核心逻辑移出消费链路(落库后异步处理)、临时降级(先落库后处理)、必要时新建临时 topic 提高并行度再回填。生产突增则考虑削峰、限流与优先级(关键消息与统计类消息分开 topic)。要强调两个坑:积压时不要盲目重试放大压力,以及处理顺序敏感的业务不能简单扩分区(会破坏分区内保序)。

订单读扩散:分库分表键与 ES

「订单插入后用户和商家都要看到、数据量太大」是典型的读写放大与多维度查询问题。分库分表先要选分片键,而问题的本质是「有两个查询维度(用户维度与商家维度)」,单靠一个分片键无法同时高效支持。可选方案要对比着讲:一是按用户 ID 分片,用户侧查询天然高效,商家侧要扫所有分片(可以建异构索引表按商家维度存一份轻量映射,用异步同步保证最终一致);二是按订单 ID(雪花)分片保证均匀,两种维度查询都走索引表;三是基因法(把用户 ID 的低位嵌进订单 ID)让同一用户的订单落在同一分片,便于用户维度聚合。跨分片的查询与统计要靠中间件(ShardingSphere)或业务层路由+并行查询再归并,注意深分页与排序的代价。原帖提到面试官提示 ES,这一路要答成「用搜索引擎做多维度查询与检索」:把订单的检索字段(用户、商家、状态、时间、金额区间)异构同步到 ES,写入时通过 binlog 订阅(Canal)或业务双写保证最终一致,查询走 ES 拿到订单 ID 再回源数据库拿详情;要主动讲清代价——一致性与延迟(最终一致、可能短暂查不到刚下的单,可以用「写后读走主库」兜)、ES 的成本与运维、以及回源带来的额外 RT 与缓存策略。合适的收尾是给组合方案:核心交易走分库分表 + 用户维度的分片键,多维度检索交给 ES,二者用异步同步对齐并做对账。

算法:最短长度连续子数组和 ≥ s

滑动窗口(双指针)是 O(n) 的最优解:右指针扩张累加和,当和大于等于 s 时收缩左指针并更新最小长度,直到和小于 s 再继续扩张。因为所有元素为正数,和随窗口收缩单调递减,所以左指针不会回退。二分答案是 O(n log n):二分长度 k,检查是否存在长度不超过 k 的子数组和 ≥ s(用前缀和 O(n) 判断是否单调可行)。面试官问「有更好做法吗」就是引导你从二分答案转到滑动窗口,答的时候要讲清为什么滑动窗口成立——前提是元素非负,否则不满足单调性(如果是负数就要用前缀和加单调队列)。边界:不存在这样的子数组(返回 0 或按约定)、s ≤ 0、数组为空;要主动确认返回的是长度还是子数组本身。

防 DBA 篡改订单金额:从「审批」转向「不可否认」

面试官否掉「加钩子让主管审批」,是因为那只是在应用层拦截,DBA 直接连库执行 SQL 就绕过了,而且审批不是不可否认的证据。正确的思路是让篡改可被发现且无法抵赖,按层给方案。第一层是权限最小化:生产库按职责分账号,DBA 日常只用只读账号,写操作通过受控通道(变更平台)执行,直接连库的写权限只保留给极少数人;这一层降低概率但不等于可发现。第二层是数据库侧的审计:打开审计日志(general_log/audit plugin、MySQL Enterprise Audit 或第三方审计),记录所有 DDL/DML 的账号、时间、SQL 文本与来源 IP,并把审计日志实时外发到独立系统(DBA 无法私下删除);这一层提供发现能力。第三层是数据完整性保护:对敏感字段做应用层加密或哈希链(把「订单号 + 金额 + 前后记录的哈希」串成链,任何一处改动都会让链断裂),或者把关键金额同时写入独立的账本表/流水系统,主表与账本对账不一致就告警;这一层让篡改必然被发现。第四层是业务侧核对与治理:定时对账(订单表与支付流水、与财务系统的日终对账)、金额变动的合法路径只有「走业务接口」并留操作人、以及对账差异自动告警并冻结相关订单。第五层是组织与流程:权限变更留痕、双人复核高风险操作、以及把「直接改库」写进红线并有事后追溯机制。回答时把这段收敛成一句话最有力:防护的目标不是「禁止 DBA 改」,而是「让他改了也藏不住」——权限降低概率、审计提供发现、哈希与对账让篡改必然暴露。