async nlog 如何与 IIS 中托管的 webapi 一起使用?

How async nlog works with webapi hosted in IIS?

我在 IIS write every request logs to database with nlog 中托管了 Web api。它按预期工作。我们的数据库与其他项目共享,最近在数据库中看到一些争用 - 这导致我们的一些网络 api 调用需要更长的时间或超时。 (当前超时为 20 秒,增加超时不是一个选项)

我正在考虑使用 nlog's async functionality 这有助于在单独的线程上异步写入日志。

在向客户端返回调用后,IIS 将如何处理这种漫长的 运行 过程? 任何一种见解都会有所帮助。

首先我们抛开IIS,只讨论application(不仅仅是webapi)和SQL之间异步的使用。无论你使用NLog的异步还是其他,它的工作原理都是一样的。

  • 当用户单击按钮时,应用程序将日志写入数据库。 这需要多个较小的任务,例如读取和填充数据 在内部对象中,与 SQL 建立连接并保存它。

  • 因为SQL在网络中的另一台机器上运行,并且在不同的环境下运行 过程,这可能很耗时,可能需要更长的时间。

  • 因此,如果应用程序在单线程上运行,那么屏幕将 在所有任务完成之前处于挂起状态,这是非常糟糕的 用户体验。

已经看到,在执行请求时,大约 70-80% 的时间被浪费在等待相关任务上。因此,异步编程可以最大限度地利用它,一旦任务传递给另一个进程(比如 SQL),当前线程将保存状态并可用于执行另一个任务。当 SQL 任务完成任何空闲的线程时,可以进一步处理它。

现在,我们来讨论一下IIS是如何处理异步的。 IIS 本身不拥有任何线程池,而是使用 CLR 线程池。 当 IIS 收到请求时,它会从 CLR 线程池中获取一个线程并将其分配给它以进一步处理该请求。所以IIS只是分配线程,CLR线程池决定何时添加或带走线程。

CLR 线程池包含工作线程和 I/O 完成端口或 IOCP 线程。当您在应用程序中进行异步 I/O 调用时,或者您的应用程序访问文件系统、数据库、Web 服务等时,运行时将使用 IOCP 线程。

使用NLog AsyncWrapper,那么应用程序线程将只有 NLog 自动捕获相关线程上下文的开销(基于目标 NLog 目标,例如 ${threadid}),并推送到 ConcurrentQueue .因此,应用程序线程不会受到 20 秒(或更多)的数据库超时的影响。

NLog AsyncWrapper 使用来自 CLR 线程池的后台线程(由计时器触发)从其 ConcurrentQueue 中写入挂起的 LogEvent。如果应用程序线程的日志记录速度非常快,而后台线程无法跟上(由于数据库超时),那么默认情况下它将开始丢弃 LogEvents(避免内存不足问题或阻塞应用程序线程)。