C# 当轻负载应用于.Net核心Web Api时,请求超时

C# 当轻负载应用于.Net核心Web Api时,请求超时,c#,asp.net-core,amazon-ecs,C#,Asp.net Core,Amazon Ecs,我有一个API,它基本上接收一个请求并将其推送到一个SQS队列,并不复杂 [HttpPost] public ActionResult Post([FromBody]object message, [FromHeader] string source) { if (message== null) return new UnsupportedMediaTypeResult(); if (PublishMessageToSQS(Json

我有一个API,它基本上接收一个请求并将其推送到一个SQS队列,并不复杂

[HttpPost]
public ActionResult Post([FromBody]object message, [FromHeader] string source)
    {
        if (message== null)
            return new UnsupportedMediaTypeResult();
        if (PublishMessageToSQS(JsonConvert.SerializeObject(message),source))
            return StatusCode(201);
        return StatusCode(500);
    }
    private bool PublishMessage(string message, string source)
    {
        try
        {
            RetryWhenException.Do(
                () =>
                {
                    SendMessageRequest request = new SendMessageRequest()
                    {
                        MessageBody = message,
                        MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
                        QueueUrl = "my queue",
                    };
                    if (!string.IsNullOrEmpty(source))
                        request.MessageAttributes.Add("source", new MessageAttributeValue()
                        {
                            StringValue = source,
                            DataType = "String"
                        });
                    var result = sqsClient.SendMessageAsync(request).Result;
                }, 3, 1000);
            return true;
        }
        catch (Exception e)
        {
            //log
            throw;
        }
    }
[HttpPost]
公共操作结果帖子([FromBody]对象消息,[FromHeader]字符串源)
{
如果(消息==null)
返回新的不受支持的MediaTypeResult();
if(PublishMessageToSQS(JsonConvert.SerializeObject(消息),源))
返回状态码(201);
返回状态码(500);
}
私有bool PublishMessage(字符串消息,字符串源)
{
尝试
{
RetryWhenException.Do(
() =>
{
SendMessageRequest=新建SendMessageRequest()
{
MessageBody=消息,
MessageAttributes=新字典(),
QueueUrl=“我的队列”,
};
如果(!string.IsNullOrEmpty(源))
request.MessageAttributes.Add(“source”,newmessageattributevalue())
{
StringValue=源,
DataType=“String”
});
var result=sqsClient.SendMessageAsync(请求).result;
}, 3, 1000);
返回true;
}
捕获(例外e)
{
//日志
投掷;
}
}
此API是容器化的,并部署到低资源机器(0.25 VCpu,512 MB RAM)上的AWS ECS

在API上应用轻负载(每秒10个请求)时,请求在一段时间后开始超时

在应用以下其中一项时,我停止接收超时:

1-使用更多资源(2个VCPU、4GB RAM)

2-使我的操作异步

[HttpPost]
public async Task<ActionResult> Post([FromBody]object message, [FromHeader] string source)
    {
        if (message== null)
            return new UnsupportedMediaTypeResult();
        if (await PublishMessageToSQS(JsonConvert.SerializeObject(message), source))
            return StatusCode(201);
        return StatusCode(500);
    }

private async Task<bool> PublishMessage(string message, string source)
    {
        try
        {
            await RetryWhenException.Do(
             async () =>
              {
                  SendMessageRequest request = new SendMessageRequest()
                  {
                      MessageBody = message,
                      MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
                      QueueUrl = "my queue",
                  };
                  if (!string.IsNullOrEmpty(source))
                      request.MessageAttributes.Add("source", new MessageAttributeValue()
                      {
                          StringValue = source,
                          DataType = "String"
                      });
                  var result = await sqsClient.SendMessageAsync(request);
              }, 3, 1000);
            return true;
        }
        catch (Exception e)
        {
         //log
         throw;
        }
    }
[HttpPost]
公共异步任务发布([FromBody]对象消息,[FromHeader]字符串源)
{
如果(消息==null)
返回新的不受支持的MediaTypeResult();
if(等待PublishMessageToSQS(JsonConvert.SerializeObject(消息),源))
返回状态码(201);
返回状态码(500);
}
专用异步任务PublishMessage(字符串消息,字符串源)
{
尝试
{
等待重新接收。是否执行(
异步()=>
{
SendMessageRequest=新建SendMessageRequest()
{
MessageBody=消息,
MessageAttributes=新字典(),
QueueUrl=“我的队列”,
};
如果(!string.IsNullOrEmpty(源))
request.MessageAttributes.Add(“source”,newmessageattributevalue())
{
StringValue=源,
DataType=“String”
});
var result=wait sqsClient.SendMessageAsync(请求);
}, 3, 1000);
返回true;
}
捕获(例外e)
{
//日志
投掷;
}
}
RetryWhenException代码:

public static class RetryWhenException
{
    public static void Do(Action action, int maxAttemptCount = 3, int retryInterval = 1000)
    {
        var exceptions = new List<Exception>();
        for (var attempted = 0; attempted < maxAttemptCount; attempted++)
        {
            try
            {
                if (attempted > 0)
                {
                    Thread.Sleep(retryInterval);
                }
                action();
                return;
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        throw new AggregateException(exceptions);
    }
}
公共静态类RetryWhenException
{
公共静态void Do(Action-Action,int-maxAttemptCount=3,int-retryInterval=1000)
{
var exceptions=新列表();
对于(var尝试=0;尝试0)
{
睡眠(重试区间);
}
动作();
返回;
}
捕获(例外情况除外)
{
例外情况。添加(ex);
}
}
抛出新的AggregateException(异常);
}
}
我知道异步可以释放线程,但是推送到SQS并没有那么昂贵,请求的数量也没有那么高


我真的不明白为什么我在应用如此低的负载时会超时,为什么异步会这样做,有什么解释吗?

我可以想象
PublishMessageToSQS
正在阻塞,它的异步变体将释放线程并在完成后立即返回。为了验证您是否需要与我们共享
PublishMessageToSQS
的代码。@二十个问题已更新,我知道旧版本的代码被阻塞,但我认为.Net core已为每个请求启动一个新线程。AFAIK ASP.Net core不会为每个请求启动一个新线程。相反,所有请求都由专用线程池处理(其线程数由KestrelServerOptions.ThreadCount控制,默认为处理器数的一半),并且不能保证每个请求都由单个线程提供服务。因此,任何长时间运行的同步I/O都会很快耗尽线程池。更多信息