部署竞争条件导致CDN缓存旧文件或损坏的文件

时间:2014-03-24 21:29:14

标签: node.js deployment versioning web-deployment cdn

我们当前的部署流程如下:

  1. 使用grunt创建生产资产。
  2. 在我们的CDN上创建日期戳和指向文件(例如/scripts/20140324142354/app.min.js)。

    旁注:我听说过这个过程称为"版本化"之前,但我不确定它是否是正确的术语。

  3. 提交构建到github。

  4. 在Web服务器上运行git pull以从github检索新代码。
  5. 这是一个node.js网站,我们正在使用forever -w来监控文件更改并相应地更新网站。

    我们的应用中设置了路线设置,可通过/scripts/*/app.min.js投放最新版本的应用。

    我们这样的版本的原因是因为我们的CDN设置为无限期缓存JavaScript文件,这故意创建缓存未命中,以便在CDN(以及我们的用户浏览器)中更新代码。

    这种情况很好。但是,如果其中一台服务器在检查新代码方面有所欠缺,那么它就会崩溃。

    有时客户端会在部署过程中点击页面并尝试从CDN检索新的JavaScript代码。 CDN尝试检索它,但命中服务器尚未检查出新代码,并缓存旧的或部分下载的文件,导致各种问题。

    这个问题因我们的CDN有许多边缘位置而加剧,因此我们的办公室始终无法立即看到问题。一些边缘位置可能已经删除了旧/坏代码,而其他位置可能已经下拉了新的/好的代码。

    有没有更好的方法来执行这些可避免此问题的部署?

3 个答案:

答案 0 :(得分:3)

作为一般经验法则:

不要进行实时升级。 (除非语言支持它,但即便再考虑三次)

使用git pull拉取代码,然后等待应用程序注意文件的更改听起来很像90:使用ftp将php文件上传到apache web服务器(如果你很酷的话,将sftp上传到sftp)并等待apache注意到它们已更新。它不可能原子地发生,所以当然存在竞争条件。一些用户获得一半建立和破坏的网站。

我建议只升级您的实时和正在运行的应用程序,而没有人使用它。希望您在某种负载均衡器后面有一个服务器池,这样您就可以一次删除它们并升级它们。

这意味着用户可以同时使用旧网站和新网站,具体取决于他们访问网站的方式和时间,但这比根本无法访问它更好。

理想情况下,您可以使用新版本的网站启动运行的每个Web服务器的副本。检查新版本是否正常工作,然后以原子方式更新负载均衡器,以便每个人同时遇到新站点。只有一切都经过验证才能完美运行,旧机器才会关闭,退役或重复使用。

答案 1 :(得分:2)

你的程序中的第4步应该是:

git archive --remote $yourgithubrepo --prefix=$timestamp/ | tar -xf -
stop-server
ln -sf $timestamp current
start-server

您的服务器将始终使用current目录(以及符号链接)。无论部署多长时间,您的应用程序都处于一致状态。

答案 2 :(得分:0)

我会继续发布我们现在正在使用的远离理想的猴子补丁。

一旦我们确定代码部署在我们进行另一次构建的所有服务器上,我们会部署一次可能会或可能不会按计划进行,其中唯一更改的是版本号。

然后我们再次按服务器部署服务器。

竞争条件仍然存在但由于两个版本之间的应用程序代码相同,这掩盖了问题,因为无论CDN命中哪个服务器,它都会获得“最新”代码。