在高并发的场景下,使用异步队列可以解决慢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
# 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任务的方法。