Go 调度器 GMP:从 GM 模型到 work stealing
写一个 go func() {} 就能起一个轻量级任务,几 KB 栈空间就能并发成千上万个 goroutine。但这不是免费的魔法——Go runtime 在用户态实现了一整套调度器,把成千上万的 goroutine 映射到数量有限的 OS 线程上。这套调度器经历了一次伤筋动骨的重写:从 Go 1.0 的 GM 模型到 Go 1.1 引入的 GMP 模型,2012 年 Dmitry Vyukov 那份设计文档奠定了现在所有 Go 版本调度器的基础。
这篇文章想讲清楚:为什么不能直接用 OS 线程?P 到底是什么?调度循环长什么样?阻塞和抢占又是怎么处理的?
InnoDB 索引设计:从 B+ 树物理结构反推主键选择
新系统评审时,一个老问题总是反复出现:主键到底用自增 BIGINT 还是 UUID? 业务方觉得 UUID"全球唯一、便于跨库合并"; 工程师担心 UUID 让索引膨胀、查询变慢。两边各有道理,但讨论很快会陷入"看情况"的口水仗。
跳出具体业务,从 InnoDB 的 B+ 树物理结构反推,主键选择其实有清晰的规则可循——大多数争议是规则没讲透。
这篇文章想回答几个问题:B+ 树在 InnoDB 里到底是什么样子?为什么二级索引一定要"回表"?随机主键的代价在哪?前缀索引什么时候值得用?唯一索引允许多个 NULL 是 bug 还是 feature?
Redis 分布式锁与 Redlock 争议:Martin Kleppmann 的拷问
分布式锁是分布式系统的常见组件——秒杀、限流、任务调度都依赖它。Redis 因为性能好、部署简单,常被用来实现分布式锁。但是 Redis 单实例的锁正确吗?Redlock 多实例锁的算法真的安全吗?本文从 SETNX 出发,逐步剖析 Martin Kleppmann 在著名文章《How to do distributed locking》中对 Redlock 的拷问。
最简单的锁:SETNX + 过期
SETNX lock:order 1
EXPIRE lock:order 30这是 Redis 分布式锁的最朴素实现。但有一个致命问题:如果 SETNX 后客户端崩溃,EXPIRE 永远不会执行——锁永久不释放。
正确做法是用一条原子命令:
SET lock:order 1 NX EX 30NX 仅当 key 不存在时设置;EX 30 设置 30 秒过期。原子操作。
单实例 Redis 锁的局限
sequenceDiagram
participant C as Client A
participant R as Redis
participant C2 as Client B
C->>R: SET lock foo NX EX 30
R->>C: OK (获得锁)
Note over R: 主从切换!<br/>从节点晋升<br/>丢失锁记录
C2->>R: SET lock bar NX EX 30
R->>C2: OK (也获得锁)主从切换是单实例 Redis 锁的最大风险:
《绿皮书》:一段跨越种族的友谊,是如何用「钢琴」开始的
2018 年的《绿皮书》在第 91 届奥斯卡金像奖上斩获最佳影片、最佳原创剧本、最佳男配角三项大奖,成为当年最具话题性的电影之一。它改编自一件真实事件——1962 年黑人钢琴家 Don Shirley 与意大利裔白人司机 Tony Lip 的一段为期八周的深南巡演。
这部片最大的独到之处,是它对友谊的精确拆解:两个不同世界的人,是如何从互相轻视走向真正理解。
消息队列:Kafka 与 RabbitMQ 的设计哲学对比
面试常被问"消息队列用哪个"——但 Kafka 和 RabbitMQ 不是"谁替代谁"的关系,它们是两种完全不同的设计哲学:Kafka 是分布式日志,RabbitMQ 是智能交换机。
把 Kafka 当成"消息队列"用,就像把 Git 当成 SVN 用——能跑,但不是它擅长的方式。本文从设计哲学出发,彻底理解两者的差异。