更新 Go Web 应用程序的最佳实践

Best practice for updating Go web application

我想知道将更新部署到 (MVC) Go Web 应用程序的最佳做法是什么。想象一下以下场景:

1) 为我的 Go Web 应用程序编写代码并测试一些更改

2) 部署更新,当前使用先前版本的任何人都不会被打断。

我不知道如何确保第 2) 点可以被覆盖 - 当有人向服务器发送请求并且我 rebuild/restart 就在这一刻,他得到一个错误 - 即使该请求只使用了我没有接触过的代码的一部分,或者是向后兼容的,或者如果我只是添加了一个新的请求处理程序。

也许我遗漏了一些微不足道的或众所周知的模式,因为我正在学习 go 并且我以前的 Web 应用程序是 ASP.NET- 或 php-applications,这不是问题我不需要在代码更改时重新启动网络服务器。

这不仅仅是围棋的问题,但通常我们可以将问题分为两个独立的问题:

  1. 确保当前请求不会被终止并影响用户体验。

  2. 确保没有无法处理新请求的停机时间。

第一个更容易解决:你只是不暴力杀死你的服务器,而是让它退出,导致"Drain phase",它不接受新的请求,只完成当前运行 请求,然后退出。例如,这可以通过监听信号并将应用程序进入特殊状态来完成。

Go 并不简单,因为默认的 http 服务器不支持关闭它,但您可以使用 net.Listener 启动一个服务器,然后保留对它的引用并在需要时关闭它到期了。

现在,只执行方法一然后再次启动服务将导致在这种情况下新请求不被接受,我们都知道在极端情况下这可能需要几秒钟。

所以我们需要的是服务器的另一个实例已经 运行 新代码,旧代码立即不响应新请求,对吧?这可以通过多种方式完成:

  1. 拥有多台服务器,并且在它们之上有一个负载均衡器,允许一台(或多台)服务器在我们重新启动另一台时承担负载。这是最简单的方法,也是大多数人这样做的方法。如果你需要N台服务器来承担你用户的负载,就保持N+1,一次重启一台。

  2. 使用套接字共享技巧。在较新的 Linux 内核中,许多进程可以在同一个端口上侦听和接受。您所做的只是启动新实例,然后告诉旧实例完成并退出。这样就没有停顿。这是通过在侦听套接字上设置 SO_REUSEPORT 来完成的。

  3. 以上内容可以通过准备交付的解决方案自动执行,例如 Einhorn,它为您处理所有细节,请参阅 https://github.com/stripe/einhorn

  4. 此博客 post 中记录了另一种方法:http://blog.nella.org/?p=879