【问题标题】:How can I programmatically recycle a .net web app's own apppool?如何以编程方式回收 .net Web 应用程序自己的应用程序池?
【发布时间】:2012-02-27 18:23:09
【问题描述】:

我有一个使用 Nhibernate 和 Linq2SQL 的复杂服务器应用程序。 Linq2sql 代码每天大约 3 次生成“值不能为空”异常。一旦发生这种情况,代码将始终生成异常。诊断和解决根本原因将是漫长的,并且会引入不稳定因素。

当前的“修复”是每小时回收应用程序池。但是,从问题发生到回收发生,服务一直处于关闭状态。我希望 Web 服务捕获异常并回收它自己的应用程序池。我希望所有其他 Web 请求在完成之前都能得到尊重。

编辑:故障出在负载平衡网络场的两台服务器上。客户端不会因为这段代码崩溃而从一台服务器切换到另一台服务器。

【问题讨论】:

  • Diagnosis and solving the root cause will be lengthy and will introduce instability 在 downvotealanche 之前。您应该将应用程序池配置为在短期内回收,并在长期内修复该错误。
  • 最好的方法是修复错误
  • 是的,完全正确。我是第一个同意一旦你放入创可贴,你就会习惯于忍受它的人。在这种情况下,旧代码被严重破坏,在我们可以安排故障分析时间之前,需要进行不涉及人工的工作,我知道这将涉及一些危险的重构。

标签: asp.net iis-7


【解决方案1】:

以下代码将回收当前站点的应用程序池。您需要添加对 Microsoft.Web.Administration 的引用

using (ServerManager iisManager = new ServerManager())
{
    SiteCollection sites = iisManager.Sites;
    foreach (Site site in sites)
    {
       if (site.Name == HostingEnvironment.SiteName) 
       {
         iisManager.ApplicationPools[site.Applications["/"].ApplicationPoolName].Recycle();
         break;
       }
    }
}

【讨论】:

  • @vittore 和 OP 有类似的问题,这不会解决问题。 APPPOOL 无权取消此操作,因此它可能对 OP 也不起作用。 OP 的解决方案对我有用,但只是感觉 令人毛骨悚然​​> ;) 这样做。
  • @ClasG 是的,你需要扩展权限才能工作
  • 您是否有任何关于它需要什么权限以及如何执行此操作的详细信息?我们遇到了类似的问题,但文件锁定导致代码部署出现问题(我们需要先擦除目录,当文件被锁定时它会搞砸网络部署)。
  • 我是从另一个具有疯狂身份验证和管理员权限的站点调用它的。我不希望应用程序池自行或以某种方式回收。
【解决方案2】:

将 ASP.NET 工作进程“绊倒”以回收应用程序池的最简单方法是以某种方式修改 web.config 文件。此更改由文件系统观察程序获取,并导致 ASP.NET 循环以加载新配置。

文件的内容不必以任何实际的方式改变;只需添加或删除空白字符就足够了。

编辑:

如果这不足以解决您的问题,您可以全力以赴并使用目录服务手动回收应用程序池。

// Set up the path identifying your application pool.
var path = "IIS://YOURSERVERNAME/W3SVC/AppPools/YourAppPoolName";

// Create the directory entry to control the app pool
var appPool = new DirectoryEntry(path);

// Invoke the recycle action.
appPool.Invoke("Recycle", null);

基于Code Project: Recycling IIS 6.0 application pools programmatically

【讨论】:

  • 触摸 web.config,即使我明确授予 IUSR 写入权限(记住这是一个创可贴)只会回收 APPLICATION,而不是 APP POOL。数据问题在应用程序池中,w3wp 进程继续愉快地进行
  • 更新了更直接的方法。它尚未经过验证可在 IIS7+ 上运行,因此请告诉我们您的使用情况。
  • 我最初是走这条路的,但所需的权限列表既繁重又复杂。我选择了一个更简单的解决方案,即让应用程序池的设置在超过 memoryLimit 值时进行回收,然后故意分配内存,直到回收被触发。
【解决方案3】:

我以前也遇到过同样的问题;我应该写博客,因为现在我不记得根本原因了。

我的直觉告诉我,这是以下情况之一:

  1. 上下文未在某处处理。
  2. 线程问题:确保多个线程不能访问同一个上下文。

或者类似的东西。只要确保您正确使用 Linq2Sql。

【讨论】:

    【解决方案4】:

    我最终选择的解决方案是为 appPool 允许使用的内存量设置一个最大值。然后代码简单地吞噬内存,直到 asp.net 决定回收 appPool。

    在应用程序池高级设置中,我将私有内存限制设置为 800,000 Kb。

    在 Linq 代码失败的 Catch 部分,我分配的内存超过了限制:

    List<string> listOfMemory = new List<string>();
    
    // in the app pool, you need to set the virtual memory limit to 800,000kb
    log.Error("Allocating so much memory that the app pool will be forced to recycle... ");
    for (int intCount = 1; intCount < 10000000; intCount++)
    {
    listOfMemory.Add("new string " + intCount.ToString());
    }
    

    现在这意味着在生成新的 w3wp 进程之前只有大约 4 个线程失败。在此解决方案之前,线程会一直失败,直到有人手动回收应用程序池。不幸的是,如果您将应用程序池设置为按固定分钟数回收,则分钟数越小崩溃的频率越高。而且分钟数越大,失败的线程就越多。

    这种创造性的解决方法限制了损害。

    【讨论】:

    • 虽然这可能适合您的环境,但如果您的应用使用 200 mb 内存,服务器有 400 mb 可用内存,您的应用开始分配内存,它也可能会暂时占用服务器。此时你需要 600 mb 来强制回收,并且在分配 400 mb 后服务器将开始大量页面。
    • 哇……好丑。但即使你想这样做,为什么不只是 new[] 你想要分配的任何数量的 RAM?
    猜你喜欢
    • 1970-01-01
    • 2018-07-07
    • 2011-07-02
    • 1970-01-01
    • 2020-03-04
    • 2015-01-07
    • 2010-10-09
    • 2011-09-20
    • 2016-06-13
    相关资源
    最近更新 更多