分布式锁与MySQL索引优化实战解析

发布时间:2026/7/28 11:21:47
分布式锁与MySQL索引优化实战解析 1. 项目概述QDKTAI实战面试题50问系列是面向技术岗位求职者的专项训练题库其中21-30题作为整个系列的中段部分主要考察候选人在实际开发场景中的问题解决能力。这个阶段的题目设计往往聚焦于技术深度与应用场景的结合既不像前20题那样偏重基础概念也不像后20题那样强调系统设计而是恰到好处地检验工程师在具体技术点上的实战水平。作为经历过数十场技术面试的面试官我发现很多候选人在这个阶段的题目上表现两极分化——要么因为对某些技术点理解不够深入而卡壳要么因为缺乏实际项目经验而只能给出教科书式的回答。这套题目特别适合那些已经掌握基础概念正准备冲击中高级岗位的开发者进行针对性训练。2. 核心题目解析与解题思路2.1 第21题分布式锁的实现方案对比这道题考察的是对分布式系统核心问题的理解。在实际面试中我通常会先让候选人列举常见的分布式锁实现方式然后深入询问每种方案的优劣比较。Redis分布式锁是最常见的方案其核心在于SETNX命令和过期时间的配合使用。但很多候选人会忽略锁续期和锁释放这两个关键问题锁续期需要配合看门狗机制避免业务未执行完锁已过期锁释放必须保证是加锁者才能释放通常用Lua脚本实现原子性操作Zookeeper分布式锁通过临时顺序节点实现天然具备可重入特性。但需要注意羊群效应——当锁释放时所有等待的客户端都会被唤醒可以通过只监听前一个节点来优化。数据库分布式锁简单但性能较差适合并发量不大的场景。关键点在于利用唯一索引和for update语句。提示回答这个问题时一定要结合实际业务场景讨论选型。比如高并发秒杀适合Redis而需要严格顺序执行的场景可能更适合Zookeeper。2.2 第22题MySQL索引失效的常见场景这是DBA岗位必问题目但开发岗也经常被考察。我建议从以下维度组织答案索引失效的典型情况不符合最左前缀原则比如联合索引(a,b,c)条件下查询b1使用了范围查询后中断索引where a1 and b1对索引列进行了运算或函数处理where YEAR(create_time)2023使用了!或操作符类型不匹配导致隐式转换varchar字段用数字查询优化建议使用EXPLAIN分析执行计划避免SELECT *只查询需要的字段考虑使用覆盖索引减少回表对于长字符串字段考虑前缀索引2.3 第23题Kafka如何保证消息顺序性这道题考察消息队列的核心特性。需要分三个层次回答分区级别的顺序保证 Kafka只能保证单个分区内消息的顺序性这是其架构设计决定的。因此要实现全局有序必须使用单分区但这会严重影响吞吐量。生产者端的顺序控制设置max.in.flight.requests.per.connection1启用幂等性(idempotence)配置对于关键业务可以考虑同步发送模式消费者端的顺序处理单个消费者线程消费单个分区使用内存队列进行顺序控制时要小心处理重平衡考虑使用Kafka Streams的状态存储3. 深度技术点剖析3.1 第24题JVM内存模型详解这道题看似基础但能很好区分初级和高级开发者。我建议按照以下结构回答运行时数据区程序计数器线程私有记录执行位置虚拟机栈栈帧存储局部变量表、操作数栈等本地方法栈为Native方法服务堆对象实例存储区域GC主要工作区方法区存储类信息、常量等重点解析堆内存结构新生代Young GenerationEden区对象首次分配区域Survivor区From/ToMinor GC后存活对象转移区老年代Old Generation长期存活对象晋升区元空间MetaspaceJDK8取代永久代内存模型实战要点使用-XX:PrintGCDetails参数分析GC日志合理设置-Xmx和-Xms避免频繁扩容关注Metaspace大小防止类加载器泄漏使用jmap和jstat工具监控内存使用3.2 第25题Redis持久化机制对比这道题需要对比RDB和AOF两种机制RDB持久化原理定时生成内存快照优点文件紧凑恢复速度快缺点可能丢失最后一次快照后的数据配置项save 900 1表示900秒内至少1次修改则触发AOF持久化原理记录所有写操作命令优点数据安全性高支持多种fsync策略缺点文件体积大恢复速度慢重写机制bgrewriteaof压缩命令生产环境建议通常同时开启RDB和AOFAOF使用everysec策略平衡性能和安全定期检查持久化文件完整性对于重要数据考虑增加从节点做备份4. 系统设计类题目解析4.1 第26题设计一个短链系统这是典型的系统设计题目考察架构能力。建议按照以下步骤回答需求分析功能需求长短链转换、访问统计非功能需求高并发、低延迟、高可用关键设计点短链生成算法自增IDBase62编码哈希算法如MurmurHash需要考虑碰撞处理存储设计关系型数据库存储映射关系Redis缓存热点数据跳转流程301/302重定向选择防爬虫和恶意请求扩展功能访问统计和数据分析自定义短链过期时间设置性能优化使用布隆过滤器判断短链是否存在多级缓存策略异步记录访问日志4.2 第27题如何设计一个秒杀系统这道题考察高并发场景下的系统设计能力核心挑战瞬时高并发库存准确性防止超卖系统稳定性架构设计要点流量削峰答题验证码消息队列缓冲库存处理Redis预减库存异步扣减数据库库存分段优化缓存策略多级缓存本地Redis热点数据特殊处理熔断保护限流策略降级方案过载保护特别注意前端静态化处理按钮防重复点击订单过期处理机制数据一致性监控5. 编码实战类题目5.1 第28题手写LRU缓存这是考察算法和数据结构实现能力的典型题目LRU核心思想 最近最少使用算法当缓存满时淘汰最久未使用的数据。实现方案使用LinkedHashMap实现最简单class LRUCache extends LinkedHashMapInteger, Integer { private int capacity; public LRUCache(int capacity) { super(capacity, 0.75f, true); this.capacity capacity; } protected boolean removeEldestEntry(Map.EntryInteger, Integer eldest) { return size() capacity; } }双向链表哈希表实现更灵活class LRUCache { class DLinkedNode { int key; int value; DLinkedNode prev; DLinkedNode next; } private void addNode(DLinkedNode node) { node.prev head; node.next head.next; head.next.prev node; head.next node; } private void removeNode(DLinkedNode node) { DLinkedNode prev node.prev; DLinkedNode next node.next; prev.next next; next.prev prev; } private void moveToHead(DLinkedNode node) { removeNode(node); addNode(node); } private DLinkedNode popTail() { DLinkedNode res tail.prev; removeNode(res); return res; } private MapInteger, DLinkedNode cache new HashMap(); private int size; private int capacity; private DLinkedNode head, tail; public LRUCache(int capacity) { this.size 0; this.capacity capacity; head new DLinkedNode(); tail new DLinkedNode(); head.next tail; tail.prev head; } public int get(int key) { DLinkedNode node cache.get(key); if (node null) return -1; moveToHead(node); return node.value; } public void put(int key, int value) { DLinkedNode node cache.get(key); if (node null) { DLinkedNode newNode new DLinkedNode(); newNode.key key; newNode.value value; cache.put(key, newNode); addNode(newNode); size; if (size capacity) { DLinkedNode tail popTail(); cache.remove(tail.key); --size; } } else { node.value value; moveToHead(node); } } }考察重点时间复杂度分析O(1)线程安全性考虑内存占用评估实际应用场景讨论5.2 第29题多线程交替打印ABC这道题考察线程协作和同步机制的理解使用ReentrantLock实现class ABCPrinter { private int num 0; private Lock lock new ReentrantLock(); private Condition conditionA lock.newCondition(); private Condition conditionB lock.newCondition(); private Condition conditionC lock.newCondition(); public void printA() { lock.lock(); try { while (num % 3 ! 0) { conditionA.await(); } System.out.print(A); num; conditionB.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } // printB和printC方法类似 }使用Semaphore实现class ABCPrinter { private Semaphore semaphoreA new Semaphore(1); private Semaphore semaphoreB new Semaphore(0); private Semaphore semaphoreC new Semaphore(0); public void printA() throws InterruptedException { for (int i 0; i 10; i) { semaphoreA.acquire(); System.out.print(A); semaphoreB.release(); } } // printB和printC方法类似 }扩展讨论如何扩展到N个线程交替打印各种同步机制的性能比较避免死锁的注意事项6. 性能优化类题目6.1 第30题MySQL慢查询优化实战这道题考察实际问题的排查和解决能力慢查询分析步骤开启慢查询日志SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1; SET GLOBAL slow_query_log_file /var/log/mysql/slow.log;使用EXPLAIN分析执行计划关注type列最好到ref或const检查possible_keys和key是否一致注意Extra列中的Using filesort或Using temporary常见优化手段添加合适的索引重写复杂查询避免SELECT *优化JOIN操作考虑使用覆盖索引实战案例-- 优化前 SELECT * FROM orders WHERE user_id 100 AND status paid ORDER BY create_time DESC; -- 优化后 ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, create_time); SELECT id, user_id, amount FROM orders WHERE user_id 100 AND status paid ORDER BY create_time DESC;高级技巧使用pt-query-digest分析慢查询日志考虑使用延迟关联优化分页查询对于大数据量表考虑分区表策略使用SQL_NO_CACHE测试真实性能