在高并发的场景下,使用异步队列可以解决慢io阻塞的问题,当用户请求到达时,先把消息塞在队列中,然后快速返回, 后台任务再从队列中取出消息慢慢处理。 sidekiq 就是一个用ruby实现的,底层使用redis,的一个异步队列。
在rails工程中, 请参考 https://github.com/mperham/sidekiq/wiki/Getting-Started 很详细, 在这不过多讨论。
Goliath 是一个高效的ruby web框架,在 rest full的接口场景下,既能满足效率的要求(上千请求每秒),又开发简单, (建议使用1.0.4版本, 1.0.3版本有一个crash的bug,需要打补丁)。 在这我们来讨论 goliath 这种纯ruby的环境下 sidekiq的使用问题。
sidekiq的 examples 目录下有一个 por.rb 的文件, 这个就是纯ruby环境下 sidekiq的队列。
require 'sidekiq' Sidekiq.configure_client do |config| config.redis = { :namespace => 'x', :size => 1 } end Sidekiq.configure_server do |config| config.redis = { :namespace => 'x' } end class PlainOldRuby include Sidekiq::Worker def perform(how_hard="super hard", how_long=1) puts "Workin' #{how_hard}" end end
启动命令
# RACK_ENV=production bundle exec sidekiq -r ./por.rb -d -L log/sidekiq.log -c 10
-c 参数可以指定在一个进程中开启多少个并发, 在任务重的情况下可以考虑多开几个, (但要注意 并发数要小于 数据库连接池的连接数量,否则会导致数据库连接失败,应为并发多,db的连接数不够用)
在goliath代码中, 比如 webapi.rb 中
class Webapi < Goliath::API def response(env) path = env[Goliath::Request::REQUEST_PATH] case path when /^\/webapi\/weixin\// PlainOldRubyWorker.perform_async("test") # 收到用户的请求,然后异步调用,把消息 塞到 sidekiq的异步队列中 end [200,{},""] end end
以上代码是最常见的使用场景, 但有一个问题,随着por中 class 越来越多,sidekiq的并发数量上升, class 任务之间会产生干扰, 一旦某个任务存在性能问题,会导致并发资源都被占用,所以需要一种资源隔离的策略, 重要的任务单独创建一个sidekiq进程。
对上面的por.rb 文件做改造
class NotifyWorker include Sidekiq::Worker sidekiq_options queue: :notify_worker, retry: 3, backtrace: true # 这 指定队列的 名称, 重试次数 def perform( openid, msg , msgdata={}) ... logger.info "-->send to #{openid} , #{succ}" end end
启动命令 -q 参数,当前进程的工作队列,这样就与其他队列隔离开了。
# RACK_ENV=production bundle exec sidekiq -r ./por.rb -d -L log/sidekiq.log -c 4 -q notify_worker
注意 por.rb 修改后, sidekiq 进程 和 goliath进程都需要重启才能生效。
测试结果如下 :
启动2个 sidekiq 分别指定不同的队列参数 ;
RACK_ENV=production bundle exec sidekiq -r ./por.rb -d -L log/sidekiq.log -c 1 -q callback_worker
RACK_ENV=production bundle exec sidekiq -r ./por.rb -d -L log/sidekiq.log -c 2 -q notify_worker
root 23881 0.0 3.0 753132 62644 ? Sl 16:51 0:02 sidekiq 2.17.1 [0 of 1 busy]
root 23997 0.1 3.3 822924 67788 ? Sl 16:52 0:02 sidekiq 2.17.1 [0 of 2 busy]
监控 sidekiq的日志输出
在进程 23881 上处理 callback_worker 任务
2014-08-12T09:37:06Z 23881 TID-ovw9yoy70 EventCallbackWorker JID-ce334f112b6374b8fc47cde1 INFO: start
在进程 23997 上处理 notify队列相关的任务
2014-08-12T09:37:07Z 23997 TID-owpks93e0 NotifyWorker JID-b0239ffa243b559dfba1be18 INFO: start
以上,可以达到隔离sidekiq任务的方法。