在IIS上部署了一个WebAPI站点给客户的一个轮询程序调用,发现api被调用一段时间后CPU就满了。(IIS只部署了Webapi,没有其他站点)如下图:
这是任务管理器的截图:(这里是提前截图的,后面iisworker的进程CPU使用率到了90%+)
这是服务器配置:
这是api程序池配置:
业务场景是:我们提供了2个接口,1、新增订单;2、根据订单号返回发货状态;
新增订单:根据之前的需求,他们每天新增的订单就几十单,很零散;一般是当天下单当天晚上就会发货。(偶尔有几单是推迟一两天发货的)
根据订单号返回发货状态:现在设置的是服务轮询,每分钟执行,查询已下单未发货的订单状态。
上周出现这种情况的时候是他们每分钟执行一次,一次大概1000个请求过来,本来就是个很简单的接口,因为他们测试数据都没删所以有这么多,正常就大概几十到三四百的样,我也没做并发相关的设置和优化。
接口里面也是直接每次根据单号来查询数据库,然后返回结果;
代码如下:
查询数据库的代码,用的Dapper:
后面我担心再次遇到这种情况,就改了下代码用redis缓存了已发货的单号,每两个小时更新一次;今天他们改成了10分钟请求一次,一次大概几十-200个请求;今天晚上只有80几个订单,轮询调用接口,又把CPU占满了。
1 public IHttpActionResult GetDNS1(int OrderNum) 2 { 3 ApiResult result = new ApiResult(); 4 try 5 { 6 result.RS_FLAG = "Y"; 7 result.Data = "未发货"; 8 if (OrderNum <= 0) 9 { 10 result.RS_FLAG = "N"; 11 result.RS_MSG = "销售单号不正确!"; 12 return Json(result); 13 } 14 Nloger.Info(string.Format("销售单号:{0}", OrderNum)); 15 16 if (RedisHelper.KeyExists("SHtime")) 17 { 18 List<string> listsh = RedisHelper.ListRange("SH"); 19 if (listsh.IndexOf(OrderNum.ToString()) > -1) 20 { 21 result.RS_FLAG = "Y"; 22 result.Data = "已发货"; 23 } 24 //foreach (string item in listsh) 25 //{ 26 // if (item == OrderNum.ToString()) 27 // { 28 // result.RS_FLAG = "Y"; 29 // result.Data = "已发货"; 30 // break; 31 // } 32 //} 33 } 34 else 35 { new RedisHelper(); 36 string DBName = WebConfigUnit.HANADB; 37 string sql = string.Format("SELECT DISTINCT T0.\"DocEntry\" FROM \"{0}\".\"ORDR\" T0 LEFT JOIN \"{0}\".\"RDR1\" T1 ON T0.\"DocEntry\"=T1.\"DocEntry\" WHERE T0.\"CANCELED\"='N' AND T1.\"Quantity\">T1.\"OpenQty\" AND T0.\"DocDueDate\">'{1}'", DBName, DateTime.Now.ToString("yyyy-MM-dd")); 38 DataTable dt = new CommonLogic().ExcuteDT(WebConfigUnit.SBOConnectionString, sql); 39 string sh = "未发货"; 40 if (dt != null) 41 { 42 RedisHelper.DeleteStringKey("SHtime"); 43 RedisHelper.ListTrim("SH"); 44 RedisHelper.SetStringKey("SHtime", "Y", TimeSpan.FromHours(2)); 45 foreach (DataRow item in dt.Rows) 46 { 47 RedisHelper.ListRightPush("SH", item["DocEntry"].ToString()); 48 if (item["DocEntry"].ToString() == OrderNum.ToString()) 49 { 50 sh = "已发货"; 51 } 52 } 53 } 54 result.Data = sh; 55 56 } 57 Nloger.Info(string.Format("销售单发货状态:{0}", result.Data)); 58 return Json(result); 59 } 60 catch (Exception e) 61 { 62 result.RS_FLAG = "N"; 63 result.RS_MSG = e.Message; 64 Nloger.Error(e, "获取销售订单发货状态异常"); 65 } 66 return Json(result); 67 }
另外有个校验ip的验证。
1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 2 public class FilterAttribute : AuthorizeAttribute 3 { 4 public override void OnAuthorization(HttpActionContext actionContext) 5 { 6 //校验IP 7 string ip = HttpContext.Current.Request.UserHostAddress; 8 if (ip == "xxxxx" ) 9 { 10 base.IsAuthorized(actionContext); 11 } 12 else 13 { 14 actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new 15 { 16 code = HttpStatusCode.Unauthorized, 17 data = "", 18 message = $"IP:{HttpContext.Current.Request.UserHostAddress}没有调用服务的权限", 19 }); 20 } 21 } 22 }
数据库在另外一台服务器上,这台服务器上还有其他应用程序部署;
个人感觉是哪里资源使用后没释放掉,一直占用,导致后面的进程阻塞,但是又找不到在哪里。
求教各位大神,帮忙分析指导一下是我的代码哪里有问题?iis设置是否有问题?
应该如何优化改正?
谢谢!
这个地方的问题,open了,没释放,
不用open,daper会自动处理,打开释放
using会自动释放吧
@灬丶: using 释放的是IDbConnection对象,不是连接池里面最大连接数
@不知道风往哪儿吹: 但是using会给close掉的呀
就这么点代码很难看出什么来. 建议你dump一个内存快照. 拖到vs里面或者windbg里面 应该能很快找到问题.
35 { new RedisHelper();
这行代码是干嘛 每调用一次 new 一个redis 实例?