欢迎点击下方👇关注我,记得星标哟~
文末会有重磅福利赠送
新的一周,祝你开心!
好久没分享面经了,今天来个大的---字节的后端实习二面,简直就是八股盛宴,问的太多太全面了。


数据库事务隔离级别主要分为四种,从低到高依次为:
对比总结:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能影响 |
|---|---|---|---|---|
读未提交 | 是 | 是 | 是 | 最低 |
读已提交 | 否 | 是 | 是 | 中等 |
可重复读 | 否 | 否 | 是 | 中高 |
串行化 | 否 | 否 | 否 | 最高 |
可重复读隔离级别通过 MVCC(多版本并发控制) 和 锁机制 实现:
示例:事务 A 启动后读取账户余额为 1000 元,即使事务 B 修改余额并提交,事务 A 再次读取仍为 1000 元。
MVCC 的核心是通过数据多版本实现读写并发控制,流程如下:
DB_TRX_ID(最近修改的事务 ID)和 DB_ROLL_PTR(指向 Undo Log 的回滚指针)。DB_TRX_ID 小于 Read View 中最小活跃 ID,说明数据已提交,可见。DB_TRX_ID 在活跃事务 ID 列表内,说明数据未提交,不可见,需沿 DB_ROLL_PTR 在 Undo Log 中查找旧版本。DB_TRX_ID。案例:事务 A(ID=101)更新数据时,事务 B(ID=102)通过 Read View 读取 Undo Log 中的旧版本,避免脏读。
维度 | 不可重复读 | 幻读 |
|---|---|---|
定义 | 同一事务内多次读取同一数据,结果不一致 | 同一事务内多次查询同一条件,结果集行数不一致 |
原因 | 其他事务修改了该数据(UPDATE/DELETE) | 其他事务插入或删除了符合条件的数据(INSERT/DELETE) |
数据范围 | 单行数据 | 多行数据(结果集) |
解决隔离级别 | 可重复读(通过 MVCC 固定快照) | 串行化(通过间隙锁阻止插入) |
示例 | 事务 A 两次读取用户工资,值从 1000 变为 2000 | 事务 A 两次查询工资=1000 的用户,从 10 条变为 11 条 |
日志类型 | 用途 | 启用建议 |
|---|---|---|
错误日志(Error Log) | 记录 MySQL 启动、运行、关闭过程中的错误和警告,用于故障排查 | 必须启用 |
慢查询日志(Slow Query Log) | 记录执行时间超过阈值的 SQL,用于优化查询性能 | 建议启用 |
二进制日志(Binlog) | 记录所有数据修改操作(INSERT/UPDATE/DELETE),用于主从复制和数据恢复 | 主库必须启用 |
重做日志(Redo Log) | InnoDB 特有,记录事务的物理修改,用于崩溃恢复(保证持久性) | 自动启用 |
回滚日志(Undo Log) | 存储数据修改前的版本,用于事务回滚和 MVCC | 自动启用 |
中继日志(Relay Log) | 从库存储主库同步的 Binlog,用于主从复制 | 从库自动启用 |
通用查询日志(General Log) | 记录所有客户端请求(含 SQL 语句),用于审计 | 仅调试时临时启用 |
Redo Log 通过 Write-Ahead Logging(WAL) 机制实现事务持久性:
物理结构:
ib_logfile0, ib_logfile1),写满后覆盖旧数据。写入流程:
1(默认):每次提交同步刷盘(强一致)0 或 2:异步刷盘(可能丢失 1 秒数据)。innodb_flush_log_at_trx_commit
控制:崩溃恢复:
优化点:顺序 I/O 写日志(性能高于随机写数据页)。
格式 | 原理 | 优缺点 |
|---|---|---|
STATEMENT | 记录原始 SQL 语句 | - 优点:日志量小,性能高 - 缺点:非确定性函数(如 NOW())可能导致主从不一致 |
ROW | 记录每行数据的变更细节(如修改前后的值) | - 优点:数据一致性高 - 缺点:日志量大(如全表更新) |
MIXED | 自动选择模式:确定性语句用 STATEMENT,非确定性语句(如 UUID())用 ROW | 平衡性能和安全性(推荐) |
漏桶算法通过固定速率处理请求,控制流量:
capacity:桶容量(最大请求数)leak_rate:漏水速率(每秒处理数)。INCR 统计请求数,EXPIRE 重置桶计数。Redis 提供两种持久化方式:
dump.rdb)。always:每次写操作刷盘(安全但性能差)everysec:每秒刷盘(默认,最多丢 1 秒数据)。数据类型 | 特性 | 应用场景 |
|---|---|---|
String | 文本、数字或二进制数据 | 缓存、计数器(INCR) |
Hash | 键值对集合(类似对象) | 存储用户信息(如 user:1000 {name:"Alice"}) |
List | 双向链表,支持有序插入 | 消息队列(LPUSH/RPOP) |
Set | 无序唯一集合 | 标签系统、共同好友(SINTER) |
Sorted Set | 带分数的有序集合 | 排行榜(ZADD+ZRANGE) |
Stream | 消息流(支持消费者组) | 实时消息系统(类似 Kafka) |
Geospatial | 地理位置坐标 | 附近的人(GEORADIUS) |
Bitmap/HyperLogLog | 位操作/基数统计 | 签到(SETBIT)、UV 统计 |
Go语言的垃圾回收(GC)采用并发标记-清除算法,结合三色标记法和写屏障技术,旨在减少停顿时间(STW)并支持高并发场景。其核心机制如下:
GOGC=100%),自动触发。runtime.GC()。sync.Pool)。GC对程序的影响:最大停顿时间通常控制在10ms以内,但高频分配仍可能导致延迟升高。
Go中slice的扩容通过append触发,底层调用runtime.growslice函数,策略兼顾效率与内存利用率:
len(slice) + 新增元素数 > cap(slice)时触发扩容。newcap = oldcap * 2)。newcap = oldcap + (oldcap + 3*256) / 4逐步增加(约1.25倍),避免过度浪费。所需容量。newcap后,根据元素大小向上取整到内存页大小(如int类型按8字节对齐)。示例:
s := []int{1, 2}
s = append(s, 3, 4) // 原cap=2,扩容后cap=4(2*2)
优化建议:预分配容量(make([]int, 0, 100))以减少扩容开销。
GMP是Go语言实现高并发的核心调度模型,包含三个组件:
runq),数量默认为CPU核心数(可通过GOMAXPROCS调整)。工作流程:
go func()将G加入当前P的本地队列;若队列满,则转移一半G到全局队列。优势:
Channel的底层结构为hchan(源码定义),核心机制如下:
type hchan struct {
buf unsafe.Pointer // 环形缓冲区
qcount uint // 当前缓冲区元素数
dataqsiz uint // 缓冲区大小
lock mutex // 互斥锁
sendq waitq // 发送等待队列(sudog链表)
recvq waitq // 接收等待队列(sudog链表)
}
qcount == dataqsiz)。qcount == 0)。sudog加入sendq或recvq队列,M切出执行其他G。recvq非空,数据直接拷贝给等待的接收者,避免经过缓冲区。示例:
ch := make(chan int, 2)
ch <- 1 // 写入缓冲区
ch <- 2 // 缓冲区满,再次写入会阻塞
defer 关键字的执行顺序defer延迟执行函数,规则如下:
执行顺序:
defer fmt.Print("A")
defer fmt.Print("B") // 先输出"B",再输出"A"
defer按后进先出(LIFO) 顺序执行(类似栈)。参数求值时机:
i := 0
defer fmt.Print(i) // 输出0(i的值在声明时确定)
i = 1
defer的参数在声明时立即求值,而非执行时。执行时机:
return赋值后、函数结束前),即使发生panic也会执行。常见陷阱:
defer,可能因延迟执行导致资源未及时释放(如文件句柄)。建议改用匿名函数包裹。defer修改命名的返回值,会影响最终结果。应用场景:资源释放(文件关闭)、错误恢复(recover)等。
TCP与UDP是传输层协议的核心区别在于可靠性与连接机制:
特性 | TCP | UDP |
|---|---|---|
连接性 | 面向连接(三次握手) | 无连接 |
可靠性 | 可靠(确认重传、有序) | 不可靠(可能丢包、乱序) |
数据格式 | 字节流(无边界) | 数据报(有边界) |
头部开销 | 较大(20-60字节) | 较小(8字节) |
速度 | 慢(拥塞控制、握手开销) | 快(无控制开销) |
应用场景 | 文件传输、HTTP、邮件 | 视频流、DNS、实时游戏 |
关键差异解释:
TCP通过以下6大机制确保数据传输可靠:
Window字段告知剩余缓冲区大小,发送方据此调整发送速率(避免淹没接收方)。总结:TCP通过上述机制实现无丢失、无重复、无错误、有序的数据传输。
版本 | 核心改进 | 主要特性 |
|---|---|---|
HTTP/1.0 | 基础版本 | 短连接(每次请求新建TCP)、无Host头、无管道化 |
HTTP/1.1 | 解决1.0性能瓶颈 | 持久连接(Keep-Alive)、Host头(支持虚拟主机)、管道化(但队头阻塞未解决) |
HTTP/2 | 性能优化 | 二进制分帧、头部压缩(HPACK)、多路复用(解决队头阻塞)、服务器推送 |
HTTP/3 | 基于QUIC协议(UDP) | 0-RTT快速连接、传输层多路复用(彻底解决队头阻塞)、内置TLS 1.3加密 |
关键演进:
记忆口诀:
HTTP/1.1:持久连接省握手,Host区分虚拟节点。 HTTP/2:二部曲(二进制、头部压缩、乱序传输)。
操作系统的进程调度算法旨在高效分配CPU资源,核心算法包括:
优先级 = (等待时间 + 执行时间) / 执行时间)。评价指标:吞吐量、周转时间、响应时间、CPU利用率。
用户态和内核态是CPU特权级的两种模式,核心区别如下:
维度 | 用户态 | 内核态 |
|---|---|---|
特权级别 | Ring 3(低特权) | Ring 0(高特权) |
内存访问 | 仅限用户空间(不可访问内核内存) | 可访问全部内存空间 |
指令权限 | 禁止执行特权指令(如I/O操作、中断管理) | 可执行所有指令 |
稳定性 | 进程崩溃不影响系统 | 内核崩溃导致系统宕机 |
性能开销 | 常规代码执行 | 系统调用需上下文切换(约1μs~10μs开销) |
切换方式:
read())、中断或异常触发。示例:
read(file_fd, buffer, size); // 系统调用,触发切换至内核态
意义:隔离用户程序与内核,防止恶意操作破坏系统稳定性。
用户态切换到内核态主要通过以下三种方式触发,核心机制是CPU特权级的转换(从Ring 3切换到Ring 0)和上下文保存:
read()、write())主动请求内核服务。rax),参数存入rdi、rsi等寄存器。
② 执行syscall或int 80h指令,触发软中断,CPU切换到内核态(Ring 0)。
③ 内核保存用户态上下文(RIP、RSP、RFLAGS等寄存器值)到内核栈,跳转至中断处理程序。iret指令恢复用户态上下文。切换的底层步骤:
ss0和esp0)。关键点:
进程间通信(IPC)主要用于数据传输、资源共享或事件通知,分为以下五类:
方式 | 原理 | 适用场景 |
|---|---|---|
管道(Pipe) | 单向数据流,基于内核缓冲区,匿名管道仅用于父子进程,命名管道(FIFO)支持无关进程。 | 命令行工具链(如ls | grep) |
消息队列 | 内核管理的消息链表,进程通过唯一标识符读写消息,支持异步通信。 | 解耦生产者与消费者(如日志系统) |
共享内存 | 多个进程映射同一块物理内存,直接读写数据,需配合同步机制(如信号量)。 | 高性能数据共享(如大型矩阵计算) |
信号量 | 计数器,控制多进程对共享资源的访问(P/V操作),解决互斥与同步问题。 | 资源池管理(如数据库连接池) |
套接字(Socket) | 跨网络通信,支持TCP/UDP协议,适用于分布式系统。 | 客户端-服务器模型(如Web请求) |
对比与选择:
进程同步解决资源竞争与执行顺序问题,核心机制如下:
P()(等待)和V()(通知)操作控制资源访问。pthread_cond_wait)。同步问题的本质:
单例模式确保一个类仅有一个实例,并提供全局访问点,常用于资源管理(如配置、线程池)。
实现方式:
饿汉式:类加载时创建实例,线程安全但可能浪费内存。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return instance; }
}
懒汉式(双重检查锁):首次调用时创建实例,避免资源浪费。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
特点:
应用场景:
策略模式定义一组算法,封装每个算法使其可互换,让算法独立于客户端变化。
核心组件:
execute())。示例:支付系统
interface PaymentStrategy { void pay(int amount); }
class AlipayStrategy implements PaymentStrategy {
public void pay(int amount) { /* 支付宝支付逻辑 */ }
}
class WeChatPayStrategy implements PaymentStrategy {
public void pay(int amount) { /* 微信支付逻辑 */ }
}
class ShoppingCart {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) { this.strategy = strategy; }
public void checkout(int amount) { strategy.pay(amount); }
}
优势:
if-else)。适用场景:
图的遍历分为两类,特点对比如下:
算法 | 数据结构 | 遍历顺序 | 特点 | 应用场景 |
|---|---|---|---|---|
深度优先搜索(DFS) | 栈(递归) | 深度优先,一条路径到底 | 可能陷入深分支,空间复杂度O(V)(顶点数) | 拓扑排序、连通性检测 |
广度优先搜索(BFS) | 队列 | 层次优先,按距离扩展 | 可求最短路径(无权图),空间复杂度O(V) | 最短路径、社交网络关系 |
关键差异:
广度优先搜索(BFS)按层次遍历图,核心是队列管理和层级扩散,确保先访问的节点其邻接点优先访问。
算法流程:
特点:
应用场景:
性能优化:稀疏图使用邻接表存储,避免邻接矩阵的O(V²)遍历开销。