首页| 论坛| 搜索| 消息
主题:暴力撬死锁!rsync 算法是如何被“逼”出来的?
爱我中华发表于 2026-07-19 13:43
我们设想一个问题:你在北京的服务器改了一个 10GB 的文件,为什么敲下 rsync 之后,几秒钟就同步到上海的服务器上了?10GB。几秒钟。按常理,10GB 的数据,就算你家是千兆宽带,满速下载也得跑一分多钟。而服务器之间的链路,往往比你家宽带慢得多、卡得多。所以这里一定发生了什么“不正常”的事。很多人会脱口而出:“因为 rsync 只传差异嘛,增量同步。”对。但问题是——它怎么知道差异在哪?你把“只传差异”这四个字说出口只需要半秒,但如果你停下来想一秒钟,一个让人细思极恐的问题就会浮上来:要找出两个文件的差异,你得先把两个文件放在一起比对吧?可一个文件在北京,一个文件在上海,你怎么比?把上海的文件传到北京来比?那你已经传了一遍了,还“只传差异”干什么——你都已经把整个文件搬过来了啊。这是一个经典的死锁:要省带宽,你得知道差异;要知道差异,你得先花带宽。而 rsync 的天才之处,就是用一个你绝对想不到的方式,把这个死锁暴力撬开了。一、先把问题翻译成一个你能摸到的场景先扔掉服务器,我们来想象一个更肉身的设定。你在北京的一家档案馆工作,你的同事小王在上海分部。你们各自保管着一本《中国工业年鉴 2026》,每本 2400 页,重得像一块砖头。今天馆长告诉你:北京这本出了修订版,加了三章新内容,改了一百多处数据,删了五十页过时的政策文件。现在,你必须在今晚让小王手上那本变得和你这本一模一样。但你们之间只有一样东西可以用:一台老式电报机。 每发一个字,收费一毛钱。你想了想,2400 页的书,按一页 800 字算,全文发电报过去——将近两百万字。二十万块钱。馆长会杀了你。好,现在你坐在这台电报机前,手心出汗。小王在两千公里外等着。你手上是全世界唯一一本新版年鉴,他手上是全世界唯一一本旧版年鉴。你们不能见面,不能拍照,不能传真。你只能用电报机发文字给他,而且每一个字都要算钱。你怎么办?二、人类第一反应:让上海那边自己算你可能会说:简单啊,让小王把旧版的内容告诉我,我来告诉他改哪。来,算个账。小王把他的旧版年鉴一字一字用电报发给你,又是两百万字。二十万块钱。然后你比对完,把差异发回去。假设差异只有全书的 5%,十万字,一万块钱。总计二十一万。比直接发新版还贵。你发现没有,“让对端把文件发过来比对”这件事,本质上就等于已经传输了整个文件。一旦传完了,你还比对什么?你直接把新版发过去不就完了?这就是问题的核心。在 rsync 诞生之前,所有人面对这个场景,能做的事只有一件:认命,传整个文件。 压缩一下,省个两三倍,仅此而已。但 1996 年,澳大利亚国立大学的两个博士生:Andrew Tridgell 和 Paul Mackerras,坐在实验室里盯着这个问题,突然问了一个让所有人愣了一下然后猛拍大腿的问题:“谁说比对差异,需要看到整个文件?”三、第一个脑洞:只问“你有没有第 X 页”,不问“你第 X 页写了什么”让我们回到你和电报机的那个夜晚。你突然想到一个取巧的办法。你不让小王把整本旧版发给你。你只让他做一件事:把旧版年鉴每一页的第一个字和最后一个字,用电报发给你。2400 页,每页两个字,一共 4800 个字。四百八十块钱。 这个代价,馆长是可以接受的。你收到这份”索引”之后,翻开你的新版年鉴,从第一页开始,逐页检查:新版第一页的第一个字和最后一个字,和旧版第一页的一样吗?一样?那这一页大概率没改。你只需要发电报告诉小王:“第一页,保留。”不一样?那这一页肯定改了。你把新版这一页的全文发过去。最后你发现,新版 2400 页里,有 2280 页的首尾字和旧版对得上,只有 120 页变了。你需要全文发送的,只有这 120 页。电报费:索引 4800 字 + 变更页 96000 字 ≈ 一万块钱。 从二十万降到一万,直接打骨折。你很得意。馆长很满意。但就在这时,一个尖锐的问题戳破了你的好心情——“万一改的那一页,刚好第一个字和最后一个字没变呢?”比如旧版第 347 页写的是”2023 年全国粗钢产量 10.13 亿 吨”,新版改成了”2023 年全国粗钢产量 10.19 亿 吨”。改了中间个数字,但首尾字一模一样——”2”和”吨”。你的首尾字索引法会判定这一页“没变”。小王就会把旧版那一页原封不动地留下来。然后上海档案馆里的年鉴就错了一个数据。你倒吸一口气。这不是开玩笑的——年鉴是给决策者看的,一个数字错了,可能就是一座钢厂的产能误判。你得想一个绝对不会漏掉任何改动的办法。四、第二个脑洞:把每一页变成一个“数字指纹”你坐在电报机前,盯着天花板看了很久。然后你想起了大学里学过的一个概念——哈希。你不需要发每一页的首尾字。你可以让小王把旧版每一页的全部内容做一个“数字指纹”发给你。什么叫数字指纹?就是一串短小的数字,但这串数字和那一页的全部内容有极强的绑定关系——只要那一页改了一个标点符号,这串数字就彻底变脸。比如 MD5 值,128 位,只有 16 个字节。一页 800 字,原本需要 800 字来”描述”它,现在只需要 16 个字节。压缩了 50 倍。于是你的新方案变成了这样:小王把旧版年鉴每一页的 MD5 值发给你——2400 页 × 16 字节 = 38400 字节。还是几百块钱的量级。你拿到这份“指纹清单”后,计算新版年鉴每一页的 MD5,然后逐页比对:指纹对上了 → 这一页没变。你发电报:“第 X 页,用你旧版的。”指纹对不上 → 这一页改了。你把新版这一页全文发过去。完美。……吗?你还没有来得及庆祝,又一个问题从阴影里浮了上来——这次的打击比上一次更狠:如果新版不是“改了一页”,而是“在中间插入了一章”呢?想象一下。新版年鉴在第 200 页和第 201 页之间,插入了一整章——“新能源汽车产业十年回顾”,一共 60 页。从第 201 页开始,旧版和新版的页码完全错位了。旧版第 201 页是“石油化工”,新版第 201 页变成了“新能源汽车”。旧版第 201 页的内容,现在跑到了新版第 261 页。但你手上只有一列按页码对齐的 MD5 清单。你会拿旧版第 201 页的指纹去对比新版第 201 页的指纹——啪,不匹配。旧版第 202 页对新版第 202 页——啪,又不匹配。从第 201 页到第 2400 页,全部不匹配!你的算法会判定:后面 2200 页全改了。全文发送。电报费又回到解放前。你瘫坐在椅子上。明明有 2200 页是原封不动搬到后面的,但你的”逐页比对”完全看不到这件事。因为你把每一页当成了一座孤岛。你看不到页面之间的“位移关系”。五、天才一击:从”逐页比对”到”逐字滑窗”现在是凌晨三点。电报机发出微弱的电流声。小王在上海已经趴在桌上睡着了。你还醒着。你在想一个问题:为什么人类翻两本书,一眼就能看出“从第 201 页开始内容往后挪了”?因为人类不是在逐页比对。人类是在任意位置寻找熟悉的段落。你翻开新版第 201 页,看到“新能源汽车……”,你觉得陌生。你继续往后翻,翻到第 261 页,看到”石油化工……”,你立刻认出来:”这不是旧版第 201 页吗!”你需要的不是“逐页指纹”。你需要的是:把新版年鉴切成无数个重叠的小片段,然后去旧版年鉴里问——“这个片段,你见过吗?”但问题来了。如果每一页切一刀,那碰到“插入一章”的情况你还是死——因为你的切分位置和内容边界错位了。你必须切得足够密,才能让任何一段连续内容都至少能在你的切割网格里找到一个能对上的片段。于是你做出了一个疯狂的决定:不按页切。按“每 500 个字”切成一个块,而且每一个字的位置都切一刀。2400 页 × 800 字 = 192 万个字。每一个字的位置都取后面 500 个字作为一个“块”——这就是接近两百万个块。两百万
下一页 (1/3)
回帖(6):
6 # huwg
07-20 01:05
谢谢分享
5 # huwg
07-20 01:05
了解一下
4 # huwg
07-20 01:05
来看看
3 # srwam
07-19 20:34
看后续
2 # srwam
07-19 20:34
了解一下
1 # srwam
07-19 20:34
来看看

全部回帖(6)»
最新回帖
收藏本帖
发新帖