我有一个非常基本的Web API,它使用实体框架访问SQL Server后端。 api代码只是将请求传递给一些存储的proc并返回数据。没什么特别的。我正在使用.net 4.6(受限制是因为我运行的是Win 2008标准)。我没有使用async / await,因为我再次受到不支持该模式的旧日志记录库的约束。
我正在运行突发测试,其中创建30个线程,这些线程同时调用一个api端点。每个线程将在两次调用之间等待一秒钟。这将导致大约每秒20个请求的负载。
运行测试时,性能很好。呼叫在<50毫秒内返回。然后,大约两分钟(总是大约在同一时间),asp.net将开始对请求进行排队(根据perf mon),然后突然所有IIS都将挂起,并且我将超时。 CPU的峰值将达到99%,这很奇怪,因为我的代码都是异步等待DB调用的。在大多数情况下,性能不会稳定下降。很好,而且很快,直到突然之间不是。
我没有从我的代码中引发任何错误。在事件日志中没有任何用处。我拥有所有默认的IIS设置,除了在其他地方阅读该建议后,将http.sys队列限制从1000更改为5000,但这无济于事。
关于我可以尝试或观察或做的事情的任何建议吗?我有点迷住了。
编辑:错误地说我正在使用异步/等待。我不是。
这里是代码,减去变量分配和其他不相关的代码。 api调用输入top方法,然后输入第二个,然后输入第三个
[HttpGet]
[Route("productvariantassociationids")]
public LocatorServiceOutputModel GetProductVariantAssociationIds([FromUri]ProductVariantInput input)
{
var output = ProductService.GetProductVariantAssociationIds(input);
if ((output == null) || (output.Data == null) || (((List<int>)output.Data).Count == 0))
throw new HttpResponseException(System.Net.HttpStatusCode.NotFound);
return output;
}
public LocatorServiceOutputModel GetProductVariantAssociations(ProductVariantInput input)
{
var output = new LocatorServiceOutputModel();
var cachedData = CacheService.Get<List<ProductVariantAssociation>>(input.ToString());
if (cachedData != null)
{
output.Data = cachedData;
output.FromCache = true;
}
else
{
var associations = ProductRepository.GetProductVariantAssociations(input.ProductLineTypeID, input.ProductVersionTypeID, input.FormCodeTypeID, input.PremiumStructureTypeID,
input.DefinitionOfDisabilityTypeID, input.StateTypeID, input.ApplicationDate, input.InsurredAge);
var mappedAssociations = Mapper.Map<List<ProductVariantAssociation>>(associations);
CacheService.Set(input.ToString(), mappedAssociations);
output.Data = mappedAssociations;
}
output.Success = true;
return output;
}
public List<DBRiderBenefit> GetRiderBenefits(int? productVariantAssociationID = null, StateTypeEnum? stateTypeID = null, int? insurredAge = null, DefinitionOfDisabilityTypeEnum? definitionOfDisabilityType = null,
EliminationPeriodTypeEnum? eliminationPeriodTypeID = null, BenefitPeriodTypeEnum? benefitPeriodTypeID = null, MentalSubstanceLimitationEnum? mentalSubstanceLimitationID = null,
OccupationClassTypeEnum? occupationClassTypeID = null, OccupationGroupTypeEnum? occupationGroupTypeID = null, string occupationTypeValueText = null,
bool? isExercise = null, string callingSystemID = null, int? productVersionRevisionId = null)
{
using (ProductLibraryContext context = new ProductLibraryContext())
{
List<DBRiderBenefit> results = null;
if (productVersionRevisionId != null)
{
results = context.Database.SqlQuery<DBRiderBenefit>("exec [USP_ProductLibrary_Get_RiderBenefit] @ProductVariantAssociationID, @StateTypeID, @IssuredAge, @DefinitionOfDisabilityID, @EliminationPeriodTypeID, @BenefitPeriodTypeID, @MentalSubstanceLimitationID, @OccupationClassTypeID, @OccupationGroupTypeID, @OccupationType_ValueText, @IsExercise, @CallingSystemId, @ProductVersionRevision"
, paramProductVariantAssociationID, paramStateTypeID, paramInsuredAge, paramDefinitionOfDisabilityID, paramEliminationPeriodTypeID, paramBenefitPeriodTypeID
, paramMentalSubstanceLimitationID, paramOccupationClassTypeID, paramOccupationGroupTypeID, paramOccupationTypeValueText, paramIsExercise, paramCallingSystemId, paramProductVersionRevision).ToList();
}
else
{
results = context.Database.SqlQuery<DBRiderBenefit>("exec [USP_ProductLibrary_Get_RiderBenefit] @ProductVariantAssociationID, @StateTypeID, @IssuredAge, @DefinitionOfDisabilityID, @EliminationPeriodTypeID, @BenefitPeriodTypeID, @MentalSubstanceLimitationID, @OccupationClassTypeID, @OccupationGroupTypeID, @OccupationType_ValueText, @IsExercise, @CallingSystemId"
, paramProductVariantAssociationID, paramStateTypeID, paramInsuredAge, paramDefinitionOfDisabilityID, paramEliminationPeriodTypeID, paramBenefitPeriodTypeID
, paramMentalSubstanceLimitationID, paramOccupationClassTypeID, paramOccupationGroupTypeID, paramOccupationTypeValueText, paramIsExercise, paramCallingSystemId).ToList();
}
return results;
}
}