请考虑一下代码 class Test private def self.test puts ‘arst’ end def test puts ‘arst’ end class << self def test2 puts ‘arst’ end private def test3 puts ‘arst’ end end end Test.test Test.test2 begin Test.test3 rescue StandardError => e p e end begin Test.new.test rescue StandardError => e p e end 结果为 arst arst #<NoMethodError: private [...]
问题根源 原始的ActiveRecord会话仓库很慢。对于低流量的网站而言没有什么问题,但是对于大一点的而言就慢了。首先,它的慢是因为ActiveRecord本身比较慢。虽然这是一个强大的ORM框架,但对于像会话管理这种简单的任务而言就是杀鸡用牛刀了。 还有其他的解决方案如cookie会话仓库(会话长度有限,不能在会话中存放敏感数据),memcached(无法持久化+难以实现高可用性方案)。 这就是为何要创建SqlSession仓库的原因。它直接操作mysql的数据库API,要比原始的AR会话仓库快很多。不过有时候它还是比较慢,因为: 每次访问都会创建、更新会话 – 任何机器人或者偶然的访客都会在数据库中创建一条会话记录,最后导致会话表里面会有成千上万的无用记录,但其中99%的访问其实是不需要任何会话更新的。 它使用32位字符串作为会话记录的键 – 所有RDBMS在处理字符串索引都要比整数慢很多,所以使用整数更好,然而我们的会话ID非常长,同时这些会话仓库都直接使用他们作为表索引。 使用了auto_increment 主键,对于MySQL 5.1.21之前的版本都会导致InnoDB使用表级锁。在不必要的插入上使用表级锁会给大型网站造成奇怪的问题。 解决方案 FastSessions Rails插件便是作为对于以上几个问题的解决方案而诞生的。 首先,我们从会话表中去掉了id字段,所以我们无须用到auto-increment锁。接下来为了让查找更快,我们使用了以下这些技术:不使用(session_id)作为查找索引,使用(CRC32(session_id), session_id)——双列键,可以帮助MySQL更快地找到会话记录因为键的基数更高(这样,mysql可以更快地找到记录而不用检查很多索引行)。我们测试过这种方法,在大会话表中显示了10-15%的性能提升。 最后,也是最强的优化是,对于空会话不创建数据库记录,同时如果数据没有在请求处理过程中没有更新过,则会话数据不会存回数据库。这个更改基本上可以减少50-90%的插入数量(根据应用程序的情况)。 那么,你肯定在想,用了这个插件之后会话究竟能快多少?这很难说。结果要看你是怎么操作会话的:如果你很少更改会话数据(如登录时储存用户id),那么可能会有90%的性能提升,但如果每次访问,你都要给用户会话写入些信息(比如最后一次访问时间last_visit_time),那么根据服务器的负载和会话表的大小,可能有5-15%的性能提升。 你只需要安装一个简单的插件,便可以自动实现上面这些更改。 我们解决了AUTO_INC锁的问题并去掉auto-increment键之后,又引入了一个新的问题,我在这里想说一下。这个问题是这样的。InnoDB会根据主键将所有数据分组。这意味着当我们使用自增长主键并向表插入记录时,会话记录会被组到一起,顺序地存储在磁盘上。然而如果使用比较随机的值(如一个随机会话id的crc32值)作为主键,那么每一个会话记录会被插入到属于它自己的不同的地方,那么会产生一些随机I/O,这对于I/O有限制的服务器不是很理想。所以,我们决定让用户自己选择在部署的时候使用何种主键,当你想在MySQL 5.1.22+上使用这个模块的话,可以设置 CGI::Session::ActiveRecordStore::FastSessions.use_auto_increment = true 这样在InnoDB中会连贯地插入数据。另一个情况当你的MySQL服务器的I/O有限制,不想因为随机主键而增加随机I/O,也可以这样设置。 如果你不想丢失使用AR会话插件创建的旧会话数据,你可以设置 CGI::Session::ActiveRecordStore::FastSessions.fallback_to_old_table = true 这样当某些session_id在新的会话表中找不到的时候,就会回去访问旧的会话表。旧会话表的名字可以使用CGI::Session::ActiveRecordStore::FastSessions.old_table_name 变量进行设置. 这个选项会使会话变慢所以我建议只要在升级到新会话表的时候才使用。在这种情况下,新的会话数据就会存入新表中,当到了会话超时期限的时候,就可以删除旧表了(我们用了两个月的期限,过了两个月之后,我们就可以删除旧表,并将此选项关闭。)。 安装 安装FastSessions插件十分简单,只需以下几个步骤: 将该插件代码从我们的SVN库中安装到vendor/plugins目录中(可以使用./script/plugin install安装,或者piston import命令进行安装——看你喜欢)例如: $ piston import http://rails-fast-sessions.googlecode.com/svn/trunk/ vendor/plugins/fast_sessions 在config/environment.rb文件中启用ActiveRecord会话仓库: Rails::Initializer.run do |config| …… config.action_controller.session_store = :active_record_store …… end 为新的会话表创建数据库迁移: [...]
我之前写的文章《浅析Ruby on Rails部署方案》受到不少同学的关注,在此首先感谢大家。 但是也有同学对此提出了一些疑问,我经过检查,发现文章确实存在很多漏洞和不足: Lighttpd作为负载均衡反向代理时,无论是链接FastCGI还是HTTP后端,KeepAlive链接默认都是关闭的 Nginx的FastCGI模式,默认也是关闭持久链接的 缺少了一些重要的前后端搭配的方式 对于Rails应用的内存占用也应该考虑在内 我会针对这一些问题,重新设计测试案例,并重写该文章。再次感谢大家的关注。
有问题或评价,请联系: socialface@gmail.com 程序截图: http://www.socialface.com/slapp/screenshot.jpg 简介 欢迎来到Slapp的教程。本文的主要目标是通过构建一个简易的聊天墙应用来介绍一下Merb微框架的主要组件。 本文其次的目标是成为最好的Merb开放教程并能不断更新。同时,我们希望本教程可以逐渐变得丰富来展现Merb框架的所有方面和开发方式。 许可 This tutorial is Copyright 2008 Social Corp. and is licensed under a Creative Commons Attribution-Noncommercial 3.0 United States License, available at: http://creativecommons.org/licenses/by-nc/3.0/us/ 相关的源代码以MIT形式的开发源代码许可: http://www.socialface.com/slapp/source 直接浏览代码: http://gitorious.org/projects/slapp/repos/mainline/trees/master 也可以直接下载: http://www.socialface.com/slapp/binary 参与人员名单 本教程最初由来自#merb的Slurry撰写。Slurry在撰写本文时主要参照了Merb的官方文档[^a]以及#merb IRC频道的内容。 在学习Merb的RSpec的过程中,还咨询了John Hornbeck的Blerb[^b],参考了Tim Connor的“Isolate controller and view testing in merb”一文[^c]——虽然帮助很大,真正掌握Merb/Rspec还是得益于来自#merb的benburkert。 中文版由ShiningRay翻译 前期决定 设计上来说,Merb是一个ORM无关的框架。当然,这仅仅是表示有不同的模型层可以选择。对于Merb v0.9.2来说,包括:DataMapper、Sequel和ActiveRecord(来自Rails)。 尽管DataMapper和Sequel都是很好的选择,但现在关注Merb的主流人群基本上都是来自Rails背景;因此,我们在本教程中会继续使用ActiveRecord。 1.) 创建模型 [...]
2006初,我接到了公司分配的一个遗留项目,让我负责一个基于C/S的系统的服务器端。其实是系统是基于HTTP协议的,因为负责客户端的同事对于服务器端编程不甚了解,虽然使用PHP对熟悉C++的他来说是驾轻就熟,但是在进一步实现更多的功能和更高的性能上就捉襟见肘了。项目是在非常突然的情况下交给我的,因为该同事在客户端上有更多的事情要做。我在分析了他的数据库结构和PHP源代码之后,决定按照与客户端的通讯协议重写他的服务器端。为了能应付老板苛刻的时间限制,我打算使用正在学习的Ruby on Rails。后来,项目在功能上非常顺利地交付了。 两年过去了,随着客户端数量的不断增加、客户端功能的增加、与服务器端交互数据的增加、老板对功能的要求不断增加,我在这个项目上走了不少弯路,尤其是在部署——或者说是架构——方面。 我遇到的最大的问题就在于并发链接数上。服务器与客户端的每次交互的数据量并不大,但内容无法缓存。起初用的是Nginx/Apache+Mongrel 的部署方式,但当遇到大量并发请求时,常常会遇到Mongrel进程死掉的情况。而客户端的用户在无法登录客户端的时候,经常会反复尝试,加重了服务器的负担、导致最后所有的Mongrel进程都挂掉。 最后,经过不懈努力,在现有的3台低端服务器上,可以满足每天500万次的请求。在这里,我将我的一些心得和研究成果总结出来,与大家分享。 文档地址:http://docs.google.com/Doc?id=ddcvzh74_28f9xppqfh 文章发布在Google Docs上,欢迎大家在其上做批注,有意见和建议也可以在此留言。文章按照知识共享“署名 3.0 中国大陆”许可协议发布,欢迎转载。
Redmine是基于Ruby/Rails的一个项目管理软件。比较类似的则是基于Python的Trac,相比之下,Redmine有很多优势: 简单的安装、配置和部署Redmine利用rake、rails的db migration安装很方便,Trac则要用到命令行的trac-admin进行配置,以及每个项目有单独的ini配置文件 方便的用户和权限管理Redmine支持多LDAP认证、还支持用户自己注册,然后通过邮件激活。Trac依然需要使用trac-admin来配置,而且默认的用户登录方式是HTTP验证,基于cookie的还需通过插件实现 基于Web的多项目管理Trac创建和配置新项目需要使用trac-admin AjaxRedmine通过Ajax在某些方面提供了更好的用户体验,如代码仓库的浏览 多语言包括简体中文 多种SCM包括SVN、CVS、Darcs、Mercurial、Bazaar,是通过调用它们的可执行文件来实现的。 trac的很多功能都需要通过trac-admin在命令行方式下进行配置,不易上手,这方面Redmine则十分方便。 其实功能方面,Redmine更多地是模仿Sourceforge的功能,比如新闻、文档、下载等,目的是建立这种适合团队协作的平台。我估计以后Rubyforge可能会迁移到Redmine上去。
虽然前一段时间Ruby社区推出了很多重大的更新,如RubyGems发布了1.0,Rails发布了2.0,Ruby发布了1.9测试版。但是却潜藏了很多危险。比如在Windows平台下,升级了RubyGems之后,会导致我现有的Mongrel无法启动,原因在于RubyGems1.0修改了系统的识别,将mswin32改成了x86-mswin32,从而导致gem_plugin无法正确定位相应gem。 修复的方法也很简单,只需要先删除Mongrel再重新安装: ::先升级RubyGems到1.0 gem update –system ::卸载再重装Mongrel gem uninstall mongrel gem i mongrel 另外还在一些人的BLOG中发现Rails2.0刚发布时,是要求使用RubyGems0.9.5,也会出现一些问题。幸而我暂时没有迁移到Rails2.0上,也还没有遇到问题。 从这一个事件上也可以看出Ruby社区相对于Python/Perl的社区来说,还不是十分的成熟。
来自Ruby官方网站的最新消息,Matz已经发布了1.9的开发版本作为献给大家的圣诞礼物。 1.9的性能较1.8有大幅提升(请参考相关测试结果),并且添加了大量新的语言的特性。 这无疑对于Ruby爱好者是一个福音,但前不久刚发布Rails 2.0还不能完全正常运行于Ruby 1.9之上,包括诸如Mongrel之类的其他组件,所以在很长时间内Ruby 1.8将仍然是主流的平台。不过相信Ruby社区和相关社区的朋友们会一起努力,使这个迁移快速而顺利地完成(就像当年Python 2.5发布的时候)
问题描述: 当使用memcached并将Model对象保存在其中时,若要取出这个缓存对象时,可能会找不到Model的类,并抛出“Undefined Class/Module SomeClass”的错误。 例如: if not (genres = Cache.get(key)) genres = Genre.find(:all, :condition => “platform_id = 1″) Cache.put(key, genres, 60*60*24) # cache for 1 day end 解决方案 要解决这个问题,可以在引用到该对象之间,先引用其类。比如,在前面的代码前面加入要引用的类Genre: Genre if not (genres = Cache.get(key)) genres = Genre.find(:all, :condition => “platform_id = 1″) Cache.put(key, genres, 60*60*24) # cache for 1 day end 还有更好地方法是在Controller的before_filter中加载所依赖的所有Model: before_filter :preload_models [...]
原文:http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done 但是,目前仍应该将所有的必须的gems(除了Mongrel)freeze到正在维护的Rails应用中。请运行: rake rals:freeze:gems