在开始之前,有一点需要说明,优化策略事实上大部分情况下都不具备通用性,因为软硬件差异,用户使用习惯等等原因,可能会造成同一条优化策略在不同系统中 得到完全不同的效果,当然这里讲的都是一些具有普遍适用性的策略,但我还是建议你在应用这些策略时进行一下对比测试,就像第一讲开头所说,不要盲目优化。
Session优化
如果你的系统需要为每个访问者保存单独的Session信息(比如购物网站),那么session的存取速度将是影响系统性能的关键因素,目前可用的session存取策略有:
- 内存,快,相当快!但是如果你的应用挂了,或者由于其它什么原因需要重启,那么所有的session信息都会丢失,并且这种方式仅仅只能在单APP Server的应用中使用
- 文件系统,很容易使用,每个session对应一个文件,并且可以通过NFS或者NAS轻松进行容量扩展,但是速度较慢
- 数据库/ActiveRecordStore,使用简单(Rails的默认策略),但是很慢
- 数据库/SQLSessionStore,与上面一种方式类似,但是使用原始SQL取代了ActiveRecord,性能有一定提升,关于SQLSessionStore与ActiveRecordStore的对比可以参看这篇文章
- memcached,比SQLSessionStore稍微快一些,可扩展性较好,但是较难获取统计信息,关于memcached与SQLSessionStore的对比,请参看这篇文章
- DrbStore,在memcached不支持的一些平台上,可以选择DrbStore,但是性能比memcached要差一些,并且不支持session自动清除。
Cache优化
Rails默认支持一下集中Cache方式:
- Pages,很快,整个页面都被保存在文件系统,Web Server可以直接绕过APP Server完成请求应答,但是存在一些固有缺陷,比如无法应付需要用户登录的应用
- Actions,第二快,缓存controller的action执行结果,同时由于可以调用到controller的过滤器,因此可以很好的防止未授权用户访问。
- Fragment,缓存请求结果的一部分,也可以感知用户是否登录
Action Cache事实上是Fragment Cache的一种特殊情况,跟session一样cache也有以下集中存取策略可供选择:
- 内存,最快的方式,如果你的程序只需要在一个APP Server上运行,那么这无疑是最好的方式
- 文件系统,一般快,但可以使用正则表达式来刷新过期页面
- DrbStore,同文件系统相比,刷新过期页面更为快一些
- memcached,比DrbStore更快且易于扩展,但不支持使用正则刷新过期页面
ActionController
使用Components会对ActionController的性能造成较大的影响,我的建议是没有特别的理由,不要使用 components,因为调用render_component会引发一个新的请求处理循环,大部分情况下,component都可以使用helper 或者partials代替。
ActionView
对于每一个请求,Rails都会创建一个controller和view实例,并会将controller的action中创建的实例变量通过 instance_variable_get和instance_variable_set传递给view,因此不要在action中创建view中用不 到的实例变量
helper优化
首先是pluralize,可以看一下pluralize的实现,如果不给出最后一个参数,它会创建一个Inflector实例,因此不要写pluralize(n, ‘post’),应该写成pluralize(n, ‘post’, ‘posts’)
其次是link_to与url_for,由于需要查找路由策略,因此link_to与url_for可以说是最慢的helper方法,没有特别的需要,不要使用这两个函数。
<a href="/recipe/edit/<%=#{recipe.id}%>" class="edit_link">
look here for something interesting
</a>
会比下面这段快许多:
<%= link to ”look here for something interesting” ,
{ :controller => ”recipe”, :action => edit, :id => @recipe.id },
{ :class => ” edit link ” } %>
ActiveRecord
访问AR对象的关联对象相对而言会比较慢,可以使用:include提前获取关联对象
class Article
belongs to :author
end
Article . find ( :all , :include => :author)
或者使用piggy backing指定要获取的关联对象的某些字段,关于piggy backing的介绍请参看这篇文章
class Article
piggy back :author name, :from => :author, :attributes => [:name]
end
article = Article . find ( :all , :piggy => :author)
puts article .author name
另外需要注意的是,从数据库中获取的字段值一般来说都是String类型,因此每次访问可能都需要进行类型转换,如果你在一个请求处理过程中需要进行多次转换,那么最好对转换后的值进行缓存。
还有,根据我对一个应用的分析,大约有30%的时间花在了字符处理上,另外30%时间花在了垃圾收集,还有10%用于URL识别,因此在数据库中缓存格式化后的字段可以大大减小字符处理的开销。
这一讲就先到这里,更多的优化技巧,请关注后续文章。

