

文件明明写成功了,断电后为什么还是丢了程序写文件已经返回成功,断电重启后数据为什么仍可能消失?这一集沿着应用缓冲区、Linux 页缓存、文件系统和存储设备,拆开“写入成功”“其他进程可见”和“真正持久化”的区别。 还会讲清 fsync、原子重命名、目录同步和文件系统日志,并给出可靠替换配置文件的完整操作顺序。 重点内容: - 普通写入为什么通常先进入页缓存 - 脏页和后台回写如何工作 - 写入成功为何不保证数据已经落盘 - fsync 与 fdatasync 有什么区别 - 原子重命名为什么不等于持久化 - 如何可靠地替换一个重要文件 英文词对照: - Page Cache:页缓存 - Dirty Page:脏页 - Writeback:后台回写 - Durability:持久性 - Metadata:元数据 - Partial Write:部分写入 - Atomic Rename:原子重命名 - File System Journal:文件系统日志 - Write-ahead Log:预写日志
程序为什么会突然栈溢出机器内存还有很多,程序为什么仍会栈溢出?这一集从一次递归遍历崩溃出发,讲清函数调用如何形成栈帧,以及调用深度、局部变量和线程栈大小怎样共同决定故障边界。 还会解释 Linux 的按需分配、保护页、段错误与备用信号栈,并给出环检测、深度限制和显式工作栈等实际修复方法。 重点内容: - 返回地址、局部变量为何占用栈空间 - 递归深度与单个栈帧大小的关系 - 主线程栈和工作线程栈有什么区别 - 保护页如何及时发现栈越界 - 为什么机器有空闲内存仍会崩溃 - 如何定位并修复栈溢出 英文词对照: - Stack:栈 - Stack Frame:栈帧 - Stack Overflow:栈溢出 - Return Address:返回地址 - Call Convention:调用约定 - Guard Page:保护页 - Segmentation Fault:段错误 - Recursion:递归 - Alternate Signal Stack:备用信号栈
为什么多线程反而更慢:锁竞争、上下文切换与缓存争用四个线程为什么可能比一个线程更慢?这一集从一个共享计数器出发,追踪互斥锁从用户态原子操作、缓存行争抢,到 Linux futex 等待和唤醒的完整路径。 还会区分锁竞争与伪共享,解释上下文切换、调度延迟和缓存变冷怎样放大成本,并给出分片计数、批量合并、缩小临界区等实际优化方法。 重点内容: - 无竞争加锁为什么通常不进入内核 - futex 如何让竞争线程等待和被唤醒 - 临界区很短为什么仍可能拖慢程序 - 原子加一为什么也存在扩展性上限 - 锁竞争与伪共享有什么区别 - 如何建立多线程性能排查的因果链 英文词对照: - Mutex:互斥锁 - Atomic Operation:原子操作 - Critical Section:临界区 - Lock Contention:锁竞争 - Futex:快速用户空间互斥机制 - Context Switch:上下文切换 - False Sharing:伪共享 - Cache Line:缓存行 - Spin:自旋 - Thundering Herd:惊群
一段代码是怎样被 CPU 执行的点击运行程序之后,源代码并不会直接进入 CPU。操作系统需要创建进程、映射可执行文件,CPU 才能从入口地址开始读取并执行机器指令。 这一集沿着一段程序的真实执行路径,讲清指令、寄存器、流水线、缓存、分支预测和进程调度如何协作,以及为什么 CPU 很忙不等于程序正在高效工作。 重点内容: - 源代码如何变成机器指令 - Linux 如何装载可执行文件并按需读取页面 - CPU 如何取指、译码和执行 - 乱序执行为什么不会打乱程序结果 - 缓存未命中为什么会让 CPU 等待 - 分支预测错误为什么代价昂贵 - 多个程序如何轮流使用 CPU - 如何用 perf 理解周期、指令和缓存未命中 英文词对照: - Machine Instruction:机器指令 - Program Counter:程序计数器 - Register:寄存器 - Pipeline:流水线 - Out-of-order Execution:乱序执行 - Cache Miss:缓存未命中 - Branch Prediction:分支预测 - Context Switch:上下文切换 - Instructions Per Cycle:每周期执行指令数
同一条查询为什么突然变慢:执行计划与统计信息代码没有发布、索引也没有删除,同一条查询为什么会从几十毫秒突然变成几秒?常见原因是数据分布发生变化,优化器基于估算选择了另一条执行路径。 这一集讲清数据库优化器如何估算成本、统计信息为什么会失真,以及排查慢查询时如何比较“预计读取多少行”和“实际读取多少行”。 重点内容: - SQL 文本与执行计划为什么不是一回事 - 优化器如何比较不同访问路径的成本 - 选择性和数据倾斜如何影响索引价值 - 统计信息过期为什么会选错计划 - 普通执行计划与实际执行分析的区别 - 为什么强制索引只适合作为谨慎的临时手段 - 查询突然变慢时应保存哪些现场信息 英文词对照: - Query Optimizer:查询优化器 - Execution Plan:执行计划 - Cardinality:基数估计 - Selectivity:选择性 - Histogram:直方图统计 - Data Skew:数据倾斜 - EXPLAIN ANALYZE:实际执行分析 - Index Hint:索引提示
连接池满了,为什么整个服务都在排队数据库本身看起来还能响应,应用却大量超时,日志里不断出现“获取连接超时”。连接池耗尽往往不是根因,而是慢查询、长事务或连接泄漏把有限连接长期占住后的结果。 这一集从一次服务雪崩出发,讲清请求线程、连接池和数据库连接之间如何排队,以及为什么盲目增大连接池可能让故障更加严重。 重点内容: - 连接池解决了什么问题 - 请求拿不到连接时究竟在等待什么 - 慢查询和长事务如何耗尽连接池 - 连接泄漏为什么会缓慢积累后突然爆发 - 为什么连接数越多不一定吞吐越高 - 超时、限流与故障扩散之间的关系 - 如何从应用和数据库两端定位连接池问题 英文词对照: - Connection Pool:连接池 - Connection Timeout:获取连接超时 - Maximum Pool Size:连接池最大连接数 - Connection Leak:连接泄漏 - Queueing:排队 - Backpressure:背压 - Fail Fast:快速失败 - Little's Law:利特尔法则
长事务为什么会拖慢数据库:MVCC 与版本清理一个只执行查询、没有锁住业务行的事务,为什么也可能让数据库空间上涨、查询变慢?因为它保留的旧快照,可能迫使 InnoDB 长时间保存大量历史版本。 这一集从报表任务忘记提交的场景出发,讲清一致性读、读视图、撤销日志和后台清理如何协作,以及长事务为什么会把版本链越拖越长。 重点内容: - 普通查询如何在不阻塞更新的情况下读取旧版本 - 读视图如何判断某个版本是否可见 - 撤销日志为什么既用于回滚,也用于一致性读 - 长事务如何阻止历史版本被清理 - 版本链变长为什么会增加读取成本 - 为什么只读事务也应及时结束 - 如何发现并治理长期未提交事务 英文词对照: - MVCC:多版本并发控制 - Consistent Read:一致性读 - Read View:读视图 - Undo Log:撤销日志 - Version Chain:版本链 - Purge:历史版本清理 - History List Length:历史列表长度 - Long-running Transaction:长事务
数据库更新为什么会卡住:行锁、范围锁与死锁一条只更新一行订单的语句,为什么会等待几十秒?问题通常不在语句执行得慢,而在它需要的锁被另一个尚未结束的事务占着。 这一集从真实的订单更新超时出发,讲清 InnoDB 实际锁住的是索引记录和索引范围,索引缺失为什么会扩大加锁范围,以及锁等待与死锁应当如何定位和处理。 重点内容: - 更新语句为什么需要排他锁 - 行锁为什么本质上锁在索引记录上 - 缺少索引如何扩大扫描和加锁范围 - 记录锁、间隙锁与临键锁分别保护什么 - 锁等待和死锁有什么区别 - 为什么死锁事务必须允许重试 - 如何定位阻塞者,而不是只处理等待者 英文词对照: - Record Lock:记录锁 - Gap Lock:间隙锁 - Next-Key Lock:临键锁 - Exclusive Lock:排他锁 - Lock Wait:锁等待 - Deadlock:死锁 - Blocking Transaction:阻塞事务 - Lock Wait Timeout:锁等待超时
数据库索引为什么能加速查询索引为什么能让数据库快速找到记录?关键不只是减少比较次数,而是利用有序结构减少需要访问的数据页面。 这一集结合 InnoDB 的现实实现,讲清 B 树索引、聚簇索引、普通索引、回表和覆盖索引之间的关系,以及为什么数据库明明有索引,却仍可能选择全表扫描。 重点内容: - 索引如何减少页面读取 - B 树为什么适合数据库索引 - 聚簇索引与普通索引分别保存什么 - 回表为什么可能让查询变慢 - 覆盖索引如何减少页面访问 - 为什么数据库有时主动放弃索引 - 主键长度为什么会影响所有普通索引 英文词对照: - Index:索引 - B-tree:B 树索引结构 - Clustered Index:聚簇索引 - Secondary Index:二级索引或普通索引 - Covering Index:覆盖索引 - Full Table Scan:全表扫描 - Query Optimizer:查询优化器 - Execution Plan:执行计划 - Page Split:页面分裂
事务已经提交,数据页没落盘为什么仍能恢复后端随身听|事务已经提交,数据页没落盘为什么仍能恢复 事务提交成功时,InnoDB 通常不需要立刻把所有修改后的数据页写回数据文件。那机器突然断电后,数据库为什么还能恢复已提交的数据? 这一集从缓冲池和脏页开始,讲清 InnoDB 如何通过预写日志、重做日志、检查点和后台刷页实现崩溃恢复,并区分撤销日志、二进制日志与双写缓冲各自解决的问题。 重点内容: * 为什么事务提交不直接等待数据页落盘 * 缓冲池、脏页和重做日志如何协作 * 写入文件与真正刷盘有什么区别 * 检查点如何限制崩溃恢复范围 * 重做日志、撤销日志和二进制日志的职责区别 * 双写缓冲如何处理数据页只写一半 * 组提交如何降低刷盘成本 英文词对照: * InnoDB:MySQL 常用事务存储引擎 * Buffer Pool:缓冲池 * Dirty Page:脏页 * Redo Log:重做日志 * Undo Log:撤销日志 * Binary Log:二进制日志 * Write-Ahead Logging:预写日志 * Checkpoint:检查点 * Doublewrite Buffer:双写缓冲 * Group Commit:组提交
消费者明明处理成功了,消息为什么还会重复后端随身听|消费者明明处理成功了,消息为什么还会重复 消费者已经成功增加积分,为什么同一条消息还会再次出现?这一集从消息队列基础概念讲起,对照 RabbitMQ 的消费者确认与 Kafka 的消费偏移量,解释重复消息真正发生的时间窗口。 重点内容: * 生产者、消息代理、队列、消费者分别做什么 * RabbitMQ 的交换器、队列、手动确认和预取数量 * Kafka 的主题、分区、消费者组和偏移量 * 至少一次、至多一次、恰好一次分别意味着什么 * 为什么业务成功后仍可能重复投递 * 如何使用业务唯一标识、数据库事务和唯一约束实现消费幂等 英文词对照: * Producer:生产者 * Consumer:消费者 * Broker:消息代理 * Queue:队列 * Exchange:交换器 * Acknowledgement:确认 * Topic:主题 * Partition:分区 * Consumer Group:消费者组 * Offset:偏移量 * Idempotency:幂等 * Dead Letter Queue:死信队列
虚拟内存:申请 1GB,为什么没有立刻占用 1GB后端随身听|虚拟内存:申请 1GB,为什么没有立刻占用 1GB 程序申请了一大块内存,为什么机器的可用物理内存没有立刻减少同样大小?这一集从这个反直觉问题出发,讲清虚拟地址、页表、按需分页和缺页异常之间的关系。 重点内容: * 申请成功、实际访问和物理内存占用为什么不同 * 页表如何把虚拟地址映射到物理页 * 缺页异常为什么不一定是程序错误 * 每页只写一个字节,为什么仍可能占用整页内存 * TLB 未命中和缺页异常有什么区别 * 换页、主要缺页和 OOM 如何影响服务 英文词对照: * Virtual Memory:虚拟内存 * Physical Memory:物理内存 * Page Table:页表 * Demand Paging:按需分页 * Page Fault:缺页异常 * MMU:内存管理单元 * TLB:地址翻译高速缓存 * Copy-on-Write:写时复制 * Swap:交换空间 * OOM:内存耗尽
一次请求是怎么到后端的后端随身听|一次请求是怎么到后端的 用户说“页面打不开”或“接口很慢”时,问题不一定出在业务代码里。这一集沿着一次请求的完整链路,讲它如何经过域名解析、连接建立、HTTP 请求、入口层、应用服务、缓存、数据库和下游依赖,最后返回给用户。 重点内容: * 为什么后端日志里没有请求 * 为什么登录态会丢 * 为什么用户真实 IP 会变成代理地址 * 为什么超时和重试可能导致重复下单 * 如何沿着请求链路排查慢请求 英文词对照: * DNS:域名系统 * TCP:可靠连接协议 * TLS:加密通信协议 * HTTP:请求与响应协议 * Cookie:浏览器保存的登录相关数据 * Nginx:反向代理和负载均衡服务器 * Gateway:网关 * Idempotency:幂等,重复执行也不产生重复结果 * Trace:链路追踪
接口超时,到底是谁在等谁后端随身听|接口超时,到底是谁在等谁 用户看到接口失败,后端却显示处理成功,这是怎么回事?这一集从“提交订单超时后重复下单”的场景讲起,拆解客户端、Nginx、应用服务和下游依赖之间的等待关系。 重点内容: * 连接超时、读取超时、写入超时有什么区别 * 为什么用户失败了,服务端可能还在继续处理 * 504 网关超时和 408 请求超时的方向差异 * 超时为什么会牵出重试、幂等和重复下单 * 排查超时时应该看哪些日志和指标 * 为什么长任务更适合异步处理 英文词对照: * Timeout:超时 * Connect Timeout:连接超时 * Read Timeout:读取超时 * Retry:重试 * Idempotency:幂等 * 504 Gateway Timeout:网关等上游服务超时 * 408 Request Timeout:服务端等客户端请求超时 * Trace:链路追踪 * Span:链路中的一段调用 * Circuit Breaker:熔断
Redis Cluster:分片、槽位和扩容单集简介 EP08|Redis Cluster:从单机走向分片 这一集是 Redis 系列收尾,讲 Redis Cluster。当前面的单机或主从架构放不下数据、扛不住写入时,Cluster 通过分片把 key 分散到多个主节点上,扩展容量和吞吐。 我们会讲为什么需要分片,槽位是什么,客户端如何找到正确节点,扩容时为什么要迁移槽位,多 key 操作为什么会受限制,以及 Cluster 和哨兵的区别。也会提醒:Cluster 不是透明无限扩展,热点 key、多 key 设计、客户端支持和运维复杂度都需要提前考虑。 英文术语对照 Redis Cluster(Redis 集群)、sharding(分片)、hash slot(哈希槽/槽位)、resharding(重新分片/槽位迁移)、MOVED redirection(永久重定向)、ASK redirection(迁移期间临时重定向)、hash tag(哈希标签)、primary node(主节点)、replica node(从节点)、failover(故障转移)、multi-key operation(多 key 操作)、hot key(热点 key)。 参考资料:Redis 官方 Scale with Redis Cluster、Redis cluster specification、CLUSTER SETSLOT。