Laravel Queueの運用管理

五十嵐正人氏:オープンロジの五十嵐です。よろしくお願いします。Vueだったりフロントの話が多いなか、サーバサイドの話をします。

「Laravel Queueの運用管理」といって、先月オープンロジでLaravelの勉強会させていただいた時も少し話したんですが、その続き的な内容の話をします。

まずは僕の紹介ということで、株式会社オープンロジという会社でCTOをやっています。基本的に0→1が好きで、前職でも別のスタートアップのCTOをやってたりしています。今は会社としては4、5年になって、0→1から1→10みたいなところになろうとしているフェーズの会社となります。

オープンロジはどういう会社かを簡単に紹介させてもらうと、誰でも簡単に使える物流アウトソーシングサービスです。

物流アウトソーシングサービスってなにかというと、主なお客様としてはECを営んでいる方なのですが、ECをやるとなると商品の在庫管理し受注があれば梱包し発送する必要があるのですが、そのような面倒な物流業務を代行するサービスになります。

従来は自分で倉庫会社さんを見つけ直接契約する必要あったのですが、それをオンライン上から誰でも簡単に登録できるようにし、我々がシステムを通して倉庫と荷主をマッチングします。最近はメルカリのように誰でも簡単に売れる時代になっています。、そのような方でもカジュアルに物流の委託ができるクラウドサービスを提供しているのが我々の企業になります。

技術スタックに関しては、どういうものも使っているかを簡単に紹介してもよかったんですが、そこらへんは去年のAdvent Calendarに書いてあるのでよかったら見てみてください。

基本的にはサーバサイドはLaravel で、フロントエンドはReactがメインです。新しいプロダクトではVueを使ったりしています。

ジョブの基本

本題に入りまして、まずはジョブの基本を話からさせていただきたいと思います。Laravelを使われている方はけっこういらっしゃると思いますが、我々はかなりジョブに振り切った使いかたをしています。

キーワードとして聞いたことがある方も多いかとは思うんですけど、「コマンドクエリの責務分離(CQRS)」というものがあります。このルールを取り入れることでいろいろ良いことがあります。

これも知ってる人からするとすごく当たり前の話かもしれませんが、Webのアプリケーションというのは、だいたい処理をするにあたってやることは、情報を読み取るか書き込むかのどちらかになります。

たとえば一番シンプルな構成でいうと、読み込むというのは、Webサーバ経由でDBに対してReadして、その結果をクライアントに返す。また、なにかしら書き込みがある場合は、POSTなどのメソッドをとおしてWebサーバ経由でDBに書き込んで、成功したら結果をクライアントに返します。この読み込みと書き込みを同じWebサーバ上でやらないようにしましょう、みたいなルールのことですね。

それを実現にするにはどうすればいいかというと、ジョブを活用しましょうということです。まずはCommandというかたちでWebサーバに投げます。Webサーバがやることは、それをQueueに対してEnqueueすることだけです。そしてmutableな処理をするJobサーバでそのQueueをDequeueしてWriteな処理を行います。

その結果をどうやってクライアントまで返すかというと、LaravelだとPusherやRedisなど、いろいろ選べる中で我々は今Pusherを使っているのですが、Pusher経由でクライアントに返すことで、ReadのサーバとWriteのサーバが別々でも、ちゃんと非同期にフィードバックを返すことができます。

こう書くとすごく難しそうに見えるかもしれませんが、Laravelは最初から、DDDやCQRSをよく意識した設計になっているので、すごく実装しやすいんです。

具体的なコードでいうと、例えば updateItemのようなController上のメソッドがあった場合、Eloquentでfindしてパラメータをセットしてsaveするような実装になってくるとは思いますが、CQRSだと単純にupdateItemというジョブを作って、ディスパッチしてあげるだけになります。

ジョブのステータス管理

このジョブ、updateItemという中身の実装のハンドラに関しては、Controller上で実装していたものと同じような実装が入っているだけなんですが、こういったかたちであらゆる更新処理をジョブを経由するような実装にする方針にしています。

そうすることで、そのジョブという存在がとても大事になってくるので、ジョブがどのように処理されているか、ちゃんと成功したのか失敗したのか結果を管理することで、一元的にシステムがどうなっているかという情報を見れるように工夫しています。

ここ最近出てきたライブラリでLaravel HorizonとLaravel Telescopeというのがありまして、これはうちではまだ使ってないんですが「どういうものなのかな?」と思ってちょっと調べてきたので、簡単にご紹介します。

これがLaravel Horizonで、これがLaravel Telescopeです。すごい似ているんですよね。

Laravel Telescopeは比較的最近できたので知らない方もいらっしゃると思いますが、それぞれどんなものかというか、実際使っている人っていらっしゃいますか?

(会場挙手)

Telescopeはたぶんまだ出たばかりなのであまり使われている方はいないのかもしれませんが、HorizonはRedis専用のキューのモニタリングツールです。

TelescopeというのはLaravel内の状態を把握するための開発用デバッグツールです。Laravel Debugbarというものもありますが、あれよりも、リクエストからクエリやジョブの状態、あとは通知のイベントの結果など、Laravelの中でいろいろなイベントが発生すると思うのですが、それらの状態なを一元的に見ることができるツールです。

ここを見ればわかりますが、Exceptionとかログとかクエリとか、モデル、イベントなどいろいろなパラメーターがあります。

Horizonは、そういった本番運用用のモニタリングツールであって、Telescopeは開発用のデベロッパーツールです。

どちらもキューのサポートがあるんですけれども、Horizonに関してはRedis Onlyです。Telescopeはすべて、Redisに限らず、DBキューだったりSQSキューだったり、あとはSyncのジョブに対してもすべてどういう状態なのかが見えるようになっています。

Horizonには、Failed Jobをリトライする機能があったり、実際投げたジョブがどんなステータスになっているかを見ることができるなど、それぞれ一長一短がありますが、そもそもコンセプトとしてデバッグ用とモニタリング用ということで違いがあることがわかったかと思います。

オープンロジでの活用法

オープンロジではジョブのステータスを別途記録していて、誰がいつどこでなにをやったかは、すべての更新処理をジョブに集約することでトラッキングできるようにしています。

これがLaravel Telescopeだと、同じようなものがあって、ユーザーがどのジョブをどういうパラメータで実行したのかが記録されています。これらの情報を記録する分DBには負荷がかかるのであくまでデバッグ用ではあるのですが、こういうところが欲しかった部分です。

クエリやジョブやメールがどんなクエリが発行されたのかまで見ることができるので、開発にあたって便利そうだなと思っています。

あとはFailed Jobの再実行もオペレーションにおいてはよくある話です。

これは我々独自で作ったんですが、任意のFailed Jobに対してリトライする画面を用意しています。

これに関してはLaravel Horizonでも同じような画面があるので、利用されている方もいらっしゃるとは思うんですけれども、我々はこのHorizonが出る前に運用していたので、こういうツールを使ったりして工夫していました。

Horizonのようなモニタリングツールが欲しいけど、同時にTelescopeみたいなちゃんとログってくれるようなのも欲しくて、どっちもどっちというか、どっちも少し足りない感じなのですが、どちらのニーズも満たすようなジョブの管理をするようなツールを求めているんですが、今は自分たちで実装したもので工夫しています。

まとめ

まとめです。

すべての更新処理をジョブで実行することによってスケーラブルにもなるし、関心事が分離されるし、それぞれ個別にReadとWriteを別々にスケーリングできるのは大きなメリットです。オープンロジでは初期からこの設計でしていますが、おかげでここまでの規模でうまくスケーラブルにスケールできています。

あとはジョブの実行記録を残すことで、実証可能な監査証跡を残すことができるし、トラブルシューティングがしやすいので非常におすすめです。

このTelescopeにもし興味あって使う方がいたときに気をつけてほしいのが、あくまでDevelopment環境での利用が前提になります。Telescopeを調べてたらこのサイトが出てきたんですよ。これってたぶんどこかの会社さんがプロダクションでもう運用しているサーバで、Telescopeが出ちゃっています(笑)。

(会場笑)

これはあとで気が向いたら報告します。しかも、Laravel Debugbarも出ちゃってて、かなりやばいです。それで「どんな会社なのかな?」って調べてみたら、これタイの会社なんですよね。トラックの画像があるので我々と同じ物流系の会社さんのようなのでがんばってほしいんですが、このトップページでもLaravel Debugbarが出てしまうというけっこうやばい状態になっているので(笑)。

(会場笑)

開発ではすごく便利なツールなんですけれども、こういうポカをしないようにみなさん気をつけてください。はい、以上です。

(会場拍手)