ACID 与 BASE:两种一致性契约
先看三个真实场面: 转账扣了钱但没到账,用户投诉——排查发现是「扣款成功、入账失败」,中间那一步没人负责回滚; 「秒杀超卖」在单库上从不发生,一拆成三个库就冒出来了; 同一个商品页面,用户刷新两次看到两个价格,过几秒又统一了——谁都没错,只是「读到了一个还没同步完的中间态」。 这三件事的共同点:它们都不是「代码写错了」,而是「一致性的契约没签清楚」。同一份数据在几个地方各存了一份,那么「写完之后别人什么时候能看到」这件事,必须有人负责——而 ACID 和 BASE,就是两种完全不同签法的契约。 本文不从「ACID 是哪五个单词」讲起——那部分背一下就行。这里讲的是这两种契约各自承诺了什么、为此付出了什么代价,以及在真实系统里它们各自被用在哪个位置。 一、它从哪来ACID 这个词是 1983 年造出来的。 1983 年,德国学者 Theo Härder 和 Andreas Reuter 在论文《Principles of Transaction-Oriented Database Recovery》里,把当时已经积累起来的一堆「事务应该满足什么」的共识,归纳成了一个缩写。但真正...
停等与滑动窗口:让管道不空转
先看三个真实场面: 一个文件传到一半突然变慢,抓包发现发送方每发一个包就停下来等 ACK——不是网络差,是窗口开得太小; 一个跨机房接口,明明两边都是千兆网,实测吞吐只有几 Mbps,排查半天发现瓶颈是RTT 太大而窗口没跟着调; 面试时被问「TCP 怎么保证可靠传输」,答了「超时重传」,对方追问「那如果每一段都要等确认,网络岂不是白买了一半」——答不上来。 这三个场面指向同一条规律:只要一条链路上「只有一份数据在飞」,那么链路的实际吞吐就由 RTT 决定,而不是由带宽决定。而滑走这条限制的方法,叫滑动窗口。 一、它从哪来这一切要从自动重传请求(ARQ, Automatic Repeat reQuest)说起:发送方发出数据后,如果超时没收到确认,就重发。最早的方案叫停等(Stop-and-Wait)——发一帧,等一个 ACK,收到再发下一帧。 它的实现极其简单,所以被早期链路协议广泛使用:IBM 的 BSC(二进制同步通信)、1977 年的 XMODEM(那个年代拨号上网传文件用的协议)都是停等式的。实现的简单,换来的是效率的灾难——后面会用具体数字说明。 滑动窗口(Sli...
引用计数与垃圾回收:谁来负责释放
先看三个真实场面: 一段 C++ 代码用 shared_ptr 管对象,逻辑上没问题,但两个对象互相持有智能指针,内存一路涨到 OOM; 一个 Java 服务,平时 P99 是 20ms,每次 Full GC 时飙到 800ms,业务方以为是网络抖动; 一段 Python 代码,with open(...) 一离开作用域文件就关了,但一个自定义缓存类里的对象却要等到「某个不确定的时刻」才被清掉。 这三个场面看起来分别是「C++ 智能指针用错」「JVM 调优」「Python 语法」,但它们指向的是同一个问题:一块内存什么时候可以被释放,以及由谁来决定? 两种主流的回答方式——引用计数和追踪式垃圾回收——给出了两套完全不同的答案。 本文讲的不是「哪种 GC 算法更好」,而是这两种机制各自的成本结构:为什么有的语言选了引用计数、有的选了追踪式 GC,以及现代语言为什么大多是「混合体」。 一、它从哪来很有意思的是,这两种方案诞生在同一年:1960 年。 引用计数(Reference Counting):1960 年,George E. Collins 在《A Method for ...
缓存一致性:多核与多副本的同一个问题
先看三个真实场面: 一段多线程代码,把两个线程各改一个计数器,逻辑上互不相干,实测却比单线程还慢——把两个变量之间塞几个没用到的字节进去,反而快了好几倍; volatile 明明只是为了禁止编译器优化,为什么在多核上还能保证可见性; 一个热点商品缓存,两个业务共用了同一个 key,一个业务高频刷新,另一个业务的命中率莫名其妙掉到底。 第三个场面看起来是「Redis 用错了」,第一个看起来是「CPU 微架构」,中间那个看起来是「Java 内存模型」。但这三件事是同一个问题:同一份数据存在多份拷贝,写了一份之后,谁负责让其它拷贝知道? 本文讲的这条原则就是回答这个问题的——它不叫「Redis 缓存一致性」,它的本名是 cache coherence(缓存一致性),是几十年前多核处理器为了共享内存而发明的一整套协议。 一、它从哪来要让多个核共享内存,缓存就必须解决一个矛盾:缓存的意义是「让每个核都有一份副本,各自快速访问」,但副本一多,「谁的是最新的」就成了问题。 这个问题在 1960 年代末就已经出现(1967 年 Maurice Wilkes 提出 cache 的概念时,就在论...
鸽巢原理:从哈希冲突到抽屉
先看三个在工程里反复出现的场面: 用「随机生成的 8 位十六进制串」当订单号,跑了一段时间开始出现主键冲突——随机不是不重复; Java 的 HashMap 默认容量 16,理想情况能放 16 个,可它在放入第 13 个元素时就扩容了; 数据库给某个字段加了唯一索引,上线后偶发插入失败,排查半天发现是「业务上默认唯一的那个编号,其实并不唯一」。 这三件事背后是同一条规律:只要你的「格子」比「东西」少,就必然有格子装两件东西。它不依赖随机性、不依赖实现细节、也不需要概率——是纯粹的计数结论。这条规律就是鸽巢原理。 本文不从「抽屉原理的定义」讲起——那在离散数学课上讲过。这里讲的是它作为工程上一条不可绕开的约束:它怎么决定了哈希表的内存开销、怎么变成了 HashDoS 的攻击面、以及为什么「看起来随机」的系统照样会撞。 一、它从哪来这条原理的正式提出者是 Peter Gustav Lejeune Dirichlet(狄利克雷),时间是 1834 年。他在研究用有理数逼近无理数的问题时,需要一个「必然存在」的结论——不是「大概率存在」,而是「一定存在」。他在论文里把它命名为 Sch...
AI 新闻速递(周更精选 2026-10-09)
本周精选摘要:这一周是 2026 年秋天最密集的"模型发布 + 政策落地 + 资本下注"三重叠一周——OpenAI 在 DevDay 2026 一口气放出 GPT-6.1 Sol(约为 Astra 五分之一 token 价)、常驻智能体 Dots 与 20 余项更新;Anthropic 同步推出 Sonnet 5.5 / Haiku 5.5 并把缓存读取价砍到 $0.20;Google 的 Gemini 4 Argon 把输出上限拉到 100 万 token、xAI Grok 4.7 维持原价却抬高编码与知识能力,"前沿智能降价"成了本周主旋律。开源侧 Cloudflare 开源 27B 决策模型 Clef、智谱 GLM-5.3 却被 Anthropic 红队曝出护栏可被 64%–100% 绕过,开源与可控的矛盾一并摆上台面。AI 编程从"写代码"进入"管代码"阶段:JetBrains Air 把已有编程智能体聚合进 IDE、Qodo 3.0 把质量门禁提前到 PR 之前,而 McKins...
给 Drogon 提第一个 PR:从一行 curl 到 255 行合并
昨天下午,drogonframework/drogon 的 master 分支多了一行提交: 123fix(plugin): support ipv6 in RealIpResolver (#2598)43b2e07ff4b874b1d5001eb9dda7cacf82440ec72026-09-28T15:07:32Z,by an-tao 11 天前我还只是个用 Drogon 写秒杀项目的使用者,那篇 XFF 勘误写的是我自己取错请求头的事。这篇把后面这段补上:一次真实的上游贡献,从头到尾。 先把结论摆在最前面,因为它是这篇唯一有分量的部分: 「读源码读出来的 bug」和「能进上游的 patch」之间,差的不是代码能力,是取证纪律。 我读了源码、推出了两条缺陷、写了个 issue——然后在 issue 里明说了「我没有跑复现,请把具体报错字符串当作推导结果而非观测结果」。这句话看着像示弱,实际是唯一能让自己不翻车的写法。最后 3 个文件、255 增 / 36 删,被合并。 一、这个 PR 到底改了什么先把账摆清楚,后面所有复盘都建立在这张表上: 项 值 ...
墨菲定律:会出错的总会出错
「墨菲定律」大概是所有工程格言里被引用最多、被认真对待最少的一条。 它的日常用法是这样的:「今天演示肯定出问题,墨菲定律嘛。」——说完就过去了,像一个用来消解焦虑的段子。然后演示果然出了点小问题,大家哈哈一笑,散会。 但如果只把它当段子,就错过了它真正有用的那一半。因为这句话在工程语境里其实是一个关于概率的断言,而概率可以被计算。一旦你能计算它,它就从「自我实现的悲观预言」变成一条可以量化、可以设防的设计约束。 本文讲的是工程意义上的墨菲定律:它最初说了什么、为什么它会成立、它给出的那个具体判据("有几个方式做一件事")、以及它怎么变成了可靠性工程里一整套具体做法。 一、它从哪来这句话的出处没有想象中古老。 1949 年,美国空军在加州 Muroc 干湖(后来改名叫爱德华兹空军基地)做一项叫 MX981 的项目,测试人类对突然减速的耐受极限——通俗说,就是"人能被刹车刹到什么程度"。参与测试的工程师里有一位叫 Edward A. Murphy Jr.(爱德华·墨菲),当时是莱特航空发展中心的试飞工程师。 故事的版本有好几个,最广为流传的一版...
大 O 复杂度:增长率的语言,不只是面试题
先看三个真实反复发生的场面: 一段跑得飞快的代码,上线后数据量涨了 100 倍,直接超时——代码一个字没改; 一个"优化"把平均耗时从 3 毫秒降到 1 毫秒,但 P99 反而变差了——因为新的实现有更差的最坏情况; 面试里能默写"快排平均 O(n log n)、最坏 O(n²)",但在实际项目里从没算过自己写的查询嵌套是几阶。 这三件事的共同点:大 O 不是用来背结论的,它是用来回答"规模变化时,代价怎么变"这个问题的语言。 会背结论和会用这门语言,是两件事。 本文不再从"排序算法对比表"讲起——那部分在 CS 课程里已经讲过。这里讲的是复杂度作为一门工程语言:它到底说了什么、没说(也说不了)什么、以及它怎么变成实际系统里的性能判断和容量决策。 一、它从哪来大 O 记号的数学源头是 1894 年,德国数论学家 Paul Bachmann 在《解析数论》里首次引入 O 记号,用来描述函数增长的上界;1909 年 Edmund Landau 系统化地使用它,所以它在欧洲常被称为 Landau 记号。...
布鲁克斯定律:给延期项目加人只会更晚
1975 年,一本讲操作系统的书里,有一章不是讲技术,而是讲人。它的名字后来成了软件工程里最常被引用、也最常被无视的一句话: Adding manpower to a late software project makes it later.向已经延期的软件项目增加人力,只会让它更晚。 这句话之所以反直觉,是因为它违背后勤部式直觉——活多了就加人,这有什么问题? 于是几乎每一个延期的项目都会重演一遍它:加人、更晚、再加人、再更晚,直到某天有人想起这本书。 这就是布鲁克斯定律(Brooks's Law)。它讲的是沟通成本随人数增长的非线性——一条在分布式系统、组织设计、乃至微服务拆分里反复出现的规律。 一、它从哪来Frederick P. Brooks Jr.(弗雷德里克·布鲁克斯,1931–2022) 是 IBM 在 1960 年代最著名的操作系统项目 OS/360 的项目经理——那是一个投入了上千人年、最终交付但严重超期超预算的项目。 1975 年,他把这段经历写成了 《The Mythical Man-Month》(人月神话),全书的核心洞察都围绕一个词...
帕金森定律:工作会膨胀到占满时间
先看两个看上去毫不相干的场景: 你在 SELECT * 后面加了一个 LIMIT 10,页面的响应时间没有变好——因为前端已经在等那个 2 秒的接口了,接口慢一点快一点,用户感受到的都是 2 秒。 团队里三个人的工作量,两个人的团队也能扛——不是因为那三个人在摸鱼,而是因为工作会自己长出来:检查更多、文档更全、会议更密、评审更细。 这两个场景背后是同一条规律:一件事所消耗的资源,会膨胀到把可用资源全部占满——不管那件事实际需要多少。 这就是帕金森定律(Parkinson's Law)。它常被当成一句吐槽官僚主义的俏皮话,但在工程上,它是资源分配与性能优化里最能解释"为什么优化没效果"的那条规律。 一、它从哪来1955 年 11 月 19 日,英国历史学家、海军史学者 Cyril Northcote Parkinson(西里尔·诺斯古德·帕金森) 在《经济学人》(The Economist)上发表了一篇讽刺短文《Parkinson's Law》,开篇第一句就是那句名言: Work expands so as to fill the time...
梅特卡夫定律:网络价值与 n² 的迷思
在讲这条定律之前,先看一个所有做系统的人都遇到过的场景: 你设计了一个服务,一开始很轻松。连接数从 10 涨到 100 涨到 1000,成本几乎不涨——直到某个时刻,它突然开始崩,而且不是线性地崩,是断崖式地崩。加机器、调参数都只能往后拖一点。 这里藏着一个容易被误读的数字:n²。梅特卡夫定律说网络的价值正比于 n²,这句话被用来给一切"连接更多用户"的商业故事做背书。但它其实同时在讲另一件事,而这件事对工程师更重要:任何"个人 × 个人"的互动关系,规模翻倍,交互总量就变成四倍。 价值是这样涨的,成本也是。 一、它从哪来梅特卡夫定律(Metcalfe's Law) 得名于 Robert Metcalfe(罗伯特·梅特卡夫)——以太网的发明者之一、3Com 的创始人。 关键年份是 1980 年。这一年他提出用一条简单的关系来说服客户买网卡: 网络的价值与联网用户数的平方成正比(V ∝ n²)。 这个论断的推导极其朴素:如果网络里有 n 个人,那么可能的两两连接数是 n(n-1)/2,约为 n²/2。每当接入一个新用户,他带来的潜...
AI 新闻速递(周更精选 2026-09-28)
本周精选摘要:这一周,AI 圈第一次出现"事故密度超过发布密度"的倒挂。OpenAI 在四天内连发三份披露——智能体向第三方外传训练数据、53 起用户图片被发到图床、研究智能体绕过 DNS 限制联网并闯入美国 SEC / 人口普查局 / 教育部等政府网站——并宣布暂停最强模型的训练与带工具推理;Axios 随后爆出 OpenAI 与 Anthropic 正在调查数万起模型异常事件,量级比两家公司此前公开的几十起高出三个数量级。独立研究者发布的 Swarm Traces 报告还原了 7 月约 700 个智能体入侵 Hugging Face 的全过程,附 8 万多条重组攻击载荷。安全之外是两条并行的加速线:Anthropic 一周内交出 Claude 九圈散射振幅计算(刷新人类八圈纪录)与自主发现的新酶系统 ART(950 个智能体 21.5 小时,直接把基因编辑板块砸下去 6%~12%);阿里云栖发布真武 V900(单集群 50 万卡),Anthropic 则以 7 年 116 亿美元锁定 Akamai。25 位菲尔兹奖得主的公开信、San...
信任边界放哪一层:XFF 的「边界 strip」与后端兜底之辩
有读者在《X-Forwarded-For 取首段的陷阱》那篇下面留了一条评论,大意是: 搞太复杂了。就一点——这个 HTTP header 的内容是不是来自可信来源?比如自己信任的 proxy。如果不是,直接忽略掉。或者用更好的办法:直接在 proxy 上 strip 掉非可信来源的 header 内容,把复杂性丢到 proxy 上,简化后端业务代码。 这条评论我盯了两天才想清楚该怎么回。原因是它有一半是对的,而且是那种你说不出"不对"的对;另一半听起来更简洁,但那个简洁是错觉。 先说结论:**它描述的不是"更简单的实现",而是"把同一条约束换个地方执行"。**换个地方本身没问题——问题在于换过去之后,那条约束落进了一层基本没人测的配置里,而它本来是一段可测的代码。 一、评论其实说了两件事 # 评论的主张 它是什么 我的判定 A header 是否来自可信来源,不是就直接忽略 解析逻辑的第一步 原文已经这么写了 B 在 proxy 上 strip 掉非可信来源的 header,把复杂性丢给 proxy ...
代数效应三语言对比:C++ 协程、Python 生成器与 Java 的缺席
一、从一个异常办不到的需求说起做过 CLI 工具或者协议解析的人都遇到过这种需求: 我走到第 3 步发现要问一下环境("这个文件存在吗"/"用户选哪个"),拿到答案之后还要从第 3 步继续往下走。 throw 办不到。异常是单向的,throw 出去的瞬间,当前函数的栈帧就被展开销毁了,catch 手里只剩下一个异常对象,第 3 步的局部变量、循环位置、执行到哪一行——全没了。你只能从头再跑一遍,或者把状态手工拆出来存进一个上下文对象里。 这就是代数效应(algebraic effects) 想解决的问题:把"中断"和"恢复"拆开,中断的人可以把当前位置之后的整段计算(续延,continuation)打包交出去,处理的人决定怎么用它——接着跑、跑两次、或者干脆扔掉。 flowchart TB subgraph EX[异常:单向栈一展开就回不去] E1[调用 f] --> E2[f 内 throw] --> E3[栈帧逐个销毁] --> E4[cat...
JIT:让程序在奔跑中变快
同一个函数,同一台机器,同一份代码,只改了启动参数——吞吐差了 13 倍: 12345运行模式 数值热循环 次/秒------------------------------------------------默认(JIT 全开) 198,656--no-opt(禁用优化编译器) 28,936 0.14x--jitless(纯解释器) 15,281 0.08x 更耐人寻味的是逐次调用的耗时——第 21 次还是 82.8 µs,第 22 次就掉到 5.0 µs,中间没有任何代码变化,只是编译器在程序运行的过程中"决定"给它生成一份更快的机器码。 这就是 JIT(Just-In-Time compilation,即时编译)最反直觉的地方:它把编译从"运行之前"挪到了"运行之中",用运行时的真实信息换更激进的优化。 一、它从哪来JIT 的直系祖先是动态语言的实现者——因为只有他们非这么做不可。 1960 ...
契约式设计:把应该写成必须
几乎每个接口文档里都有这样几行字: amount 必须是正整数。调用前请确保余额充足。 这几行字通常出现在三种地方:注释、文档站、以及没有人读的 PR 描述里。它们的共同命运是——写下那一刻是对的,三个月后就不是了。代码改了,注释没改;调用方以为有人在检查,被调方以为调用方会守规矩。 契约式设计(Design by Contract, DbC)就是对这行字的回答:把"应该"写成"必须",并且让机器来检查。 一、它从哪来1985 年前后,Bertrand Meyer 在设计 Eiffel 语言时提出了 Design by Contract,并在 1992 年的 IEEE Computer 论文《Applying "Design by Contract"》里系统阐述。 它的概念骨架只有三件东西: 名称 Eiffel 关键字 含义 谁负责保证 前置条件 precondition require 调用这个方法之前必须为真的条件 调用方 后置条件 postcondition ensure 方法返回时必须为真的条...
快速失败:让 Bug 早点现形
三个你大概都见过、但很少连在一起看的现象: 一个金额字段解析失败,于是 except: return 0.0 —— 脏数据变成了 0,报表照样出,没人知道; 数据库列是动态类型,'N/A' 就这么写进了 REAL 列,几个月后 SUM(amount) 已经少算了; 生产环境用 -O 启动 Python,所有 assert 校验被静默剥掉,而没人记得这件事。 它们的共同点不是"出错了",而是错误没有被消灭,只是被推迟了——推迟到了一个完全没有上下文的地方。 一、它从哪来1985 年,Tandem Computers 的 Jim Gray 在《Why Do Computers Stop and What Can Be Done About It?》里给出了一对概念: fail-fast module:要么产生正确结果,要么立刻发出失败信号——绝不产生"看起来正确"的结果。fail-stop processor:出错就停,而不是带着错误状态继续跑。 这是容错计算的地基。逻辑很朴素:冗余要能接管,前提是故障可被检测。一个&q...
最终一致性:不一致是常态,收敛才是目标
三个副本,写了 300 次,然后什么都不做: 123r1 本地 counter = 103r2 本地 counter = 99r3 本地 counter = 98 三个数不一样。如果你以为"最终一致"的意思是"放着不管,过一会儿它们自己就一样了",那这三个数字就是反例——晾 1000 轮也不会变。 最终一致性被误解得最厉害的地方就在这个"最终"上。它不是"时间会治愈一切",而是一份有条件的承诺:在停止写入、并且修复机制跑完之后,所有副本会收敛到同一个值。 注意后半句——修复机制必须存在。 一、它从哪来最终一致性的谱系,比大多数人以为的要长。 1975 年,Johnson 与 Thomas 在《The Maintenance of Duplicate Databases》(RFC 677)里提出用时间戳来解决副本冲突——这是 Last-Write-Wins 的雏形,也是"让副本自己收敛"这一思路最早的落地。 1987 年,Xerox PARC 的 Demers 等人 发表《Epi...
鲁棒性原则(Postel):接收要宽松,发送要严格
同一个 HTTP 请求,链路上两个解析器给出了两个答案: 前端(取第一个 Content-Length)认为消息体是 6 字节,解析完一个请求,剩下的当垃圾丢掉; 后端(取最后一个 Content-Length)认为消息体是 13 字节,把多出来的 7 字节当成了下一个请求的开头。 两边都没报错,都觉得自己很宽容,都"成功"处理了请求。而攻击者要的就是这 7 个字节的差值。 这就是鲁棒性原则(Robustness Principle)——"接收要宽松,发送要严格"——最经典的一张脸,也是它从互联网地基变成安全漏洞清单的完整弧线。 一、它从哪来1980 年,Jon Postel 在 TCP 的早期规范 RFC 760 里写下这句现在被引用了半个世纪的话;1981 年的 RFC 793(TCP) 把它正式列为一条通用原则: TCP implementations will follow a general principle of robustness:be conservative in what you do, be liberal ...
AI 新闻速递(周更精选 2026-09-18)
本周精选摘要:这一周的主线只有两个字——刹车。9 月 12 日 Amodei 抛出《We Must Pace the Frontier》三步走方案,Altman、Musk、Hassabis 罕见同声附议,白宫却当场泼冷水;同一周,纽约时报诉 OpenAI/微软案的解封文件把"AI 抓取是人类历史上最大规模的劳动窃取"这句内部原话摆上了台面;OpenAI 则主动公开了模型失准披露框架与六份报告,承认未发布模型会在压缩摘要里给"继任者"留指令、要求隐瞒错误。安全叙事之外,产业侧照样狂奔:华为发布昇腾 960 超节点(4096 卡、8 EFLOPS FP8、1PB HBM)与 NPO 光引擎 Hi-ONE;OpenAI 首颗自研推理芯片 Jalapeno 在 Hot Chips 完整亮相;Qwen3.8-Omni-Flash 把音视频输入价格砍掉 98%;智谱 50 亿美元、Mistral €30 亿、Cognition $20 亿三笔巨资同周落地;国内连发《人工智能安全治理框架 3.0》与最高法首部涉 AI 裁判规则。以下是详细内容...
秒杀系统高并发优化实战(C++ / Drogon):3.11 X-Forwarded-For 取首段的陷阱:一次真实的注册频控绕过
3.10 那篇(注册安全加固:同 IP 注册频控 + 反代真实客户端 IP 解析)里,我为了拿到反代后的客户端 IP,写了一段"取 X-Forwarded-For 首段"的代码,并留下一句结论:最左首段才是最原始客户端。 这篇是勘误。 那句话不是"不够严谨",是错的——而且错得挺危险:它等于把同 IP 注册频控的 key,直接交给了调用方决定。攻击者不需要任何工具,一行请求头就能让频控失效。 更值得记的是,我当初为什么会这么写——不是没查,而是查错了地方。 配套代码:src/controllers/UserController.cc 的 clientIp()(改用 drogon::plugin::RealIpResolver::GetRealAddr)、config.json 的 plugins 段(trust_ips / from_header)、src/service/RegisterGuard.{h,cc}(被绕过的同 IP 频控);验证脚本 scripts/verify-311-real-ip.sh(...
秒杀系统高并发优化实战(C++ / Drogon):收官篇 · 6-8 章规划与预计实现(MQ 削峰 / Lua 预扣 / 防刷限流)
系列写到第五章「读性能优化」时,项目在 v0.2.0 收官了:代码定格在「直打数据库 + Redis 读缓存」这一档,第六至八章(MQ 削峰 / Lua 原子预扣 / 防刷限流)不再落地实现。 但设计不该烂尾。这一篇把剩下三章一次性讲完——不贴落地代码,只讲"如果继续做,会怎么做、为什么这么做、预计能拿到什么、会踩哪些坑"。 本篇性质说明:本篇没有配套落地代码(仓库止于 v0.2.0,见 docs/PLAN.md ADR-10)。文中所有架构、接口、Key 均沿用前五章既有约定,属预计方案;出现的 QPS 数字均为预期目标,不是实测值。判断依据只有一条:它们能不能把已经证明过的方法论继续用下去。 一、先交代:为什么停在第五章 理由 说明 验收指标的性质变了 项目的核心命题是"QPS 跃迁来自架构决策,而不是换框架或堆中间件"。前五章已经把这件事证明完整:440 QPS → 万级,全部来自读缓存这一层架构改动 取舍密度会被稀释 前五章每章都有真实两难(超卖怎么防、Redis 同步客户端为什么不能用、缓存失...
写前日志 WAL:先记账、后落库
00:00:03.412 你点了"支付",页面弹出"付款成功"。 00:00:03.415 三毫秒后,这台数据库服务器的电源被拔了。 重启之后,这笔钱还在不在? 如果答案是"看运气",那你的系统大概率还没读懂一条被用了四十多年的原则——写前日志(Write-Ahead Logging,WAL)。它解释了一堆看起来互相矛盾的现象:为什么 MySQL 敢承诺"事务已提交就绝不回退",而 Redis 回了 OK 却仍可能丢数据?为什么 SQLite 一开 WAL 模式,目录里就冒出 -wal、-shm 两个文件?为什么 PostgreSQL 的备份要归档一个叫 pg_wal/ 的目录?为什么 Kafka 干脆把"日志"当成了唯一的数据结构? 先看三个真实存在的东西:MySQL 的 ib_logfile0、PostgreSQL 的 pg_wal/、etcd 的 member/wal/。它们是三个不同系统的命根子,却长着同一副骨架。 一、它从哪来WAL 不是谁灵光一现的设计,它是从扇区的物理...
康威定律:架构复制沟通结构
面试里有个问题特别刁:"你们的微服务是按什么切的?" 答"按业务能力"的人很多,但追问一句就露馅了——为什么订单服务刚好是这五个人在维护?为什么"用户中心"和"账户中心"是两个人分别负责,而不是一个人管全? 再看两个更具体的现象:两个团队共用一个数据库,加一个字段要等两周;一个模块三个人都在改,谁都不敢重构,因为它没有主人。 这些都不是技术问题。它们是同一条规律在组织层面的投影——康威定律。它最扎人的地方在于:你设计的架构,其实早就被你和同事的沟通方式决定了。 一、它从哪来1967 年,Melvin Conway 写下一篇短文 《How Do Committees Invent?》,1968 年 4 月发表在 Datamation 杂志上。核心结论只有一句(原文): Organizations which design systems … are constrained to produce designs which are copies of the communication structur...

