Rails性能优化一则

抓取系统周末的时候突然发现抓取的速度慢了很多,比平时的速度大约慢了一倍,于是习惯性地开始逐个方向进行问题的排查:

1、先检查是否网速的问题,处在不同网络下的两台服务器都出现了抓取速度变慢的现象,并且经过实际测试速度很快,排除网速的问题;

2、检查服务器CPU、磁盘IO,发现CPU和IO占用均为较高值,有异常!而持续占用CPU的是mongodb进程;

3、于是按图索骥,查看mongodb的日志文件,发现了大量的重复查询:

1
2
3
4
5
Thu Aug 13 22:53:13.086 [conn34] command bidding.$cmd command: { count: "raw_htmls", query: { site_id: 613 } } ntoreturn:1 keyUpdates:0 numYields: 1 locks(micros) r:1075348 reslen:48 1047ms
Thu Aug 13 22:53:13.367 [conn31] command bidding.$cmd command: { count: "raw_htmls", query: { site_id: 19102 } } ntoreturn:1 keyUpdates:0 numYields: 12 locks(micros) r:2728177 reslen:48 1512ms
Thu Aug 13 22:53:13.687 [conn25] command bidding.$cmd command: { count: "raw_htmls", query: { site_id: 25226 } } ntoreturn:1 keyUpdates:0 numYields: 2 locks(micros) r:1720307 reslen:48 1155ms
Thu Aug 13 22:53:13.708 [conn32] command bidding.$cmd command: { count: "raw_htmls", query: { site_id: 15362 } } ntoreturn:1 keyUpdates:0 numYields: 2 locks(micros) r:2401703 reslen:48 1518ms
Thu Aug 13 22:53:14.124 [conn35] command bidding.$cmd command: { count: "raw_htmls", query: { site_id: 5278 } } ntoreturn:1 keyUpdates:0 numYields: 2 locks(micros) r:3090745 reslen:48 1641ms

持续频繁出现,应该就是影响mongodb的原因了!

4、接着开始逐个审查最近提交的代码,和查询BaseSite::Config相关的,结果发现了这样一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 已抓取的数量
def grabbed_count
Raw::Html.where(site_id: self.id).count
end

def options
_options = self.options||{}

# 第一次抓取
if self.grabbed_count==0
_options['max_link'] = self.limit || '100'
else
_options['max_link'] = '100'
end
....

_options
end

在options这个方法中,增加了一个是否首次抓取的判断,这个判断是通过grabbed_count方法来取出已抓取的页面数量来确定的。问题就出在options这个方法在抓取的过程中会重复调用很多次,也就导致了这个count语句不断在反复执行!

1
Raw::Html.where(site_id: self.id).count

找到问题,解决起来也就很简单了,增加一个临时的变量存储grabbed_count的结果,避免重复查询:

1
2
3
4
5
6
def grabbed_count
if @grabbed_count.nil?
@grabbed_count = Raw::Html.where(base_site_forum_id: self.origin_site_forum_id).count
end
@grabbed_count
end

提交代码,重启问题果然解决了!

经验总结:
在写查询数据库的语句的时候,心里面一定要预判这条语句在每次请求时执行的次数,以及加载数据的量,一时的疏忽可能导致的就是严重的性能问题。
另外就是看日志文件很重要,很重要,很重要!(重要的事情要重复三遍哦!)