我的WCF数据服务(一)瓶颈

(说明:本篇文章的出发点是,解决把数据从数据库搬到WINDOWS服务(内存)中而产生的检索、更新等问题。按照CQRS原则对Q端进行支持分布式的优化。)

起初,公司的网站是个小网站,每天访问几千IP,虽然我们两个技术看起来很忙,其实老板让做的东西都是些零碎东西,差不多百分之八十工作都是页面改版。看这个页面不顺眼,就改一版;那个页面不顺眼,也改一版。有时候一个页面一年内能改四五次。后来公司来了个SEO,作网站的优化。不久,网站开始卡,有时一卡几分钟,后来一天要崩溃几次。这样的情况持续了一星期,老板受不了了,说咱们别老是改版了,看看是哪出了问题,于是有了这篇文章。

我开始分析日志,发现网站的流量也涨了不少,最重要的是,搜索引擎蜘蛛来抓的很频繁。有一个重要的列表页,平均每秒要抓三次到五次。我对SEO说:你能不能让蜘蛛少来,给网站都抓坏了。SEO说:不行,来的少了索引就少,对网站优化不利。我一想也是,毕竟做个网站要给别人看。于是就开始分析是哪里的瓶颈。
CPU,10%左右,正常。
内存,总数32G,用了20G左右,正常。
硬盘,资源监视器差不多顶格了。就是这里的问题了。
磁盘活动和 sqlserver profiler 的种种迹像表明:数据库查询占用了太多的硬盘资源,当硬盘IO跟不上的时候,IIS就会崩溃。
原因找到后,我尝试了多种解决方法:
1,缓存。网站的其他地方是有缓存的,但是这个列表页因为检索的条件很多,所以没有用。现在当然要试一下。结果是,没有用,检索条件大概有5个,每个条件的选项都在20个以上,缓存命中率超低,蜘蛛也不傻,不会只抓一个页面。既然缓存不行,再试别的。
2,索引。给数据表里涉及检索的几个字段,都加了索引。结果情况稍好一点,不过还是每天要崩溃个一两次,这显然不行。
3,生成静态。这个没有做在这个列表页,我算了一下,各种检索的条件加在一起,有上亿种组合。如果生成了静态页,我修改或新加了几条,是不是就得生成几千万条?这样当然不可行。不过生成静态还是可以用在其他地方,比如新闻的终端页面、各个频道的首页等。最后结果是,生成了静态的页面很快,这个重要的列表还是不行,一周还是会崩溃两三次。
4,CDN。这个以前就在用了,对用户来说打开速度会快些,但只限于静态内容,列表页这样的动态内容还是解决不了。
5,加服务器,这个只是想了想,那个时候服务器上还没有装固定硬盘的,加服务器就得需要一个DBA了,成本太高,老板不愿意。
在一系列方案没解决问题之后,我开始突发奇想。既然这个列表访问的次数这么多,能不能把所有数据都缓存在一个变量里呢?再优化各种访问,数据也是存在硬盘里的,如果一直放在内存里,不就快了么?那时还没有接触过CQRS,但还是想到了要把“读”操作给分离开来。这个列表的内容改变的不多,平均每天用户会发布几十个,最多几百个,相对于现有十几万的数据并不多。
于是说干就干,在所有抓取和访问很高的列表页的业务逻辑层,都加了一个静态变量 List<Model.XXX>,用来存放数据表的所有数据。用户或蜘蛛来访问页面的时候,直接根据条件 FindAll一下,再排个序分个页,就行了。
不到两天,就都做好了。事实证明,这一招非常管用,几个应用这种方法的列表页变得飞快,而且再也没有发生过因为硬盘IO不够而网站崩溃的情况。
在这种结构下,网站安安稳稳运行了两三年的时光。直到差不多一年半前。这期间是经过一系列小改动的。比如:
1,查询的方法,以前是多个查询参数的,后来凡是条件的查询的,都统一成 Predicate 委托了。
2,用户反应发布的东西出来的太慢,第二天才出现,要求快一点。忘说了,网站是每天凌里四点时回收,前一天的更新才会重新加载到静态变量。后来改成,用户发布了,也往静态变量里插入一下,这样就不会太慢了。
大概一年半之前,我对这样的结构不想容忍了。原因有几个:1,网站加载速度太慢,你可能还没忘记,老板要经常改版,所以我们经常要更新网站,每次更新,w3wp进程加载数据需要五分钟,这样显然不行。2,数据不统一。由于网站速度上的要求,我用NGINX做了静态前置、分布式。启用分布式的话,数据就要分离出来,不然用户在A进程发布了数据,A进程里的缓存就有了这个数据,B进程里的缓存就没有,这样体验非常不好。
于是我就把数据独立了出来,具体独立过程,下回分解。

猜你喜欢

转载自blog.csdn.net/zl33842902/article/details/52233478