ASP.Net网站静态锁文件写/ IIS回收问题

时间:2017-07-28 13:52:55

标签: c# asp.net multithreading iis locking

我看到很多讨论都认为网站中的静态锁定要写入单个文件进行记录。

有些人说永远不会使用静态锁,而有些人则表示在这种情况下明确要求使用静态锁。反对者争辩说:如果IIS应用程序池被回收怎么办?然后静态锁丢失,可能发生文件写入错误。

我的具体问题:如果您的用户群体相当小(n <1000),并且您的锁中有一行代码执行文件写入&lt; 500个字符,这是一个关注的天文学上不可能的问题吗?

如果是一个任何规模的问题,那么最简单的改进路径是什么,以避免这种罕见的IIS回收 - 静态锁定错误?一个简单的尝试/捕获写甚至&#34; catch&#34;在这种情况下多文件访问?

1 个答案:

答案 0 :(得分:0)

使用FileShare.ReadWrite并使用Async = false

使用this constructor创建FileStream来访问该文件(不要使用File.Open)并指定以下参数:

var stream = new FileStream(path, 
                            FileMode.Append, 
                            FileAccess.Write, 
                            FileShare.ReadWrite, 
                            4096, 
                            false);

需要注意的重要论据是FileShare.ReadWriteuseAsync = false

  

FileShare.ReadWrite:允许随后打开文件进行读写。如果未指定此标志,则在文件关闭之前,任何打开文件以进行读取或写入(通过此进程或其他进程)的请求都将失败。但是,即使指定了此标志,仍可能需要其他权限才能访问该文件。

     

useAsync:指定是使用异步I / O还是同步I / O.但请注意,底层操作系统可能不支持异步I / O,因此在指定true时,可能会根据平台同步打开句柄。异步打开时,BeginRead和BeginWrite方法在大型读取或写入时执行得更好,但对于小型读取或写入,它们可能要慢得多。如果应用程序旨在利用异步I / O,请将useAsync参数设置为true。正确使用异步I / O可以将应用程序的速度提高10倍,但在不重新设计异步I / O应用程序的情况下使用它可以将性能降低10倍。

通过使用这些参数,您将获得一个文件句柄,该句柄将允许其他进程并行访问该文件。同时,您的写入将是同步的,这将阻止您的输出被另一个进程分成两半。仍有锁定,但它由底层操作系统处理,对您和任何竞争过程都是透明的。

添加锁定

如果它让你感觉更好,你可以把它包裹起来:

lock (lockObject)
{
    using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 4096, false))
    {
        var writer = new TextWriter(stream);
        writer.Write(message);
    }
}

请注意,lock可以保护您免受竞争线程的攻击,但不会保护您免受竞争进程的攻击。如果您有一个处理日志写入的工作线程(例如,使用队列和生产者/消费者模式),您可能不需要它,这会增加不必要的开销。但是,如果您直接从Web工作线程写入日志,则确实需要它。

跨进程互斥

即使在应用程序池回收期间,上述应该非常安全。至少我从来没有遇到任何问题。但是..如果你真的偏执并且你的日志记录是关键任务,那么你可以使用named mutex进行跨越进程边界的锁定。

var mutex = new Mutex(false, "MyLoggingMutex");
try
{
    mutex.WaitOne();
    using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 4096, false))
    {
        var writer = new TextWriter(stream);
        writer.Write(message);
    }
}
finally
{
    mutex.ReleaseMutex();        
}

这种事情有很多开销,所以我可能不会使用它,除非记录是关键任务,例如您可以将可审计数据转储到可能用于支持不可否认性的日志文件中(例如,证明谁做了什么,这样您就不会被起诉,那种事情)。但如果真的如此,那么我就会坚持使用数据库,这使问题变得微不足道。