RabbitMQ +运动鞋:一个工人还是100个?

时间:2018-10-31 12:51:46

标签: ruby-on-rails ruby rabbitmq amqp sneakers

比方说,我需要对100个用户进行复杂的计算。我当前的配置如下:

制作人

class Producer
  class << self
    def publish(target, options = {})
      connection = Bunny.new(some_params).start
      channel    = connection.create_channel
      exchange   = channel.fanout("#{target}_exchange", durable: true)

      exchange.publish(options.to_json)
    end
  end
end

MassComplexCalculations工作器

module UsersWorkers
  class MassComplexCalculations
    include Sneakers::Worker

    from_queue "#{ENV['RAILS_ENV']}.users.mass_complex_calculations_queue",
               exchange: "#{ENV['RAILS_ENV']}.users.mass_complex_calculations_exchange"

    def work(options)
      parsed_options = JSON.parse(options)

      ActiveRecord::Base.connection_pool.with_connection do
        User.where(id: parsed_options['ids']).each do |user|
          ::Services::Users::ComplexCalculations.call(user)
        end
      end
      ack!
    end
  end
end

运行工作者

Producer.publish("#{ENV['RAILS_ENV']}.users.mass_complex_calculations", ids: User.limit(100).ids)

我不太了解AMQP如何分配资源来执行任务以及如何提供帮助。是对的,最好在单独的工作程序中运行每个计算?例如:

已更改MassComplexCalculations工作者

module UsersWorkers
  class MassComplexCalculations
    include Sneakers::Worker

    from_queue "#{ENV['RAILS_ENV']}.users.mass_complex_calculations_queue",
               exchange: "#{ENV['RAILS_ENV']}.users.mass_complex_calculations_exchange"

    def work(options)
      parsed_options = JSON.parse(options)

      ActiveRecord::Base.connection_pool.with_connection do
        parsed_options['ids'].each do |id|
          Producer.publish("#{ENV['RAILS_ENV']}.users.personal_complex_calculations", id: id)
        end
      end
      ack!
    end
  end
end

新的PersonalComplexCalculations工作器

module UsersWorkers
  class PersonalComplexCalculations
    include Sneakers::Worker

    from_queue "#{ENV['RAILS_ENV']}.users.personal_complex_calculations_queue",
               exchange: "#{ENV['RAILS_ENV']}.users.personal_complex_calculations_exchange"

    def work(options)
      parsed_options = JSON.parse(options)
      user           = User.find(parsed_options['id'])

      ActiveRecord::Base.connection_pool.with_connection do
        ::Services::Users::ComplexCalculations.call(user)
      end
      ack!
    end
  end
end

据我了解,可能有两个选择:

  1. 第一个实现的运行速度可能会变慢,因为它将按顺序为每个用户调用该服务,而在第二个选择中,我们将有100个同时工作的工作人员并行执行其工作
  2. 没有区别

那么哪种方法更好?也许甚至其中之一是完全错误的?

谢谢。

1 个答案:

答案 0 :(得分:0)

您的假设均不成立。您不能保证会有100个并行工作器,因为运动鞋的默认线程池大小不一定要覆盖:

https://github.com/jondot/sneakers/blob/master/lib/sneakers/worker.rb#L20

如果您没有为ActiveRecord连接池配置至少100个连接,则由于此处资源匮乏,您的代码也会阻塞并等待。

在一般情况下,大多数情况下并行执行此类任务可能在大多数情况下会更快[em] -但这不能保证。