我们有一个非常简单的async web api定义为 public async Task> GetOrderById(长id)。 通常情况下,它运行速度很快,可以在100毫秒内完成。但有时,生产需要5秒以上。 下图是我们跟踪的慢速调用之一(最后一列显示了服务器收到api调用时方法的以ms为单位的偏移时间)。
在AuthenticationAttribute类(ActionFilterAttribute的子类)中调用'RedisDataBase.StringGetAsync'方法,使用'onActionExecutingAsync'异步方式,'var user = await redisCache.TryGetAsync(sessionId)'。
因此我们怀疑在'await'关键字之后切换回Asp.net线程期间API已被临时阻止。用AuthenticationAttribute类和同步调用redis服务器的'OnActionExecuting'替换'OnActionExecutingAsync'方法后,可以消除成本。
此外,我们删除了API中的AspNetSynchronizationContext以避免不必要的上下文切换,如下所示
public async Task<ResultModel<OrderModel>> GetOrderById(long id)
{
var capturedContext = SynchronizationContext.Current;
try
{
// Tricky, set current SynchronizationContext to null, to avoid capturing context during call await
SynchronizationContext.SetSynchronizationContext(null);
...
return new ResultModel<OrderModel>(order);
}
finally
{
// Restore the sync context
SynchronizationContext.SetSynchronizationContext(capturedContext);
}
然而,在callstack结束时,有时候还有几秒未知的成本。我的问题是这里发生了什么?是否有任何文章或方向我应该做进一步调查?
顺便说一句。目前在我们的项目中,我们仍在使用async&amp; amp;同步webapi和大多数api仍在使用同步。这是性能问题的根本原因吗?
并且,我们监控了PROD机器。它显示线程数约为120,并且有罕见的“请求排队”号码(峰值为8)。可能是由于Asp.net线程池号不足造成的吗?我们没有说明在我们的应用程序和web.config中设置线程数,而且我被告知iis 8.0的默认模式是auto,可以动态调整线程池号。