2時間の処理が10分に。JOBはどう作ればよいか見直してみた。

JOBはどう作ればよいか見直してみた。

ネット上にはいろんな情報があります。
その情報を見ていたら段々とよくわからなくなってきたのが『JOB』です。

大体書いてあるのは次のような時は「JOBを使ってQUEUE発行しようね」となってます。

  1. 重い処理の時
  2. 遅延処理などを組み込むとき
  3. スケジュールで実行させるとき

しかし最近『JOB』について段々と理解から遠のいている気がしています。

そこで、何が問題と考えていて、JOBをどう捉えたらいいか思考回路を再構築したいと思います。
※あくまでもLaravelにおけるJOBという解釈でお願いいたします。

作成したシステムで発生している問題

ネットショップ用のツールなので、情報を探る機能がテンコ盛りです。

  1. 自社のジャンルランキングを取得する機能
  2. 他社の価格を調べる機能
  3. モール側のジャンルコードやタグコードの変化を探す機能
  4. 自社店舗に商品が出品されているか探す機能
  5. 楽天やAmazonのサジェストワードを探す機能 etc.

こういった処理は情報取得頻度のコントロールを含め2~3時間かかる事はザラにあります。

だってねぇ、データの量が多いですもん。

今までの私だったら何の疑問も持たず【重い処理の時】だからと処理したい塊をJOBに投げてました。

例えば【自社のジャンルランキングを取得する機能】の時『ランキングを調べて自社商品があったらDBに登録してね』という塊ごとJOBに渡していました。

ここで発生した事例が次の内容です。

  1. 同じレコードが3回記載される事がある。
  2. TimeOutエラーが発生すると色々なJOBが軒並み動かなくなる。
  3. 重い処理を実行するものと記載しながら何故かタイムアウト90秒とかの例が多い。

当座のしのぎとして、JOBをリセットするボタンを用意して、JOBが動かなくなったらこいつを押してCommand実行してやるという運用をしてましたが、テスト運用から実際の運用に移行してくるとこのリセットボタンを押す頻度が超気になってきます。

そもそもJOBの捉え方が違うんじゃね?

そう思ったのはこんな事案がきっかけです。

 なぜリトライが用意されているのか

まぁ様々な要因でQueueが止まる事があるから事前にリトライ回数を定義しておきましょうと言う事なのでしょう。

Normal状態ではリトライ回数は3です。

Dockerではマルチタスクで動くApacheよりもNginxの人気が高いのはなぜか

処理速度が速いからとの事です。

但し、私のような3時間かかる処理とかをガツンとJOBに入れ込んでる奴がNginxでやったらどうなる事か…。
その為DockerもApacheでの構築で組んでいたのですが今回の疑問で「ひょっとして、そもそもの考え方が違うのでは?」と思ったわけです。

私のような時間のかかる処理を書いている人がゼロなんて事はないわけです。だってこういった処理を陰でやってくれるからシステムが重宝されるわけですから。

その方たちはどうやって処理してるの?
リトライによる重複を考えて、重複チェックを毎回仕掛けに入れる?
まさかねぇ、レコード数が増える度に付加掛かって「どうなっていくか」簡単に想像できますよね。

JOBとはどう考えていればいいの?

重い処理を非同期処理させ、JOB実行中でもブラウジングが快適に行える仕様。

これがJOBの役割である事は間違いありません。

問題は『JOBにどんな値を渡すか』です。

ひょっとして1処理毎の細かいJOBを発行した方が良い?

ただ、こうするとforeachでIDごとのJOBを発行するとかになるので、Queueの数が5000とか平気で越えてきます。
そもそもJOBを発行するためのプロセスで時間食わない?という疑問も出てきます。

JOBが細かくなれば、並列処理でなくても良いので計算処理の早いNginxの人気が高くなっていくのもわかります。
そして、3回のリトライも重複チェックの必要なく使える事になります。

JOBを再構築して運用実験してみる

さぁどうなるか。

これでJOBエラーの頻度が下がるならLaravel的には『細かいJOBを格納』の方が正解と言う事でしょう。
と言う事で、細かなJOBバージョンでランキング情報の取得を試みてみました。

Apacheすげー!と同時に遅延処理どうすんだ?の悩み

ランキングの取得は同期処理で行った場合、2時間コースの処理です。
発行したJOBの数は1742個。それぞれ最終ページを探りながらすべてのランキングをsearchして自店舗の商品を探すよう指示してます。

実行結果は下の通り。

  • 処理終了:約10分
  • JOBエラー数:9件

マジか。あんなに待った処理なのに…。

でもsearch結果が芳しくありません。
ランキングに入っている商品を拾ってこれていない。

なぜ?
それはアクセス制限に掛かり『APIから結果をもらえない』時があったからです。
そりゃね、10分で1700アクセス掛ければそうなるよね。処理時間の短さにはこういう『情報無いから即終了』というJOBが多かったからという理由もありそうです。

Apacheの並列処理の凄さを痛感しつつ、同時に「これってsleepしても同じだよな?」と気づきます。

だってねぇ、全JOBが同じ秒数休んだら結局同じことでしょうよ。

まとめ

作って運用してみると、意外と上手くいかない所って出てきます。

さぁどうしたものか。
トライ&エラーで最善の道を探すしかないのだろうけど、今回は処理速度の違いに脱帽でした。