资讯详情

关于 Redis 锁与 MySQL 锁的苏格拉底式对话

📅 2026/11/4 11:52:40 | 华诺云谱 👁 阅读
关于 Redis 锁与 MySQL 锁的苏格拉底式对话
—— 关于 Redis 锁与 MySQL 锁的苏格拉底式对话人物苏格拉底Socrates探寻本质的提问者与架构哲人。年轻工程师Theaetetus崇尚现代技术、追求高并发性能的后端开发者。第一幕速度的幻觉年轻工程师苏格拉底我最近陷入了深深的困惑。在我们这个时代Redis 运行在内存之中单机便可吞吐十万请求快如闪电而 MySQL 还要寻道、刷盘、维护繁重的事务日志。在分布式系统里我们为什么不把所有的锁都换成轻盈的 Redis 分布式锁彻底告别沉重的 MySQL 呢苏格拉底告诉我泰阿泰德Theaetetus当你给自家门庭安上一把精巧的锁时你追求的究竟是“锁芯转动的速度”还是“门后金银的周全”年轻工程师自然是门后金银的周全。如果金银失窃转得再快的锁又与废铁何异苏格拉底那么在你的系统里什么才是真正的“金银”是那几行执行代码的速度还是账本上毫厘不差的账户余额年轻工程师是账户余额。若余额算错系统即便拥有百万 QPS也不过是更快地走向破产罢了。苏格拉底既然如此让我们来看看你那把“快如闪电”的 Redis 锁。它是凭借什么向你保证门后的金银绝对安全呢第二幕时间的背叛年轻工程师它依靠时间的契约。当我们向 Redis 申请一把锁时会通过SET NX EX刻下一段生存时间TTL比如三十秒。要么我们在三十秒内完成操作后用 Lua 脚本将锁焚毁归还要么时间一到Redis 会自动抹去它避免系统死锁。这难道不够完美吗苏格拉底听起来十分精巧。但请设想这样一个清晨你的代码刚刚从 Redis 手中接过这把锁正准备更改账户却突然遭遇了 JVM 严酷的垃圾回收停顿Full GC STW亦或是外部网络陷入了长久的静默。这一停顿恰恰耗去了三十一秒。告诉我在第三十一秒的瞬间Redis 里的锁还在吗年轻工程师……不在了。三十秒一过Redis 已经依约将它无声地抹去了。苏格拉底那么刚刚苏醒过来的那个线程它知道自己的锁已经被收回了吗它会停下手中即将落盘的写操作吗年轻工程师冷汗它……它感知不到Redis 不会跨越网络向正在运行的 Java 线程投掷一道闪电让它停下。线程对自己赤身裸体一无所知它会继续执行扣款苏格拉底而就在此刻另一个等待多时的线程走上前去看见 Redis 门扉虚掩于是也拿到了一把崭新的锁踏入了同一个房间。此时门后会发生什么年轻工程师两个线程同时在修改同一个账户原本用来保证绝对互斥的分布式锁在这一刻形同虚设苏格拉底所以你看泰阿泰德依赖“物理时间”作为安全界限的锁终究会被时间的波动所背叛。当锁在无声中消亡持有者却沦为失明之人。第三幕血缘与契约年轻工程师我明白了。但如果代码执行到一半抛出了异常——比如唯一键冲突、算术溢出、或者数据库断开连接——这时候 Redis 锁又会如何对待那些已经写到一半的数据呢苏格拉底它懂得什么是“回滚Rollback”吗年轻工程师不懂。它只是一方孤立的内存缓存根本不知道数据库里发生了什么灾难。苏格拉底那 MySQL 自己的行锁SELECT ... FOR UPDATE呢它的生命又是与何物绑定在一起的年轻工程师它的生命与**数据库事务Transaction**休戚与共。只要事务尚未COMMIT锁便如磐石般钉在数据行上一旦抛出异常触发ROLLBACK不仅锁会瞬间消解连同此前写入的一切半吊子数据都会被 Undo Log 彻底抹平不留一丝痕迹。苏格拉底一个是与数据毫无血缘、随时可能因超时而背信弃义的“外部信号”另一个是与数据骨肉相连、同生共死的“物理枷锁”。在守护真金白银的最终一刻你敢将身家性命全盘托付给谁年轻工程师我必须信任 MySQL。唯有它能让“锁”与“数据状态”在同一片土地上同生共死。第四幕连接池的悬崖年轻工程师既然如此苏格拉底我们干脆把所有的并发控制都统统交给 MySQL 吧让所有的请求都去争抢FOR UPDATE行锁岂不是万无一失苏格拉底莫急年轻人。告诉我在你们的国库数据库连接池里一共常备着多少名精壮的卫士Connections年轻工程师通常不过数十至多二三百人。苏格拉底现在假定一位富商要提取资产。你的卫士握住账本拿到了 MySQL 行锁但按照规矩他必须先派遣一只信鸽飞往大洋彼岸的远邦交易所Feign RPC 调用核实这笔交易的合法性。信鸽在海上逆风飞行整整耗去了十个呼吸的时间。在这十个呼吸里这位手握账本的卫士在做什么年轻工程师他必须霸占着这根珍贵的数据库连接什么也不能干只能在原地苦苦等待苏格拉底若在此时城中有一百位百姓同时涌来要求验核账目呢年轻工程师惊呼国库的卫士会被瞬间抽调一空所有的数据库连接在几秒内耗尽后来的百姓连最普通的查询都无法进行整座城邦的交易系统陷入了彻底的雪崩苏格拉底那么是谁杀死了这座城邦是并发太高还是有人在“不可脱身的重地”里做了“耗时漫长之事”年轻工程师是我我把需要跨洋通信的网络调用关进了 MySQL 锁的深闺之中在 DB 锁内做 RPC无异于引火自焚第五幕双重卫士的城邦年轻工程师老师我彻底迷茫了。Redis 锁快却会在超时中失明MySQL 锁稳却经不起哪怕一丝一毫的等待与网络延迟。难道在这世上竟没有两全之策吗苏格拉底泰阿泰德一个睿智的城邦是如何防范盗贼与维护安宁的是将所有的守卫都堆在国库的金库门前还是在十里之外的城门要塞便设立哨卡年轻工程师自然是在城门设立哨兵盘查可疑之徒而在金库门前另设重锁。苏格拉底善哉现在把这道城门与这座金库投射到你的代码之中它们分别是谁年轻工程师眼中闪过灵光城门上的哨兵正是 Redis 分布式锁它驻扎在业务的最外层以十万 QPS 的速度瞬间击退狂乱连击的重复请求。就算它需要守护长达数秒的跨洋网络调用RPC它也只会消耗几字节轻巧的内存绝不动用国库哪怕一滴水源DB 连接只要别人抢不到令箭立刻打发他离开Fail-Fast绝不阻塞城邦道路而金库门前的大锁正是 MySQL 的事务行锁与状态机只有那些穿过了城门、拿齐了外部文书、准备真正动账的请求才获准跨入内室。在短短两毫秒之内它落锁、记账、更新状态、释放一气呵成苏格拉底那如果……城门上的哨兵打了个盹Redis 锁超时穿透导致两个盗贼在同一刻溜进了内室呢年轻工程师内室的卫士依然威严即便两人同时潜入MySQL 的行锁依然会强迫他们排队即便排在后面的人侥幸拿到了锁我那冰冷的状态机条件WHERE status PROCESSING也会让他扑个空affected rows 0绝不给非法的二次动账留下一丝空隙苏格拉底妙极了。此时此刻你还认为 Redis 锁与 MySQL 锁是非此即彼的仇敌吗年轻工程师不它们从来不是对手。Redis 锁是哨兵守在外层以“闪电之速”阻挡重入护卫流程MySQL 锁是界石立于核心以“磐石之重”锚定数据捍卫底线。知其轻重内外相济方为架构之道。苏格拉底去吧泰阿泰德。去把这些刻进你的代码里。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑