面试题记录

1. redis数据结构

Redis有8种核心数据结构:

  • String:最常用,底层SDS(简单动态字符串),支持整数和字符串。用于缓存、计数器、分布式锁。

  • Hash:底层是压缩列表或哈希表,适合存对象,如用户信息、购物车。

  • List:底层双向链表或压缩列表,可作为消息队列、栈、最新列表。

  • Set:底层整数集合或哈希表,无序去重,适合标签、共同好友。

  • ZSet(Sorted Set):底层是跳表+哈希表或压缩列表,按score排序,用于排行榜、延迟队列。

  • Bitmap:基于String的位操作,适合签到、活跃统计。

  • HyperLogLog:概率数据结构,用于UV统计,误差约0.81%。

  • Geo:基于ZSet,存地理位置,支持附近的人查询。


2. redis持久化机制

Redis提供两种持久化方式:

RDB(Redis Database)

  • 在指定时间间隔内将内存中的数据集快照写入磁盘

  • 触发方式:save(阻塞)、bgsave(fork子进程)

  • 优点:文件小、恢复快、对性能影响小

  • 缺点:可能丢失最后一次快照后的数据

AOF(Append Only File)

  • 以日志形式记录每个写操作,追加到文件末尾

  • 三种同步策略:always(每次)、everysec(每秒)、no(不主动)

  • 优点:数据更完整,最多丢失1秒数据

  • 缺点:文件体积大,恢复慢

混合持久化(Redis 4.0+)

  • RDB作为AOF文件的前缀,结合两者优势

3. mysql索引底层

MySQL InnoDB引擎的索引底层使用 B+树 数据结构。

B+树特点

  • 所有数据存储在叶子节点,非叶子节点只存索引值

  • 叶子节点之间用双向链表连接,支持范围查询

  • 树的高度低(3-4层可存千万级数据)

  • 磁盘预读友好,每个节点大小等于一页(16KB)

为什么用B+树不用B树?

  • B+树非叶子不存数据,每个节点可存更多索引,树更矮

  • 叶子节点链表结构,范围查询和全表扫描更高效


4. 聚簇索引与非聚簇索引

聚簇索引

  • 数据和索引存储在一起

  • InnoDB中,主键索引就是聚簇索引

  • 叶子节点存完整行数据

  • 一个表只能有一个聚簇索引

非聚簇索引(二级索引)

  • 数据和索引分开存储

  • 叶子节点存主键值

  • 回表:通过非聚簇索引查到主键,再到聚簇索引查完整数据

  • 一个表可以有多个非聚簇索引

对比

特性 聚簇索引 非聚簇索引
数据存储 叶子节点存数据 叶子节点存主键
数量 1个 多个
查询效率 主键查询快 需要回表
插入顺序 按主键顺序插入 独立维护

5. 索引优化

  1. 选择区分度高的列:如主键、唯一ID,避免性别这类低区分度列

  2. 最左前缀原则:联合索引(a,b,c),查询条件命中a或a,b才能用索引

  3. 覆盖索引:查询字段都在索引中,避免回表

  4. 索引下推(ICP):在索引层面过滤数据,减少回表次数

  5. 避免索引失效(见第6题)

  6. 控制索引数量:索引会降低写性能,一般单表不超过5-6个

  7. 主键设计:自增整型主键,避免UUID作为聚簇索引(页分裂严重)


6. 索引失效

常见导致索引失效的场景:

  1. 违反最左前缀:联合索引(a,b,c),查询条件只有b或c

  2. 在索引列上使用函数或计算WHERE DATE(create_time) = '2024-01-01'

  3. 隐式类型转换 :varchar字段传int,如WHERE phone = 13800000000

  4. 使用LIKE以通配符开头WHERE name LIKE '%张三'

  5. OR条件中有非索引列WHERE id=1 OR name='张三'(name无索引)

  6. 索引列参与比较操作WHERE a+1 > 10 应改为 WHERE a > 9

  7. 数据分布不均:查询结果超过全表30%左右,优化器可能放弃索引

  8. IS NOT NULL :某些情况下会导致索引失效,但IS NULL通常能用


7. mysql执行一条sql

MySQL执行一条SQL的完整流程:

text

复制代码
客户端 → 连接器 → 查询缓存(8.0已移除) → 解析器 → 预处理器 → 优化器 → 执行器 → 存储引擎

详细步骤

  1. 连接器:建立连接、验证身份和权限

  2. 查询缓存(8.0删除):命中则直接返回

  3. 解析器:词法分析(识别SQL关键字)、语法分析(检查语法)

  4. 预处理器:检查表和字段是否存在,权限验证

  5. 优化器:选择索引,生成执行计划(如先查哪个表、用哪个索引)

  6. 执行器:调用存储引擎接口,执行查询,逐行判断条件

  7. 存储引擎:读写数据、事务处理、锁管理(InnoDB/MyISAM)

一条UPDATE语句额外:写redo log(prepare状态)、binlog,再commit。


8. 那么多索引mysql怎么选(不会)

(按你的要求标记:不会

这个问题涉及MySQL优化器的索引选择算法。核心逻辑是:

  • 优化器基于索引统计信息 (采样估算)计算每个索引的扫描行数代价

  • 代价包括:IO成本、CPU成本、回表成本

  • 选择代价最小的执行计划

但优化器可能选错,原因:

  • 统计信息不准确(采样误差)

  • 索引基数(cardinality)估算不准

  • 不同版本优化器策略差异

解决办法:

  • FORCE INDEX / USE INDEX 强制指定索引

  • ANALYZE TABLE 重新统计

  • 调整优化器参数


9. tcp与udp区别

特性 TCP UDP
连接 面向连接(三次握手) 无连接
可靠性 可靠传输,确认重传 不可靠,丢包不重传
顺序 保证顺序 不保证
流量控制 有(滑动窗口)
拥塞控制
头部大小 20-60字节 8字节
传输效率 较低 较高
典型应用 HTTP、FTP、SSH DNS、视频直播、游戏

10. tcp为什么可靠

TCP通过以下机制保证可靠传输:

  1. 确认应答(ACK):接收方收到数据后返回ACK,发送方未收到则重传

  2. 超时重传:RTO超时未收到ACK就重发

  3. 快速重传:收到3个重复ACK后立即重传,不等超时

  4. 序列号和确认号:保证数据有序,解决乱序和重复问题

  5. 校验和:检测数据损坏

  6. 流量控制(滑动窗口):接收方控制发送速率,防止接收方缓存溢出

  7. 拥塞控制:慢启动、拥塞避免、快重传、快恢复

  8. 三次握手/四次挥手:建立可靠连接,保证连接正常关闭


11. 消息队列作用

  1. 异步处理:用户注册后发送邮件、短信等异步执行,减少主流程耗时

  2. 应用解耦:订单系统完成订单后发消息,库存、积分系统订阅,互不直接依赖

  3. 流量削峰:秒杀场景先写MQ再慢慢消费,保护下游数据库

  4. 日志处理:业务日志发MQ,消费端异步写入ES或大数据平台

  5. 分布式事务:结合TCC或本地消息表,实现最终一致性

  6. 延迟/定时任务:如取消超时未支付订单(RocketMQ/Redis的延迟队列)


12. kafka怎么保证消息有序性

Kafka保证有序的几种方式:

  1. 单个分区内有序:Kafka保证一个分区内消息按发送顺序存储和消费(offset递增)

  2. 全局有序:Topic只设置1个分区(牺牲吞吐量)

  3. 业务键有序 :使用相同的key发送到同一分区,producer.send(record)中key相同则进入同一分区

消费端保证有序

  • 一个分区只能被一个消费者实例消费(同一个消费者组内)

  • 消费端使用单线程处理,或使用max.poll.records=1保证每次拉取少量消息

注意事项

  • 生产者重试可能导致乱序,可设置max.in.flight.requests.per.connection=1(吞吐量下降)

  • Kafka 0.11+支持幂等生产者,可避免重试导致的乱序


13. mcp是什么?

MCP(Model Context Protocol)

  • 由Anthropic(Claude团队)开源的一个协议标准

  • 用于AI模型与外部数据源、工具之间的标准化连接

  • 类似AI应用的"USB-C接口",让大模型能访问数据库、API、文件系统等

  • MCP Server提供工具能力,MCP Client(如Claude Desktop)调用

(如果面试官不是问这个,可能是其他领域的MCP,比如MCP协议其他含义)


14. skills是什么?

Skills(技能) 在不同上下文中的含义:

AI Agent领域(如Claude、GPT):

  • 预定义的一组能力/工具,让AI能执行特定任务

  • 例如:代码执行技能、联网搜索技能、文件操作技能

  • Skill = Prompt模板 + 工具调用 + 权限范围

后端/微服务

  • 指开发者的技术能力栈

建议结合你的面试上下文判断。如果是AI方向,Skills是AI应用中的一个概念。


15. jvm内存分配与回收过程

(你回答"从创建对象到判断垃圾对象到垃圾回收",方向是对的)

完整流程

内存分配

text

复制代码
新对象 → 栈上分配(逃逸分析) → TLAB分配 → Eden区 → 年龄+1 → Survivor区 → 年龄阈值 → Old区
  • 优先栈上分配(不逃逸的对象)

  • 再尝试TLAB分配(线程本地缓冲区)

  • 然后放Eden区

  • 大对象直接进老年代(-XX:PretenureSizeThreshold)

垃圾判断

  • 引用计数法(已弃用,循环引用问题)

  • 可达性分析(GC Root:栈帧引用、静态变量、JNI引用等)

垃圾回收过程

  1. Minor GC(年轻代):Eden满时触发,存活对象复制到Survivor,年龄+1

  2. 晋升:年龄达到15(默认)或Survivor放不下时,晋升老年代

  3. Full GC:老年代满或System.gc()时触发,回收整个堆

分代假设:大多数对象朝生夕灭,存活久的进入老年代


16. fullgc触发机制

Full GC触发场景:

  1. 老年代空间不足:Minor GC后晋升对象放不进老年代

  2. 大对象直接进入老年代,老年代放不下

  3. 元空间(Metaspace)不足(触发时回收类卸载)

  4. System.gc()(可用-XX:+DisableExplicitGC禁用)

  5. CMS GC的Concurrent Mode Failure:并发收集时老年代被填满,退化为Serial GC(Full GC)

  6. 统计信息判断:Minor GC的平均晋升大小 > 老年代剩余空间

  7. 调用RMI或NIO的sun.misc.GC(分布式定时GC)

调优目标:尽量减少Full GC次数,因为STW时间很长


17. tcp的拥塞控制流程(不会了)

(按你的要求标记:不会

简要答案:

  • 慢启动:cwnd从1开始,每收到ACK翻倍,直到ssthresh

  • 拥塞避免:cwnd线性增加,每次RTT加1

  • 快重传:收到3个重复ACK立即重传,不等超时

  • 快恢复:重传后设置cwnd = ssthresh(或ssthresh+3),进入拥塞避免


18. 分布式事务解决方案

  1. 两阶段提交(2PC):准备阶段+提交阶段,强一致性,性能差,协调者单点

  2. 三阶段提交(3PC):引入超时机制和CanCommit阶段,解决单点阻塞

  3. TCC(Try-Confirm-Cancel):业务层面补偿,高并发场景,需实现回滚逻辑

  4. 本地消息表:消息持久化+定时轮询,最终一致性

  5. RocketMQ事务消息:半消息+本地事务状态回查,最终一致性

  6. Saga:长事务拆分为多个本地事务,依次执行,失败则逆序补偿

  7. 最大努力通知:业务完成后持续重试通知,适合跨平台回调场景

选型原则:强一致选2PC/3PC,高并发选TCC,长事务选Saga,最终一致性选事务消息


手撕:反转双向链表

java

复制代码
class ListNode {
    int val;
    ListNode prev;
    ListNode next;
    ListNode(int val) { this.val = val; }
}

public ListNode reverseDoublyLinkedList(ListNode head) {
    if (head == null || head.next == null) return head;
    
    ListNode cur = head;
    ListNode prev = null;
    
    while (cur != null) {
        // 交换prev和next指针
        ListNode next = cur.next;
        cur.next = prev;
        cur.prev = next;
        
        // 移动
        prev = cur;
        cur = next;
    }
    
    return prev;  // 新头节点
}

测试

text

复制代码
原链表:1 <-> 2 <-> 3 <-> null
反转后:3 <-> 2 <-> 1 <-> null

1. redis与数据库的缓存一致性

常见方案:

  • Cache Aside Pattern:读先读缓存,未命中读DB再写缓存;写先更新DB,再删除缓存

  • 延迟双删:写后删缓存,隔几百毫秒再删一次

  • 订阅binlog:Canal监听MySQL变更,异步更新缓存

  • 双写一致性要求高:使用Redis自带的redisson读写锁

2. 分布式CAP理论

C(一致性):所有节点同一时间数据一致

A(可用性):非故障节点总能响应

P(分区容忍性):网络分区时系统继续运行

CAP只能三选二,但P必须保证,实际是CP或AP的选择。

3. 什么时候AP,什么时候CP

  • AP:互联网业务(商品浏览、评论),允许短暂不一致,保证高可用。如Eureka。

  • CP:金融、交易系统,强一致性要求,允许部分节点不可用。如Zookeeper、Etcd。

4. 进程线程协程

  • 进程:资源分配最小单位,独立内存空间,切换开销大

  • 线程:CPU调度最小单位,共享进程内存,切换开销较小

  • 协程:用户态轻量线程,切换由用户控制,开销极小,Go goroutine、Kotlin协程

5. Spring的IOC原理及优点

原理:控制反转,通过DI(依赖注入)管理对象生命周期和依赖关系。核心是BeanFactory和ApplicationContext,解析配置→创建Bean→存入容器→注入依赖。

优点:解耦、易测试、管理统一、减少样板代码。

6. 除了解耦还有什么优点?(IOC)

  • 单例管理(默认Bean单例)

  • 生命周期回调(@PostConstruct、@PreDestroy)

  • 循环依赖解决(三级缓存)

  • AOP整合(基于动态代理)

7. SpringBoot与Spring区别

  • Spring需手动配置依赖、web.xml、容器等

  • SpringBoot自动配置、内嵌容器、starter简化依赖

  • 源码层面:@SpringBootApplication组合注解、AutoConfigurationImportSelector加载META-INF/spring.factories

Tomcat:SpringBoot内嵌,启动时通过TomcatServletWebServerFactory创建,核心是Connector(接收请求)+Container(处理请求)。

8. MyBatis、Ibatis、SQL写法

MyBatis是半自动ORM,Ibatis是旧版。SQL写在XML或注解中,但团队可规范用MyBatis-Plus、通用Mapper减少手写。

9. 设计秒杀系统(前端→网关→缓存→数据库防超卖)

  • 前端:按钮置灰、倒计时、验证码

  • 网关:限流(令牌桶、漏桶)、风控、过滤无效请求

  • 缓存:Redis预减库存,Lua脚本原子扣减,ZSet记录成功用户

  • 数据库防超卖 :乐观锁(UPDATE ... WHERE stock>0 AND version=xxx)、或redis扣减后异步落库

  • MQ:削峰,下单异步处理

10. 怎么做限流

  • 计数器(固定窗口,有临界突发)

  • 滑动窗口(更平滑)

  • 令牌桶(允许一定突发)

  • 漏桶(恒定速率)

  • 中间件:Guava RateLimiter、Sentinel、Redis + Lua

11. 缓存一致性 + 异步要用户等吗?

等:同步更新缓存(双写)

不等:先返回成功,异步通过binlog/Canal更新缓存,最终一致

秒杀场景:下单成功直接返回,异步处理后续,用户不感知异步延迟。

12. 负载均衡怎么做

  • 四层:LVS、F5,基于IP+端口

  • 七层:Nginx、HAProxy,基于HTTP Header、URL

  • 算法:轮询、加权轮询、最小连接数、IP哈希、一致性哈希

13. 多数据中心&没卖完怎么处理

  • 多数据中心:就近接入,数据同步(数据库双活、DRC),限流需全局配额

  • 没卖完:延长活动时间、降价推送、库存释放给其他渠道、预约提醒

相关推荐
zzzsde1 小时前
【Linux】线程同步和互斥(1):线程互斥与加锁实现
linux·运维·服务器·开发语言·算法
ㄟ留恋さ寂寞1 小时前
Golang格式化输出占位符都有什么_Golang fmt占位符教程【通俗】
jvm·数据库·python
番茄去哪了1 小时前
JVM虚拟机基础篇(上)
jvm
努力努力再努力wz1 小时前
【C++高阶数据结构系列】:时间轮定时器详解:原理分析与代码实现,带你从零手撕时间轮!(附时间轮的实现源码)
c语言·开发语言·数据结构·c++·qt·算法·ui
mmz12072 小时前
广搜题目练习(c++)
c++·算法
iiiiyu2 小时前
⾯向对象和集合编程题
java·大数据·开发语言·数据结构·编程语言
YuanDaima20482 小时前
贪心算法基础原理与题目说明
数据结构·人工智能·python·算法·贪心算法·手撕代码
Full Stack Developme2 小时前
Spring-web 解析
java·前端·spring
NashSKY2 小时前
波束成形MVDR (最小方差无失真响应) 算法数学原理解析
算法·矩阵