Sidekiq + SidekiqUniqueJobs で前回の試作コードの sync_cache! を非同期にまとめて実行するようにしてみよう

みなさんこんにちは菊池です。

さいきんめっきり寒くなりましたね。遠方に紅葉を見にいこうとしていた 前回の記事 から早くも1ヶ月半ぐらい経ちまして、会社の窓から見える新宿中央公園もすっかり紅葉しています。ちなみに前回の記事を公開した翌日の週末は、青森の八甲田山に登って来ました!この話はどこかで別途。

写真
写真は11/28弊社会議室から撮影しました。左下の森が秋の小雨の新宿中央公園です

今回は前回の記事「Rails4 の counter_cache のカウントを redis-objects でカウントしてみた時の試作コード」を改良して、redis-object に保存しているカウンター値をあまりデーターベースに負荷をかけずに保存するようにしてみたので紹介します。

まずは、前回のコードを軽く整理すると
  • redis-object のカウンター値は、ガンガン更新してもらって OK なリアルタイムな値
  • データーベース上のカウンター値は、定期的に redis-object のカウンター値を反映させたスナップショット的な扱い 。主にレポート作成などでの利用を想定
となっています。 

この redis-object のカウンター値をデータベースに反映させる方法について考えてみました。

Rails なんで whenever で更新をかけようかと思ったんだけど、これだと更新されたカウンター値を把握するのに手間がかかりそうです。なにも考えないでカウンター値を全部更新っていう実装をすると、更新されていない redis-object の値までデータベースに更新することになり無駄が多そう。

ここでは、更新されたカウンター値だけデータベースに更新をかけるようにしたい。で、カウンター値が更新される度にデータベースへ反映させると負荷が心配なんで、更新があったカウンター値だけ一定期間毎に更新かけたい。

ということで、いろいろ検討した結果良さそうなのが、タイトルにもある Sidekiq と SidekiqUniqueJobs の組み合わせです。
Sidekiq は Rails で非同期にバックグラウンドでジョブを実行する仕組みです。同じ用途で Resque を使っている方も多いのではないでしょうか。

Resque は各ワーカーがプロセスとして動作するのに対し、Sidekiq では各ワーカーがスレッドで動作します。Resque はワーカーを増やして行くと CPU やメモリーの消費量が目に見えて増えていき、いつのまにか OOM Killer に○されてた!なんて実運用では経験したのですが、Sidekiq はスレッドベースなんで結構軽いっす。その代わり、ワーカーの実装時はスレッドセーフに気をつける!などありますが、僕的には軽く動くのが好感度高いです。

SidekiqUniqueJobs は Sidekiq に投入された複数の同じジョブを一つにまとめてしまうライブラリです。これを使うと30分の間に投入された複数の同じジョブは1回だけ実行する、といったことが出来ます。

ということで、

更新があったカウンター値だけ一定期間毎にデーターベースに更新をかけたい

ということが目論み通り実装出来そうな予感。

記事が長くなってしまったので、実際のコードは次回の記事で紹介したいと思います。それではみなさんごきげんよう!良い週末を! 

Cheers!
菊池