如何以零停机时间部署ASP.NET应用程序

要部署我们网站的新版本,我们执行以下操作:

  1. 压缩新的代码,并将其上传到服务器。
  2. 在活动的服务器上,从IIS网站目录中删除所有的实时代码。
  3. 将新代码zipfile解压缩到现在为空的IIS目录中

这个过程全是脚本化的,而且发生的很快,但是当旧文件被删除,新文件被部署时,仍然会有10-20秒的停机时间。

任何关于0秒停机时间的build议?

您需要2个服务器和一个负载平衡器。 这是步骤:

  1. 打开服务器2上的所有stream量
  2. 在服务器1上部署
  3. testing服务器1
  4. 打开服务器1上的所有stream量
  5. 在服务器2上部署
  6. testing服务器2
  7. 打开两台服务器上的stream量

事情是,即使在这种情况下,如果您使用“粘性会话”,仍然会重新启动应用程序并丢失会话。 如果你有数据库会话或状态服务器,那么一切都应该没问题。

Microsoft Web部署工具在某种程度上支持:

启用Windows事务性文件系统(TxF)支持。 当启用TxF支持时,文件操作是primefaces的; 也就是说,他们要么成功,要么完全失败。 这确保了数据的完整性并防止数据或文件在“中途”或损坏的状态下存在。 在MS Deploy中,TxF默认是禁用的。

这似乎是整个同步的交易。 此外,TxF是Windows Server 2008的一个function,所以此事务function将不适用于早期版本。

我相信这是可能的修改您的脚本0停机时间使用文件夹作为版本和IIS元数据库:

  • 对于现有的path/url:
    • path :\ web \ app \ v2.0 \
    • url : http:// app
  • 将新的(或修改的)网站复制到服务器下
    • \networking\程序\ 2.1 \
  • 修改IIS元数据库以更改网站path
    • \ web \ app \ 2.0 \
    • \ web \ app \ v2.1 \

这种方法提供了以下好处:

  • 如果新版本出现问题,您可以轻松回滚到v2.0
  • 要部署到多个物理或虚拟服务器,可以使用脚本进行文件部署。 一旦所有服务器都具有新版本,则可以使用Microsoft Web部署工具同时更改所有服务器的元数据库。

我最近经历了这个,我提出的解决scheme是在IIS中设置两个站点并在它们之间切换。

对于我的configuration,我有这样的每个A和B网站的Web目录:c:\ Intranet \ Live A \ Interface c:\ Intranet \ Live B \ Interface

在IIS中,我有两个相同的站点(相同的端口,身份validation等),每个都有自己的应用程序池。 其中一个站点正在运行(A),另一个站点停止(B)。 活的还有活的主机标题。

当部署到现场时,我只需发布到STOPPED站点的位置即可。 因为我可以使用其端口访问B站点,所以我可以预热站点,以便第一个用户不会导致应用程序启动。 然后使用一个batch file,我把现场主机头复制到B,停止A并开始B.

使用Microsoft.Web.Administration的ServerManager类可以开发自己的部署代理。

诀窍是更改VirtualDirectory的PhysicalPath,这会导致旧的和新的Web应用程序之间的在线primefaces切换。

请注意,这可能会导致新旧AppDomain并行执行!

问题是如何同步更改数据库等

通过使用旧的或新的PhysicalPath轮询AppDomain的存在,可以检测旧的AppDomain何时终止,以及新的AppDomain是否已经启动。

要强制AppDomain启动,必须​​发出HTTP请求(IIS 7.5支持自动启动function)

现在您需要一种方法来阻止对新AppDomain的请求。 我使用了一个已命名的互斥锁 – 它由部署代理创build并拥有,由新的Web应用程序的Application_Start等待,然后在部署代理完成数据库更新后发布。

(我使用Web应用程序中的标记文件启用互斥等待行为)一旦新的Web应用程序正在运行,我删除标记文件。

通过利用IIS中的应用程序请求路由作为不同端口上的两个本地IIS站点之间的软件负载平衡器,可以在单个服务器上实现零宕机时间部署。 这就是所谓的蓝绿色部署策略 ,在任何给定时间只有负载均衡器中有两个站点中的一个可用。 部署到“closures”的站点,对其进行预热,然后将其带入负载平衡器(通常通过应用程序请求路由运行状况检查),然后将原始站点从“池”(再次通过使其健康检查失败)。

完整的教程可以在这里find。

好吧,因为每个人都低估了2008年我写回来的答案。

我会告诉你我们现在是如何在2014年完成的。我们现在不再使用网站,因为我们现在正在使用ASP.NET MVC。

我们当然不需要负载平衡器和两台服务器来完成这项工作,如果您维护的每个网站都有3台服务器,但这对大多数网站来说都是过度的。

另外,我们并不依赖微软的最新精灵 – 太慢了,太隐藏了魔法,而且也很容易改变它的名字。

以下是我们如何做到的:

  1. 我们有一个后期构build步骤,将生成的DLL复制到“bin-pub”文件夹中。

  2. 我们使用Beyond Compare(这是非常好的**)来validation和同步更改的文件(通过FTP,因为它被广泛支持)直到生产服务器

  3. 我们在网站上有一个安全的URL,包含一个button,将'bin-pub'中的所有内容复制到'bin'(先备份以启用快速回滚)。 在这一点上,应用程序重新启动。 然后我们的ORM检查是否有任何表或列需要添加并创build它们。

这只是几毫秒的停机时间。 应用程序重新启动可能需要一两秒钟,但在重新启动期间,请求被缓冲,因此实际上停机时间为零。

整个部署过程需要5秒到30分钟的时间,具体取决于更改的文件数量以及要查看的修改量。

这样,您不必将整个网站复制到不同的目录,而只需要bin文件夹。 您也可以完全控制stream程,并确切知道正在发生的变化。

**我们总是对我们正在部署的变化做一个快速的眼球 – 作为最后一刻的双重检查,所以我们知道要testing什么,以及是否有任何事情打破了我们的准备。 我们使用超越比较,因为它可以让你轻松地通过FTP区分文件。 没有公元前我不会这样做,你不知道你在重写什么。

*滚动到底部看到它:(顺便说一句,我不会再推荐网站,因为它们build设速度较慢,可以用半编译的临时文件崩溃,我们过去使用它们是因为它们允许更多的敏捷文件部署,很快解决一个小问题,你可以看到你正在部署什么(如果使用Beyond Compare当然 – 否则忘记)。

我能想到的唯一的零宕机方法涉及至less2台服务器的托pipe。

对于单台服务器,我将对George的答案进行一下细化,如下所示:

  1. 使用Web部署项目将站点预编译为单个DLL
  2. 压缩新网站,并将其上传到服务器
  3. 将其解压缩到位于具有正确权限的文件夹中的新文件夹,以便解压缩文件正确inheritance权限(可能是e:\ web,子文件夹v20090901,v20090916等)
  4. 使用IISpipe理器更改包含该站点的文件夹的名称
  5. 保留旧文件夹一段时间,所以你可以在出现问题时备份

第4步将导致IIS工作进程回收。

如果您不使用InProc会话,这只是零停机时间; 如果可以的话,使用SQL模式(甚至更好,完全避免会话状态)。

当然,当多个服务器和/或数据库发生变化的时候,会涉及更多的内容。

为了扩展sklivvz的答案,这个答案依赖于某种types的负载平衡器(或者是同一台服务器上的备用副本)

  1. 将所有stream量指向站点/服务器2
  2. 可以稍等一下,以确保尽可能less的用户在部署的版本上有未决的工作stream程
  3. 部署到Site / Server 1并尽可能地预热
  4. 以事务方式执行数据库迁移(努力使之成为可能)
  5. 立即将所有stream量指向站点/服务器1
  6. 部署到站点/服务器2
  7. 直接访问这两个网站/服务器

可以通过创build数据库快照/副本来引入一些烟雾testing,但这并不总是可行的。

如果可能并且需要使用“路由差异”,例如不同的租户URL:s(customerX.myapp.net)或不同的用户,首先部署到未知的豚鼠组。 如果没有失败,释放给大家。

由于涉及数据库迁移,回滚到以前的版本往往是不可能的。

有一些方法可以使应用程序在这些场景中更好地发挥作用,例如使用事件队列和回放机制,但是由于我们正在讨论如何将更改部署到正在使用的某些东西上,所以实际上没有任何可以防止的方法。

这是我如何做到的:

绝对最低系统要求:
1服务器

  • 1端口80上运行的负载均衡器/反向代理(例如nginx)
  • 2个不同的TCP端口上的ASP.NET / mono fastcgi-chroot jails

工作stream程:

开始交易myupdate

try Web-Service: Tell all applications on all web-servers to go into primary read-only mode Application switch to primary read-only mode, and responds Web sockets begin notifying all clients Wait for all applications to respond wait (custom short interval) Web-Service: Tell all applications on all web-servers to go into secondary read-only mode Application switch to secondary read-only mode (data-entry fuse) Updatedb - secondary read-only mode (switches database to read-only) Web-Service: Create backup of database Web-Service: Restore backup to new database Web-Service: Update new database with new schema Deploy new application to apt-repository (for windows, you will have to write your own custom deployment web-service) ssh into every machine in array_of_new_webapps run apt-get update then either apt-get dist-upgrade OR apt-get install <packagename> OR apt-get install --only-upgrade <packagename> depending on what you need -- This deploys the new application to all new chroots (or servers/VMs) Test: Test new application under test.domain.xxx -- everything that fails should throw an exception here commit myupdate; Web-Service: Tell all applications to send web-socket request to reload the pages to all clients at time x (+/- random number) @client: notify of reload and that this causes loss of unsafed data, with option to abort @ time x: Switch load balancer from array_of_old_webapps to array_of_new_webapps Decomission/Recycle array_of_old_webapps, etc. catch rollback myupdate switch to read-write mode Web-Service: Tell all applications to send web-socket request to unblock read-only mode end try 

我会build议保留旧文件,并简单覆盖它们。 这样,停机时间仅限于单个文件的覆盖时间,并且一次只有一个文件丢失。

不知道这有助于在“networking应用程序”,虽然(我认为你说这就是你正在使用),这就是为什么我们总是使用“网站”。 此外,“网站”部署不会重新启动您的网站,并放弃所有的用户会话。