Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails Async Process with Sidekiq

wtnabe
August 29, 2015

Rails Async Process with Sidekiq

『Railsで非同期処理 - Sidekiqを使うための準備と使ってみて気づいたこと』 via Kanazawa.rb meetup #36

wtnabe

August 29, 2015
Tweet

More Decks by wtnabe

Other Decks in Programming

Transcript

  1. Railsで⾮同期処理
    Sidekiqを使うための準備と
    使ってみて気づいたこと
    @wtnabe
    Kanazawa.rb meetup 36
    2015-08-29 (Sat) at IT-Plaza MUSASHI

    View Slide

  2. お品書き
    ⾮同期処理とは
    Sidekiq
    ⾮同期Worker作成時の注意
    課題はテスト

    View Slide

  3. ⾮同期処理とは

    View Slide

  4. Railsで⾮同期処理とは
    HTTP requestと同期しないもの
    ジョブの実⾏指定と実際の実⾏時間が同
    期しないもの
    伝統的なバッチジョブは違う?
    クライアントサイドの⾮同期処理とは意味が違う

    View Slide

  5. 例えば
    POST時の処理を後回しに
    メールの送信
    画像のサムネイル⽣成
    response time短縮向け
    ⼤量の作業をスケジュール実⾏

    View Slide

  6. ⾮同期⽤のGem
    Rails 4.2+ ActiveJob ( adaptor )
    Rails 4.1- (various methods)
    DelayedJob
    BackgrounDrb
    Rescue
    Sidekiq

    View Slide

  7. Sidekiq

    View Slide

  8. Sidekiqの特徴
    http://sidekiq.org/
    Queue ⽤のストレージは Redis
    Celluloid を使ったスレッドモデル
    Sinatra 製の Dashboard 付き
    Sidekiq Pro アリ

    View Slide

  9. 今回選んだ理由
    もともとよく名前を⽬にしていた
    redis 環境の⽤意が楽になっていた
    Sidekiq Pro があるってことはビジネスを
    起こせるレベルのツールと看做せる
    Dashboard がレポートとしても使えそう

    View Slide

  10. セットアップ
    bundle install
    Procfile
    initializers/sidekiq.rb
    config/sidekiq.yml
    config/routes.rb ( if you wish Dashboard )

    View Slide

  11. Redisのインストールは省略

    View Slide

  12. bundle install
    in Gemfile
    gem 'sidekiq'

    View Slide

  13. Foremanの話はこちら
    前回 meetup #35 で紹介済み
    Lightweight PHP development environment with Foreman and built-in
    server // Speaker Deck

    View Slide

  14. Procfile
    Sidekiq⽤に別なRailsを⽴ち上げるイメージ
    web: bundle exec rails s
    redis: redis-server
    worker: mkdir -p tmp/pids && \
    bundle exec sidekiq \
    -C config/sidekiq.yml
    Unicornと同じように全部bundle execで済んじゃう

    View Slide

  15. Herokuでは初期化に注意
    RailsのバージョンによってDATABASE接
    続の設定反映の挙動が違う
    Herokuは環境変数設定を推奨している
    が、特にその辺りが違う
    see Advanced Options · mperham/sidekiq Wiki

    View Slide

  16. Concurrencyに注意
    RailsのDB connection poolはdefault 5
    Sidekiqのconcurrencyはdefault 25
    溢れるに決まってる><

    View Slide

  17. sidekiq.ymlの例
    :concurrency: 3
    :staging:
    :concurrency: 9
    :production:
    :concurrency: 9
    development は SQLite, production と staging で web と worker 2つの
    サーバから max 20 conn までの DB サーバに繋ぐ想定

    View Slide

  18. Dashboard
    in Gemfile
    gem 'sinatra'
    in routes.rb
    require 'sidekiq/web'
    mount Sidekiq::Web => '/sidekiq'
    もちろんアクセス制限は忘れないで>< 

    View Slide

  19. Sidekiq Dashboard Demo

    View Slide

  20. Workerの作り⽅

    View Slide

  21. in Gemfile
    gem 'sidekiq'

    View Slide

  22. in application.rb
    app/workers ディレクトリを
    作る
    autoload 対象に
    eager_load 対象に
    eager_load については ggl `rails thread'

    View Slide

  23. in foo_worker.rb
    class FooWorker
    include Sidekiq::Worker
    def perform(*args)
    end
    end

    View Slide

  24. How to use
    FooWorker.perform_async(arg1, ...)
    FooWorker.perform_in(time, arg1, ...)
    etc

    View Slide

  25. worker⽤のRails上で
    perform()が呼ばれる
    request を受けた Rails とは別な⼈であることに注意
    perform_in() を使うと遅延時間が指定できる

    View Slide

  26. Worker作成時の注意点

    View Slide

  27. 基本⽤語
    ここでは以下のように⾔葉を⽤いる
    Worker
    実際に⾮同期の動作を担当するclass
    ジョブ
    Workerが実⾏する⼀つ⼀つの処理

    View Slide

  28. 注意点
    perform() にはプリミティブを与える
    できるだけ細かくジョブを分ける
    ※ Rubyにはプリミティブなんて存在しないけど

    View Slide

  29. serializeしたオブジェクト
    じゃダメなの?

    View Slide

  30. オブジェクト渡し
    簡単だしDBに負担掛けない
    Queueの容量膨らむ
    安定してdeserializeできるとは限らない
    処理の記録の意味が分からない

    View Slide

  31. 処理の記録重要
    ⾮同期処理はいつ終わるか分からない
    「ポチッとやって結果を⽬視」みたいな
    やり⽅は通⽤しない

    View Slide

  32. Sidekiqの記録
    Workerの名前と引数がそのまま残る
    readableな名前と引数を使う

    View Slide

  33. class BulkThumbnailGeneratorWorker
    include Sidekiq::Worker
    def perform(k, id, attr, size)
    r = Object.const_get(k).find(id)
    ...
    end
    end
    例えば⼀括サムネイル⽣成

    View Slide

  34. こうすると
    どのModelの
    どのIDの
    どのカラムの画像を
    どのサイズにするのか
    これらが記録に残る。readableで丸分かり。

    View Slide

  35. しかも
    ⼩分けにできる

    View Slide

  36. ジョブの⼩分け重要
    × 1万回のeachのある1つのジョブ
    ○ 1万のジョブ
    ※ ⼩分けなら記録も明確で途中からretryできる

    View Slide

  37. ジョブの分け⽅
    ⼤量の作業が必要な場合
    peform の中で each しない
    each の中で perform_in を呼ぶ
    処理に掛かる時間を予測して遅延時間
    を指定しておく
    もちろん必要な遅延時間はあらかじめ予測して検証する

    View Slide

  38. 課題はテスト

    View Slide

  39. 今のところ⾃動テストなし
    そんなに変更しない
    いつも⾛らせる必要はない

    View Slide

  40. ⼤きな課題は
    peform の呼び⽅呼ばれ⽅のコードというよりは
    遅延時間やジョブの衝突などの⽅で、こ
    れは⾮常にテストしにくい

    View Slide

  41. (機会があれば)
    頑張ります><

    View Slide