0

我们正在致力于购物车网站与超过1万卢特产品,在流行的电子商务应用程序的顶部 - NopCommerce 2.3版(只是向您介绍NopCommerce - 这是一个最好的&流行的开源电子商务应用程序,电子商务应用程序构建于ASP.net版本4和MVC3之上)。该网站出版了两种语言和单一货币。为什么ASP.net网站只有很少的访问者需要高CPU?

大约80个类别和30-40k产品,它工作得很好。我的意思不是很糟糕。但它也不好。只要添加了更多产品,性能问题就开始出现诸如响应时间长(加载超过40-50秒)和CPU使用率高(利用率90-100%)等仅有10-20个用户的症状。

服务器是四核至强处理器采用16 GB的RAM - 在Windows Server 2008 R2,并且工作正常多一个电子商务网站与50K产品定制开发代码 - 几乎没有服用4-8%的CPU。

我们使用缓存来存储主页特色产品和类别菜单在内存中,以避免数据库调用。它只改进了主页。

后来修复问题,我们分析并发现它是目录列表,这导致很多延迟从数据库中获取数据,这是很好地规范化。 SQL服务器似乎需要80-90%的CPU,w3wp占用了30-40%的cpu,这使得网站上只有少数访问者持续不断地导致100%cpu。我们咨询了一些专家,他们建议我们以二进制格式在磁盘上存储非标准化数据以绕过昂贵的数据库连接。我们做了一些研究,并使用Protobuff将非标准化的序列化对象数据存储到只存储目录 - 产品列表页面所需的那些字段的磁盘上。但是由于维护了我们用来创建3个二进制文件的一些规范功能。一个用于产品对象,另一个用于类别说明对象。这两个文件是每个类别。还有一个用于产品和规格映射的文件 - 占用近5 MB。当请求到达时,它从序列化的二进制文件中读取数据并将数据返回给对象。只有当有人根据规格过滤产品时才会读入映射文件。

因此,现在无论何时对类别产品列表页面发出请求,它都会检查是否为该类别创建了二进制文件,是否使用存储过程生成二进制文件,并将对象保存为二进制文件以备后用。如果文件存在,它直接从二进制文件中读取它。有了这件事,我们在加载这个页面时避免了90%的数据库调用。只有几个用户(约30-40),它就像一个魅力。我们可以将每次页面加载的响应时间缩短到700-800毫秒。如果我们查看加载时间,这是一个很大的改进,但CPU仍然处于较高水平。不同之处在于:现在w3wp使用60-70%cpu与20-30个访问者,sql几乎不使用5-8%。

但随着更多的用户appx达到100-120,服务器开始挂起,并且w3wp持续使用超过100%。请求不再以秒为单位,而是需要超过20-25秒才能加载。然后大多数请求从未被服务。当有多个请求来到网站时,我们注意到了这一点。

我们并不擅长序列化和二进制格式。但是我们认为CPU的高使用率是由文件读取操作引起的,或者可能是由于在每个目录页面负载上执行了反序列化操作。

我们正在研究可能的解决方案来解决高CPU使用率问题。可能是什么问题,我们应该在哪里寻找解决办法。你认为,这是文件读取操作还是反序列化造成的?我们应该在db中存储非规范化对象吗?我们有什么替代方案来解决这个问题?

等待你的专家意见。

在此先感谢。

+3

配置您的代码。没有必要“思考”导致高CPU使用率的原因。找出。 – AakashM 2012-02-10 15:49:04

+2

您应该剖析您的代码(http://stackoverflow.com/questions/3927/what-are-some-good-net-profilers)并找出问题所在。另外,如果你看看NopCommerce论坛,你会发现有很多抱怨性能问题......这些问题没有解决...... – 2012-02-10 15:56:00

+0

它是一个迟到的反应,但我们已经设法解决这个问题。我们通过使用几种优化技术优化nopCommerce并将Apache Solr与它集成来解决了这个问题。我们构建与可用于解决问题的插件相同的插件。更多细节可以在这里找到http://www.nopaccelerate.com/?utm_source=stackoverflow&utm_medium=forum&utm_campaign=reference – Krunal 2013-03-02 13:36:48

回答

0

问题1:什么都在这个盒子上运行?如果我阅读正确,你有一个网站有50,000个产品(没有提及用户或点击),另一个网站有更多。在堆叠网站时,即使代码非常紧密,您也会看到一些降级。

问题2:您是否在一个盒子上有所有图层?您现在有相互竞争的担忧,并可能由于I/O操作而阻塞一些CPU绑定的线程。

问题3:你有代码审查,以确保正确的发展理念和方法(固体等)?如果没有,您可以将资源放在比需要更长的时间并导致问题。

问题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连接筛选,因为一个开发商没有理解底层连接池和思维对象初始化的概念会更一击的不是通过静态过滤“永远在线”的连接。

在您简介应用程序之前,您在这里没有问题可以回答。一旦你发现问题并提出问题,有人可以加强并说“这是你如何解决问题”。您可以为此问题添加更多信息,但在确定问题之前,而不是一般症状之前,您无处可去。

+0

嗨,格雷戈里,谢谢你的见解。以下是答案: 1.在同一台服务器上,我们有一个购物车网站,其中包含50k个带有appx的产品。每天超过1000位游客。 – Krunal 2012-02-11 04:45:14

+0

2.是的,他们都在一台服务器上。包括两个网站管理面板。 3.是的,我们已经对它进行了审查,并修改了范围。 4.我们有简介的SQL和应用程序。早期的SQL引起了问题,但现在它是一个应用程序。我们从二进制文件读取并返回到模型的控制器是应用程序受到影响的地方。 我的问题是:1.当请求到来时,使用二进制文件存储非标准化数据并从二进制文件读取是否正确?你有什么建议?为什么? – Krunal 2012-02-11 04:59:52

+1

你的问题的答案真的取决于很多因素。一般来说,最大的痛点在哪里?对于异常数据,只要数据库具有结构(这是一个简单的介绍,这是一个很长的描述等),数据库可以正常工作。对于非结构化数据,CMS是一种选择。例如,使用FAST的SharePoint可以工作。这实际上取决于数据的性质。现在,控制器正在做什么工作?而且,可以提前完成一些工作,然后存储在某个地方?如果你能找到长路和缩短它,你会获得很多好处。 – 2012-02-23 15:21:18

1

由于你有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; 
} 

实现ISerializable的,这样就可以做自定义序列化和反序列化。

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>(); 
} 

这不仅使有效载荷10-100倍较小,但也受到10倍到100倍,有时提高性能。

另一件事,看看你是否有任何循环通过数千个对象的大循环。也许你有不太理想的linq查询。那些有时候是CPU猪。

最后,我会推荐我见过开发人员做的十大缓存错误,特别是在使用分布式缓存时。

http://www.codeproject.com/Articles/115107/Ten-Caching-Mistakes-that-Break-your-App

+0

如果你实现了这个,你需要为所有对象再次生成序列化的二进制文件。否则,现有文件不会反序列化。 – oazabir 2012-02-12 12:32:03

+0

我们已将反序列化的对象存储在对象缓存中,并且每当从内存中选择退出时,都会从数据库中检索它。我们更改为db来存储二进制对象而不是文件系统。虽然我们需要测试它。 – Krunal 2012-02-15 10:08:49

+0

你试过了ISerializable实现吗?看到改进? – oazabir 2012-02-16 15:08:51

0

答案数据库的“问题”是解决您的设计不佳的数据库。数据库“问题”不是数据库能力的根本问题。这是你设计时的问题。

修复以多种形式出现,但它始终是答案。数据库“问题”总是与许多不同类型的问题相同。

这个故事的寓意,从来没有从一个对修复数据库问题一无所知的人那里得到数据库建议,并建议你应用胶带。所有数据库问题的答案是将数据和计算尽可能地靠近数据库

从数据库移动的数据越多,越会加剧问题并且线性降低解决方案的可伸缩性。不要听试图“修复”数据库的非数据库开发人员。

+1

同意再说! – Krunal 2013-05-22 13:46:18