読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

resqueで非同期分散処理を試す

resqueは非同期処理の仕組みを提供するライブラリです。

  • Webアプリで、画像変換とかメールの一括送信のような重たい処理を行うときに使ったりします。
    • Railsに組み込んで使うこともできる模様。
  • 複数ノードでの分散処理にも対応。
  • 管理コンソールがついているので、処理ノード(worker)の状態や、積まれた処理の数を簡単に確認できるもポイント。

サンプルのタスクを作って、複数ノードで分散処理するところまで試してみました。

構成

docker上に構築します。用意したコンテナは以下。

  • redis
    • resqueではバックエンドにredisを使います。
  • resque-manager
    • resqueの管理コンソール(webアプリ)を動かすコンテナ
  • resque-console
    • resqueで行わせる処理(job)を置くコンテナです。
    • resqueへの処理の登録もこのコンテナから行います。
  • resque-worker x2
    • 非同期処理を実行するコンテナです。2つ用意します。

図にするとこんな感じ。


  • すべてのコンテナからredisにアクセスできるようにします。
  • resque-consoleにjobを置き、さらにData Volume Containerにして、resque-workerからもjobを参照できるようにします。
    • jobは、タスクの登録時および実行時の両方で必要です。
    • workerの実行時に必要なRakefileも、resque-consoleに置いて共有します。

1. redis コンテナを作る

まず、redisコンテナを作ります。

$ mkdir -p ~/work/redis
$ vi ~/work/redis/Dockerfile

Dockerfileの中身は以下。

FROM centos:centos7

RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum -y install redis; yum clean all

EXPOSE 6379
CMD ["redis-server"]
  • centos7をベースに使います。
  • redisをインストールして、起動します。

Dockerfileを保存したら、Dockere Imageをビルドして実行。

$ sudo docker build --rm -t='redis' redis
$ sudo docker run -d --name=redis redis
  • -d オプションを指定して、バックエンドで実行します。
  • redisへのアクセスはコンテナ内からのみできればOKなので、ホスト側のポートとのマッピングはしていません。

2. resque-manager コンテナを作る

次にresque-manager コンテナを作ります。

$ mkdir -p ~/work/resque-manager
$ vi ~/work/resque-manager/Dockerfile

Dockerfileは以下。

FROM centos:centos7

RUN yum -y update; yum clean all
RUN yum -y install ruby; yum clean all
RUN gem install resque

EXPOSE 3000

CMD resque-web -p 3000 -r redis -F
  • rubyとresqueのgemをインストールします。
  • コンテナ起動時にresqueの管理コンソールを起動するように指定します。
    • 「-p 3000」で使用するポートを3000に変更。
    • 「-r redis」でredisノードを指定します。
      • コンテナ起動時に、「--link redis:redis」を指定することで、resque-managerコンテナの /etc/hosts にredisコンテナのアドレスが追加され接続できるようになる仕組み。(詳しくはこちら)なお、上記の例ではportは省略しています。
    • 「-F」でフォアグラウンドで実行するようにします。

ビルドして実行。

$ sudo docker build --rm -t='resque-manager' resque-manager
$ sudo docker run -d -p 3000:3000 --link redis:redis --name=resque-manager resque-manager
  • 「-p 3000:3000」で、ホストのポート3000へのアクセスをゲストのポート3000にマッピングするようにしています。

起動したら、ブラウザから http://127.0.0.1:3000 にアクセス。resqueの管理コンソールが表示されるはず。


3. resque-console コンテナを作る

管理コンソールの起動が確認できたら、resque-console コンテナを作ります。

$ mkdir -p ~/work/resque-console
$ vi ~/work/resque-console/Dockerfile

Dockerfile:

FROM centos:centos7

RUN yum -y update; yum clean all
RUN yum -y install ruby; yum clean all
RUN gem install resque

VOLUME ["/resque-data"]

CMD ["/bin/bash"]
  • jobの登録時に必要になので、rubyとresqueをインストールします。
  • 「VOLUME ["/resque-data"]」で data volume を追加。
    • ここにjobの定義ファイルやwoker起動用Rakefileを置いて、他のコンテナと共有します。

ビルドして実行。

$ sudo docker build --rm -t='resque-console' resque-console
$ sudo docker run -ti --link redis:redis --name=resque-console resque-console


起動後のコンソールから、jobファイルを作成します。

# cd /resque-data 
# vi job.rb

job.rb:

class Job 
  @queue = :default

  def self.perform(time)
    puts "start #{time}"
    sleep time
    puts "end #{time}"
  end
end
  • 非同期で行う処理の定義です。
  • perform メソッドが処理の本体になります。
  • @queue でキューの名前を指定します。

jobが用意できたので、resqueに登録してみます。

add_jobs.rb:

require 'resque'
require_relative 'job'

Resque.redis="redis" # 接続先とするredisを指定

10.times {|n|
  Resque.enqueue( Job, n )
}

実行すると、jobが登録されます。

# ruby add_jobs.rb

workerはまだないので、実行はされません。

4. workerの起動時に使用するRakefileを作る

resque-workerコンテナをつくる前にworker起動用のRakefileを用意しておきます。

  • workerはRake Taskの形で提供されているので、Rakefileを作る必要があります。
    • といっても、job.rbとresque/tasksをrequireするだけですけど。
    • あと、接続先とするredisもこの中で指定します。
  • Rakefileはresque-consoleコンテナの /resque-data に置き、resque-worker x2 と共有します。
    • アクセスできるようにするための設定は後述。

Rakefile:

require_relative 'job'
require 'resque/tasks'

Resque.redis="redis"

5. resque-worker コンテナを作る

最後にworkerコンテナを作ります。

$ mkdir -p ~/work/resque-worker
$ vi ~/work/resque-worker/Dockerfile

Dockerfile:

FROM centos:centos7

RUN yum -y update; yum clean all
RUN yum -y install ruby; yum clean all
RUN yum -y install rake; yum clean all
RUN gem install resque

CMD TERM_CHILD=2 QUEUE=default rake -f /resque-data/Rakefile resque:work
  • ruby,resque と rake も必要なので追加でインストールします。
  • CMDで、起動時にresqueのworkerを起動します。

ビルドして実行。別の名前で2つ実行します。

$ sudo docker build --rm -t='resque-worker' resque-worker
$ sudo docker run -d --link redis:redis --volumes-from resque-console --name="resque-worker1" resque-worker
$ sudo docker run -d --link redis:redis --volumes-from resque-console --name="resque-worker2" resque-worker
  • 「--volumes-from resque-console」でresque-consoleに追加した「/resque-data」にアクセスできるようにしています。

管理コンソールをリロードすると、workerが2つ起動しているはず。

jobの実行も始まります。