rails3项目解析之4——异步和定时任务

标签: rails3 项目 解析 | 发表时间:2011-08-01 11:31 | 作者:(author unknown) 董玉伟
出处:http://www.iteye.com
上一篇:rails3项目解析之3——redis
下一篇:rails3项目解析之5——rails on windows


在当前的web应用中,尤其是互动概念越来越大行其道的今天,为了加快网站的反应速度,提高用户体验,有些操作不能等到所有的后台处理完成之后再展现给用户,因此需要引入异步任务机制。典型的应用场景如用户注册完成之后的确认邮件发送,如果等邮件发送成功再给用户返回确认信息,这个时间间隔在用户体验上是难以接受的。另外,由于用户量和数据量的庞大,某些数据在平时只能做增量处理,需要在例如凌晨负载较小时对数据进行集中处理,这就需要引入定时任务。

1、技术选型

针对异步和定时任务的组件选择,我们当时颇费了一番功夫。可选的很多,而且网上也没有压倒性的信息可供参考和选择,因此只能对几种解决方案进行了概略地尝试和评测。

1.1 crontab+rake(runner)。据我所知,这种方式有些项目在使用,优势是比较简单,没有附加的学习成本,但这个方案很快就被我们否决,原因是和操作系统绑定最为紧密,权限上也要做一些相应的调整,不利于项目的自动发布,而且rake命令需要启动加载整个rails项目环境,速度和资源占用上有较大的劣势。

1.2 workling+starling。传说这是twitter当初自己做的东西,我安装试用了一下,评价仅仅是可用。后来经过几次测试,感觉配置和使用比较复杂,而且这套组件已经很长时间都没有更新了,看起来没什么活力,估计马上就要被宣布停止使用而碾碎掩埋了。遂弃用之。

1.3 另外象delayed_job、background_job、background_fu等等这些组件,不是功能不全不能满足需求,就是消息队列基于数据库,要么就是扩展性不好没有想象空间,因此都不合乎项目的要求。

1.4 最后,选定了resqueresque-scheduler套件作为异步/定时任务的组件。其优点在于功能比较强大,可扩展性好,已有数个各种不同目的的扩展可用。使用redis作为消息队列的存储,比较与时俱进,与操作系统无绑定,完全在rails框架内运行,配置和使用简单可理解。而且它是github贡献出来的开源组件,目前似乎仍然在github上跑着,稳定性无庸置疑。所以相信它一定能够满足我们项目的需求。至于你信不信,我反正是信了。

2、异步任务

2.1 异步任务主要由resque来实现。其原理是每当定义一个任务,就把这个任务写入redis的一个消息队列,resque的worker再轮循从队列中取消息,根据取出的消息构造任务,然后执行。

执行任务是resque的worker来完成的,需要启动一个rake命令来产生worker:
rake --trace resque:work QUEUE=* VERBOSE=1 RAILS_ENV=production


2.2 调用enqueue方法来产生异步任务。
Resque.enqueue(Sendmail, email)

第一个参数是执行该任务的类,在这个类中,需定义一个类方法perform
class Sendmail
  def self.perform(email)
    。。。。。。
  end
end

除了第一个定义类的参数,enqueue方法中其它的所有参数,都将被作为参数传入perform方法。

这里需要注意的一点就是,resque在根据enqueue方法构造消息存入redis的时候,保存的是json的格式,也就是说,enqueue传入的参数,必须是属于简单类型,可被转化为json的,例如string、integer等,不能传入一个复杂类或自定义类的实例。如果必须要在任务中使用对象,则可以传入id,执行任务时再从数据库中取对象,或者是把实例用marshal序列化传入。等等。但序列化的方式一般不推荐使用。

3、定时任务

resque的异步任务只能是立即执行的,如果要求这个任务延时比如1个小时后再执行,或者是要求某些任务在某个时刻定时执行,则需要使用resque的定时任务插件resque-scheduler。

3.1 resque-scheduler的原理是,底层使用rufus-scheduler启动一个定时器,定时器从配置文件中获取所有的任务列表,根据列表中的指定时刻,产生resque任务,插入redis消息队列,然后该任务被resque的worker执行。

rufus-scheduler可以使用plain方式,也可以使用eventmachine方式。plain方式就是启动一个loop轮循,比较简单粗糙,因此为了保证健壮性,建议使用eventmachine。无需特别配置,只需在项目中加入eventmachine的gem,rufus即可自动识别并使用EmScheduler模块。

需启动一个rake命令,来调入scheduler配置文件并定时产生各项任务:
rake --trace resque:scheduler RAILS_ENV=production


3.2 定时任务写在scheduler.yml文件中,由resque-scheduler的rake命令调用。典型的任务格式为:
redis_bgrewrite_aof:
  cron: "0,20,40 * * * *"
  class: RedisRewriteAof
  args: 'localhost:6379'
  queue: application
  description: "每20分钟重写redis的binlog"

cron就是crontab所使用的格式,免除额外的学习成本,即看即用。
class就是resque的执行类,如上文所述,在该类中定义类方法perform来执行任务。
args是传入perform方法的参数,同样,必须是可以json encoded的简单类型。
queue是队列名称,不指定的话就使用默认队列。

其中,cron也可以更换为every指令,every: 3m,就是每3分钟。

4、异常退出和解决

在实际使用中,发现rake resque:work和rake resque:scheduler两个命令驻留进程后,都会因为某些任务执行时一些莫名其妙的异常而全部退出。trace日志也明确地指出了这一点。因此需要在这两个rake命令之上,加入监控脚本,在rake退出之后重新启动之。

4.1 使用rufus-scheduler启动一个监控,每秒调用系统命令执行一次扫描:
ps -eo pid,command | grep resque | grep -v grep

计算正在运行中的worker的数量,如果低于某个指定值,即说明有某个worker已异常退出,则启动rake命令再次加入rake resque:work直至达到指定值。

4.2 使用rufus-scheduler启动一个监控,每秒调用系统命令执行一次扫描:
ps -eo pid,command | grep resque:scheduler | grep -v grep

如果没有找到含有resque:scheduler的进程,则调用rake命令重新启动之。

5、高可用

5.1 resque:work的高可用比较好解决,同时启动两台甚至多台服务器,在每台服务器上都运行监控脚本启动数个worker,根据系统的负载做出一定的冗余,这样即使有一台服务器宕机也不会影响到任务的执行。

5.2 resque:scheduler稍微麻烦一点。因为不能启动两台服务器同时跑定时任务,否则每个任务都会被执行两次,造成资源的浪费和潜在的问题,何况这样也不优雅,简单粗暴得让人鄙视。最终我们采用了与keepalived相结合的解决方案。在resque:scheduler监控脚本中,加入一个判断命令:
ip a | grep 10.0.0.100

其中10.0.0.100是keepalived的VIP(虚拟IP),判断如果该VIP正在本机,则监控脚本启动rake resque:scheduler。如果运行scheduler的服务器宕机,则10.0.0.100的VIP会马上跳到另一台备用服务器上,该服务器上的监控脚本会扫描到该VIP的存在,从而在本地启动rake resque:scheduler命令,继续产生定时任务。

6、管理界面

resque自带一个简单的管理界面,你可以在这个界面上查看队列中的任务,当前正在执行的任务,已执行完毕的任务,执行成功和错误的详情。并且可以手动清空队列。等等。虽然都是些常用功能,但一图顶千言,看起来直观方便,也聊胜于无而已。





7、仍存在的问题

到目前为止,resque套件运行还算正常,该做的事都做了,不该做的事也不会做。但仍然还有一个问题迟迟未能解决。

worker执行任务,到公司oracle服务器和搜索引擎中获取数据时,有时会出现假死现象,就是说没有取得数据,但oracle数据库和搜索引擎的http接口却一直也不给超时中断的指令,任务就一直挂在那里,始终占用一个worker进程。而且我们也针对worker加入了使用SystemTimer的timeout强制中断措施。但这个timeout时间短的时候有效,时间一长比如几个小时,就无效了,到了超时时间也不会中断,真是奇哉怪也。尤其是timeout,按说SystemTimer是很可靠的,但至今我们都找不到准确的原因所在。这只能说是一个奇迹。如果你非要问我为什么,我只能告诉你,它就是这样发生了。

作者: seamon 
声明: 本文系ITeye网站发布的原创文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!

已有 16 人发表回复,猛击->>这里<<-参与讨论


ITeye推荐



相关 [rails3 项目 解析] 推荐:

rails3项目解析之4——异步和定时任务

- 董玉伟 - Ruby编程论坛最新讨论 - ITeye
上一篇:rails3项目解析之3——redis. 下一篇:rails3项目解析之5——rails on windows. 在当前的web应用中,尤其是互动概念越来越大行其道的今天,为了加快网站的反应速度,提高用户体验,有些操作不能等到所有的后台处理完成之后再展现给用户,因此需要引入异步任务机制. 典型的应用场景如用户注册完成之后的确认邮件发送,如果等邮件发送成功再给用户返回确认信息,这个时间间隔在用户体验上是难以接受的.

Rails3中的性能分析方法

- - Taobao QA Team
(转帖请注明出处: http://qa.taobao.com/?p=15025). 性能分析是Web应用开发中非常重要的一个环节,相比访问缓慢的站点,访问快速的站点拥有更好的用户体验,帮助用户节省更多时间,带来更多的用户访问. 作为当前十分流行的Web框架, rubyonrails当然也提供很多方式进行性能分析.

locomotive - 用Rails3开发的开源CMS软件

- yuaz - ITeye资讯频道
用Rails做的CMS - locomotive ,功能超级棒. 支持多域名,可以对页面内部的不同区块直接编辑,所思即所得. 用的技术都很潮,Rails最新的版本3.0.7,存储用了MongoDB,内置多语言支持. 还是开源的:http://www.locomotivecms.com (要翻wall) ,国外已有软件公司用它做二次开发来卖CMS软件了.

Java:解析sql语句的一个开源项目

- - 脚本爱好者
有时候一些数据不支持sql语句,那么我们为了使其应用更加方便,sql语句可以在接口中包装一下,自己写parser太复杂,工作量不小,这里有一个开源的项目可以帮助我们做这个事情. With this example class you can easily get the list of tables in a select statement (including subqueries and joins and, as soon as the union code will be ready, unions).

Service Mesh 最火项目: Istio 架构解析

- - IT瘾-tuicool
Istio 是一个开源的服务网格,可为分布式微服务架构提供所需的基础运行和管理要素. 随着各组织越来越多地采用云平台,开发者必须使用微服务设计架构以实现可移植性,而运维人员必须管理包含混合云部署和多云部署的大型分布式应用. Istio 采用一种一致的方式来保护、连接和监控微服务,降低了管理微服务部署的复杂性.

解析:徐小平投资的七个失败的项目,深入分析原因!

- - TECH2IPO创见
真格基金创始人、著名天使投资人徐小平在《创业家》杂志主办的“创业家沙龙”做主题分享,从他多年的投资经历中,给创业者分享了七个最后失败的创业公司案例,针针见血. 在当下的中国,创业确实是时代最强音. 我每一个项目投的时候,都会想“又是一个Facebook”,结果却往往变成“又是非死不可”. 这是永远在绝望中再去寻找希望的过程,也是我做投资五六年惨痛的教训.

reCAPTCHA项目

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 要说reCAPTCHA,就要先说一说CAPTCHA,全称是Completely Automated Public Turing test to tell Computers and Humans Apart,即全自动区分计算机和人类的图灵测试,也就是通常说的“验证码”,目的就是要把计算机和人区分开来.

项目集成项目管理之项目范围管理

- - CSDN博客系统运维推荐文章
7.1项目范围和项目范围管理.    项目范围:为完成具有规定特征和功能的产品、服务或结果,而必须完成的项目工作. 7.1.2项目范围管理的作用.    确定在项目内包括什么工作和不包括什么工作;由此界定的项目范围在项目的全生命周期内可能因某种原因而变化,项目范围管理也对这种变化进行管理. 7.1.3项目范围管理的主要过程.

项目的秘密——Programmers(29)

- allentranks - 西乔的九卦
载于《程序员》杂志2011年第9期. 从这一期起,开始在杂志上登出整P的大幅漫画,需要看大图的同学们,讯猛点击下图. 这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主. 如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件.

绝望的项目——Programmers(21)

- leo - 西乔的九卦
载于《程序员》杂志2011年第1期. 这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主. 如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件.