为什么ASP.net网站只需要很少的访问者就可以使用高CPU?
我们正在开发购物车网站,拥有超过10万种产品,是在流行的电子商务应用程序NopCommerce版本2.3的基础上开发的(只是为了向您介绍NopCommerce,它是在ASP.net版本4和MVC3的基础上开发的最受欢迎的开源电子商务应用程序之一)。该网站以两种语言和单一货币发布 大约有80个类别和30-40k个产品,它工作得相当好。我的意思是不太坏。但也不好。一旦添加了更多产品,性能问题就开始出现,表现为响应时间长(加载时间超过40-50秒)和CPU使用率高(利用率90-100%),只有10-20个用户 该服务器是四核Xeon处理器,内存为16 GB—Windows server 2008 R2,并且与另一个电子商务网站配合良好,在定制开发代码上有50k产品—几乎占用4-8%的cpu 我们使用缓存将主页特色产品和分类菜单存储在内存中,以避免数据库调用。它只改进了主页 后来为了解决这个问题,我们分析并发现是目录列表导致了从数据库中获取数据的大量延迟,这是经过精细规范化的。SQL server似乎占用了80-90%的CPU,而w3wp占用了30-40%的CPU,这导致网站始终保持100%的CPU,只有很少的访问者。我们咨询了几位专家,他们建议我们以二进制格式将非规范化数据存储在磁盘上,以绕过昂贵的数据库连接。我们做了一些研究,并使用Protobuff将非规范化的序列化对象数据存储到磁盘,磁盘只存储目录-产品列表页面所需的字段。但由于维护了一些规范功能,我们用来创建3个二进制文件。一个用于产品对象,另一个用于类别规范对象。这两个文件按类别列出。另外还有一个用于产品和规范映射的文件—占用了近5 mb的空间。当请求到来时,它读取序列化的二进制文件并将数据返回给对象。只有当有人根据规范过滤产品时,它才会读入映射文件 所以现在,每当出现分类产品列表页面的请求时,它都会检查是否有为该类别创建的二进制文件,如果没有,它会使用存储过程生成,并将对象保存为二进制文件以供以后使用。若文件存在,它直接从二进制文件中读取。通过这种方式,我们在加载此页面时避免了90%的db调用。只有很少的用户(appx.30-40),它就像一个魅力。我们能够将每个页面加载的响应时间减少到700-800毫秒。这是一个很大的改进,如果我们看看加载时间,但CPU仍然在较高的一面。不同之处在于:现在w3wp使用60-70%的cpu和20-30个访问者,而sql几乎不使用5-8% 但随着appx到100-120的用户越来越多,服务器开始挂起,w3wp的使用率不断超过100%。请求不再在几秒钟内送达,而是需要20-25秒才能加载。然后,大多数请求从未得到满足。当多个请求到达站点时,我们注意到了这一点 我们不擅长序列化和二进制格式化程序。但是我们认为cpu的高使用率是由文件读取操作引起的,或者可能是由于在每个目录页加载上执行的反序列化操作 我们现在正在寻找解决高CPU使用率的可能解决方案。问题可能是什么,我们应该在哪里解决它。您认为是文件读取操作还是反序列化导致了这种情况?我们应该将非规范化对象存储在db中吗?我们有什么办法来解决这个问题 等待您的专家意见为什么ASP.net网站只需要很少的访问者就可以使用高CPU?,asp.net,performance,serialization,shopping-cart,nopcommerce,Asp.net,Performance,Serialization,Shopping Cart,Nopcommerce,我们正在开发购物车网站,拥有超过10万种产品,是在流行的电子商务应用程序NopCommerce版本2.3的基础上开发的(只是为了向您介绍NopCommerce,它是在ASP.net版本4和MVC3的基础上开发的最受欢迎的开源电子商务应用程序之一)。该网站以两种语言和单一货币发布 大约有80个类别和30-40k个产品,它工作得相当好。我的意思是不太坏。但也不好。一旦添加了更多产品,性能问题就开始出现,表现为响应时间长(加载时间超过40-50秒)和CPU使用率高(利用率90-100%),只有10-2
提前谢谢。问题1:这个盒子上运行的是什么?如果我读对了,你有一个网站有50000个产品(没有提到用户或点击率),另一个网站有更多。当您堆叠站点时,您将看到一些降级,即使您的代码非常紧凑 问题2:在一个盒子上有所有层吗?您现在有了相互竞争的问题,并且可能会由于I/O操作而阻塞一些CPU绑定的线程 问题3:您是否对代码进行了审查,以确保正确的开发概念和方法(SOLID等)?否则,您可能会占用资源超过需要的时间,并导致问题 问题4:你介绍过吗?我指的是SQL Server和web应用程序。如果没有,你不知道问题可能在哪里,我怀疑在这个论坛上是否有人能帮助你 即使有数以百万计的“产品”,一个正确设计的数据库和网站也应该相当快。但是,不同的因素组合在一起代表性能。所有层上的所有部分都会影响应用程序 举个例子,我曾经咨询过一家公司,该公司开发了一款即将消亡的高性能电子商务应用程序。在代码评审中,所有的部分似乎都很好。在测试中,页面和数据库都运行良好。但他们从未强调过这一制度。如果他们有,他们会抓到这一点疯狂
//let's not focus on the magic string, okay? Think about static
private static SqlConnection connection = new SqlConnection("{conn string here}");
整个站点都在通过一个SQL连接进行过滤,因为一个开发人员不理解底层连接池的概念,并且认为对象初始化比通过静态“始终打开”连接进行过滤更容易成功
在您分析应用程序之前,这里没有可以回答的问题。一旦你发现一个问题并提出问题,有人会站出来说“这就是你解决问题的方法”。您可以在此问题中添加更多信息,但在确定问题而不是一般症状之前,您将一事无成。由于您有CPU问题,我怀疑反序列化是主要原因。在这种情况下,通过自己实现
ISerializable
接口,可以使序列化、反序列化速度提高近100倍。我以前用过这种技术
[Serializable]
public class TestObject : ISerializable {
public long id1;
public long id2;
public long id3;
public string s1;
public string s2;
public string s3;
public string s4;
public DateTime dt1;
public DateTime dt2;
public bool b1;
public bool b2;
public bool b3;
public byte e1;
public IDictionary<string,object> d1;
}
public void GetObjectData (SerializationInfo info, StreamingContext ctxt) {
SerializationWriter sw = SerializationWriter.GetWriter ();
sw.Write (id1);
sw.Write (id2);
sw.Write (id3);
sw.Write (s1);
sw.Write (s2);
sw.Write (s3);
sw.Write (s4);
sw.Write (dt1);
sw.Write (dt2);
sw.Write (b1);
sw.Write (b2);
sw.Write (b3);
sw.Write (e1);
sw.Write<string,object> (d1);
sw.AddToInfo (info);
}
public TestObject (SerializationInfo info, StreamingContext ctxt) {
SerializationReader sr = SerializationReader.GetReader (info);
id1 = sr.ReadInt64 ();
id2 = sr.ReadInt64 ();
id3 = sr.ReadInt64 ();
s1 = sr.ReadString ();
s2 = sr.ReadString ();
s3 = sr.ReadString ();
s4 = sr.ReadString ();
dt1 = sr.ReadDateTime ();
dt2 = sr.ReadDateTime ();
b1 = sr.ReadBoolean ();
b2 = sr.ReadBoolean ();
b3 = sr.ReadBoolean ();
e1 = sr.ReadByte ();
d1 = sr.ReadDictionary<string,object> ();
}