@
duanquanyong 你好,朋友告诉了我这个帖子,所以我特地过来回复一下老哥。
首先要说的是,问题解决了,问题产生时间大概是 2020-03-09 17:00:00,解决时间是 2020-03-10 00:20:00 左右。
我来分享下具体细节吧,这在国内 CDN 服务商里应该也算是一个坑,希望今后能多少帮助到大家做别的开发。
错误产生的具体原因是“Content-Encoding: gzip”和“ETag”两个响应头同时出现导致了 CDN 多级缓存节点重验证行为异常,从而响应给了客户端错误的内容。我猜测国内的 CDN 服务商对“ETag”的“W/”弱验证机制支持的并不是很友好,应该是只支持强验证,而我们这次的服务更新中恰好就用到了弱验证(对于“Content-Encoding: gzip”和“ETag”存在的矛盾详见
https://tools.ietf.org/html/rfc7232#section-2.3.3 这里)。
目前 [
goproxy.cn](
https://goproxy.cn) 服务的所有 Go modules 文件里,只有 .mod 这一类文件可能会触发这个错误(因为只有它存在被 gzip 的可能),但也并不是百分百触发。触发所需的一个大前提是目标文件得满足尺寸不小于 1KB (这是我们 gzip 传输的起征点,而
https://goproxy.cn/github.com/spf13/viper/@v/v1.6.2.mod 就恰好满足了这个条件),所以大多数 .mod 文件都不会遇见这个错误。满足尺寸条件后,后台也是可以正常响应 gzip 过的内容给 CDN 节点的,CDN 节点也是可以正常缓存的,客户端也是可以正常从 CDN 节点那里获取到的。只有在 CDN 节点已经有了目标文件的缓存,并且缓存已经在 CDN 节点中存在了一段时间,需要与后台商量进行重验证时,才会有概率出现这个错误。所以才会有比如老哥你遇到了这个错误,但你在群里一说,隔壁省(也就是不同 CDN 节点的意思)的某个哥们儿却能正常获取的情况。
错误的具体解决办法有两种,一种是关闭 gzip 传输功能。还有一种是在“Content-Encoding: gzip”出现时移除“ETag”(这是国内很多 CDN 服务商目前响应 gzip 过的内容给客户端时的做法,但从后台拿 gzip 过的内容时他们并没有忽略“ETag”),或者也可以修改“ETag”,但千万不要试图使用“W/”使 CDN 节点强行走“弱验证”的路子,因为国内很多 CDN 服务商可能并不理解什么是“弱验证”(或者说理解得不够好),通用可行的修改方法可以参考 Apache Web Server 或者 RoR Web 框架等,在“ETag”内容里追加一个“-gzip”后缀,比如“ETag: "<some-hash-characters>"”就修改成“ETag: "<some-hash-characters>-gzip"”。不过,第二种办法是我给爱好自己写 Web 框架的朋友们准备的,其他朋友如果遇到这类问题直接选用第一种办法就好,简单直接。至于我们这次选用的解决办法,当然了,我们不能关闭 gzip 传输功能,因为我们有一个大目标就是要保证所有人都能以最快的速度获取到模块版本,所以我们是选择了第二种里面修改“ETag”的办法(加“-gzip”后缀)。
此外,像一楼老哥说的,[
goproxy.cn](
https://goproxy.cn) 之所以快,主要得力于我们上了七牛云的融合 CDN 服务,并且没有做任何带宽或者速率限制(单节点带宽甚至高达 40Gbps+)。虽然我不是七牛的员工,但按照我的个人理解所谓“融合”指的应该是把多家 CDN 服务商整合起来一并拿给用户使用,这样当某家提供商的服务出现问题时,或者节点不足时,可以采用别家的以作补充。当然,这是我的个人理解。近期,为了能做得更好,我们在探索“零错误率”的可能性,也就用到了 CDN 算是还未正式发布给所有人用的一些功能。对于我个人来说,由于我还没参与到实际社会工作当中,所以在很多事情的处理方式上可能显得太过胆大不计后果(这些老前辈们最近也有说过我),相当于我是在冒着出事故的风险优化我们的服务,试图用事故来换取未来的低错误率……为此鲁莽行为我郑重地向大家道个歉。[
goproxy.cn](
https://goproxy.cn) 是我去年还在学校里时开发的,可能在我潜意识里它还停留在一个“校园项目”的类别中吧,直到最近我才意识到了它已经不再是我曾经自己搭建自己跑的那个鲜有人用的小服务了,现在日访问量直逼千万级,比我了解到的别的几个同类服务的数据是要多的,就连已缓存的模块版本数量都要比官方的 [
proxy.golang.org](
https://proxy.golang.org) 多出不少,甚至都有 [
goproxy.baidu.com](
https://goproxy.baidu.com) 这种大厂的公共代理将 [
goproxy.cn](
https://goproxy.cn) 用作上游……所以任何一个不负责任的改动都可能导致很多人的日常开发或多或少的受到影响,哪怕本意是好的,但我还是会深感愧疚……好了,睡觉,夜里太过感性……总之,出过的错,记下了,下次再出同样错的机率就会很低很低了。
最后,我为这次产生的问题向大家道个歉,造成了麻烦,实在是不好意思。