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

时间:2008-09-29 09:25:42

标签: asp.net iis deployment redundancy

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

  1. 压缩新代码,然后将其上传到服务器。
  2. 在实时服务器上,从IIS网站目录中删除所有实时代码。
  3. 将新代码zipfile解压缩到现在空的IIS目录
  4. 这个过程都是脚本化的,并且发生得非常快,但是当旧文件被删除以及新文件被部署时,仍然会有10-20秒的停机时间。

    有关0秒停机时间方法的任何建议吗?

11 个答案:

答案 0 :(得分:79)

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

  1. 关闭服务器2上的所有流量
  2. 在服务器1上部署
  3. 测试服务器1
  4. 关闭服务器1上的所有流量
  5. 在服务器2上部署
  6. 测试服务器2
  7. 在两台服务器上转换流量
  8. 事情是,即使在这种情况下,如果您使用“粘性会话”,您仍然会重新启动应用程序并丢失会话。如果你有数据库会话或状态服务器,那么一切都应该没问题。

答案 1 :(得分:59)

Microsoft Web Deployment Tool在某种程度上支持这一点:

  

启用Windows事务性文件   系统(TxF)支持。当TxF支持时   已启用,文件操作是   原子;也就是说,他们要么成功了   或完全失败。这可以确保数据   完整性并防止数据或文件   从存在于“中途”或   腐败的国家。在MS Deploy中,TxF是   默认情况下已禁用。

似乎交易是针对整个同步的。此外,TxF是Windows Server 2008的一项功能,因此此事务功能不适用于早期版本。

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

  • 表示现有路径/网址:
    • 路径:\ web \ app \ v2.0 \
    • 网址http://app
  • 将新的(或修改过的)网站复制到服务器下
    • \网络\应用\ V2.1 \
  • 修改IIS元数据库以更改网站路径
    • 来自 \ web \ app \ 2.0 \
    • \ web \ app \ v2.1 \

此方法具有以下优点:

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

答案 2 :(得分:10)

通过将IIS中的应用程序请求路由用作不同端口上两个本地IIS站点之间的软件负载平衡器,您可以在单个服务器上实现零停机时间部署。这称为蓝绿色部署策略,其中在任何给定时间,负载均衡器中只有两个站点中的一个可用。部署到“关闭”的站点,将其加热并将其带入负载均衡器(通常通过传递应用程序请求路由运行状况检查),然后从“池”中取出已启动的原始站点(再次通过健康检查失败)。

A full tutorial can be found here.

答案 3 :(得分:7)

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

对于我的配置,我为每个A和B站点都有一个web目录,如下所示: c:\ Intranet \ Live A \ Interface c:\ Intranet \ Live B \ Interface

在IIS中,我有两个相同的站点(相同的端口,身份验证等),每个站点都有自己的应用程序池。其中一个站点正在运行(A),另一个站点正在运行(B)。 live live也有实时主机标题。

在部署到生活时,我只是发布到STOPPED站点的位置。因为我可以使用其端口访问B站点,所以我可以预热站点,以便第一个用户不会导致应用程序启动。然后使用批处理文件将实时主机标头复制到B,停止A并启动B.

答案 4 :(得分:7)

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

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

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

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

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

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

现在您需要一种方法来阻止对新AppDomain的请求。 我使用一个名为mutex - 由部署代理创建和拥有,由新Web应用程序的Application_Start等待,然后在部署数据库更新后由部署代理发布。

(我在网络应用中使用标记文件来启用互斥锁等待行为) 新web应用程序运行后,我删除了标记文件。

答案 5 :(得分:6)

好的,因为每个人都在低估我在2008年写回来的答案* ...

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

我们当然不需要负载均衡器和两台服务器来执行此操作,如果您维护的每个网站都有3台服务器,那就没问题了,但对于大多数网站而言,它总是过度杀伤。

此外,我们不依赖于微软的最新向导 - 太慢,太多隐藏的魔法,而且太容易改变其名称。

以下是我们的工作方式:

  1. 我们有一个帖子构建步骤,可将生成的DLL复制到'bin-pub'文件夹中。

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

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

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

    整个部署过程需要5秒到30分钟,具体取决于更改的文件数量和要审核的更改数量。

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

    **我们总是快速了解我们正在部署的更改 - 作为最后一分钟的双重检查,因此我们知道要测试什么,如果有什么破坏我们准备好了。我们使用Beyond Compare,因为它可以让您轻松地通过FTP传播文件。没有BC我永远不会这样做,你不知道你在覆盖什么。

    *滚动到底部查看它:(顺便说一句,我不再推荐网站,因为它们构建速度较慢,并且可能会因为一半编译的临时文件而崩溃。我们过去使用它们是因为它们允许更敏捷的文件 - 按文件部署。很快就可以解决一个小问题,你可以确切地看到你正在部署什么(如果当然使用Beyond Compare - 否则就算了)。

答案 6 :(得分:5)

我能想到的唯一零停机方法涉及托管至少2台服务器。

答案 7 :(得分:1)

对于单个服务器,我会稍微改进George的答案,如下所示:

  1. 使用Web部署项目将网站预编译为单个DLL
  2. 压缩新网站,并将其上传到服务器
  3. 将其解压缩到位于具有该网站权限的文件夹中的新文件夹,以便解压缩的文件正确继承权限(可能是e:\ web,子文件夹v20090901,v20090916等)
  4. 使用IIS管理器更改包含站点的文件夹的名称
  5. 将旧文件夹保留一段时间,以便在出现问题时可以回退
  6. 步骤4将导致IIS工作进程回收。

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

    当然,当有多个服务器和/或数据库更改时,它会更复杂一些......

答案 8 :(得分:1)

扩展sklivvz的答案,该答案依赖于某种负载均衡器(或只是同一服务器上的备用拷贝)

  1. 将所有流量定向到Site / Server 2
  2. 可选择稍等一下,以确保尽可能少的用户在已部署的版本上具有待处理的工作流程
  3. 部署到站点/服务器1并尽可能地加热
  4. 以事务方式执行数据库迁移(力求实现此目标)
  5. 立即将所有流量定向到Site / Server 1
  6. 部署到站点/服务器2
  7. 指向两个站点/服务器的流量
  8. 可以通过创建数据库快照/副本来引入一些冒烟测试,但这并不总是可行的。

    如果可能并且需要使用“路由差异”,例如不同的租户URL:s(customerX.myapp.net)或不同的用户,首先部署到一群不知情的豚鼠。如果没有任何失败,请向所有人发布。

    由于涉及数据库迁移,因此通常无法回滚到以前的版本。

    有很多方法可以让应用程序在这些场景中发挥更好的效果,例如使用事件队列和回放机制,但是由于我们正在讨论将更改部署到正在使用的内容,因此实际上没有万无一失的方法。

答案 9 :(得分:1)

我就是这样做的:

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

  • 在端口80上运行的1个负载均衡器/反向代理(例如nginx)
  • 2个ASP.NET-Core / mono反向代理/ fastcgi chroot-jails或docker-containers侦听2个不同的TCP端口
     (或者在两个不同的TCP端口上只有两个反向代理应用程序,没有任何沙箱)

工作流:

启动事务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 

答案 10 :(得分:-7)

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

不确定这对“网络应用程序”有帮助(我认为你说的是​​你正在使用的),这就是为什么我们总是使用“网站”。此外,通过“网站”部署,不会重新启动您的站点并删除所有用户会话。