ジョブキューシステムFireworqのアーキテクチャ設計と運用時のベストプラクティス
by
INA Lintaro
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
ジョブキューシステム Fireworqのアーキテクチャ設計と 運用時のベストプラクティス INA Lintaro id:tarao @oarat 2023-03-19 YAPC::Kyoto 2023
Slide 2
Slide 2 text
自己紹介 2 id:tarao @oarat @tarao エンジニア (バックエンド)・エンジニアリングマネージャ ● 2013~ はてなに新卒入社 ● 2015~ はてなブックマークのシステム刷新 (テックリード) ● 2021~ エンジニアリングマネージャ 今回に関連する話 ● 10年でどう変わった? はてなブックマークでのPerlの 使い方 YAPC::Nagoya::Tiny 2019, 名古屋市中村区, November 2019 (ゲストスピーカー)
Slide 3
Slide 3 text
3 Fireworq is 何?
Slide 4
Slide 4 text
Fireworq is 何? ● ジョブキュー (メッセージキュー) ● Go製 ● ストレージはMySQL ● at-least-once 4
Slide 5
Slide 5 text
Fireworq is 何? ● HTTPでジョブを投げる ● 指定ワーカーにPOSTしてくれる ● 投入元 = ワーカー なら つまり非同期処理 5
Slide 6
Slide 6 text
Fireworq is 何? ● HTTPでジョブを投げる ● 指定ワーカーにPOSTしてくれる ● 投入元 ≠ ワーカー なら つまりメッセージング 6
Slide 7
Slide 7 text
7 以前の ジョブキュー ソリューション
Slide 8
Slide 8 text
TheSchwartz + WorkerManager 困りどころ ● Perlでしか使えない ● 重いジョブによるリソース占有 ● ワーカー並列数を増やすと詰まる ● ワーカーをメンテしづらい ○ エントリーポイントが特殊 ○ 環境セットアップが特殊 8
Slide 9
Slide 9 text
TheSchwartz + WorkerManager 困りどころ ● Perlでしか使えない ● 重いジョブによるリソース占有 ● ワーカー並列数を増やすと詰まる ● ワーカーをメンテしづらい ○ エントリーポイントが特殊 ○ 環境セットアップが特殊 9
Slide 10
Slide 10 text
TheSchwartz + WorkerManager ● 複数のワーカーが一斉にジョブを掴む ● ワーカーを増やしていくと詰まる 10
Slide 11
Slide 11 text
11 Fireworqの設計
Slide 12
Slide 12 text
設計思想 12 Portability 言語非依存 (インタフェースはHTTP) Reliability RDBMS (MySQL)で永続化 Availability プライマリ/バックアップのノード構成 Scalability 単一ディスパッチャ+多数のワーカー Flexibility 複数のキューを動的に設定可能 APIや管理Webコンソールで操作可能
Slide 13
Slide 13 text
アーキテクチャ ● 単一ディスパッチャでポーリング 13
Slide 14
Slide 14 text
しくみ - MySQLエンジン ● 1テーブル = 1キュー ● INSERTとUPDATEを 競合させない ● TheSchwartzや MogileFSもだいたい同じ 14 id next_try status 6 12:05 claimed 5 11:05 claimed 4 10:32 claimed 3 10:27 claimed 2 09:41 grabbed 1 09:07 grabbed 現在時刻 新規ジョブ INSERT位置 次に掴む UPDATE claimed ↓ grabbed
Slide 15
Slide 15 text
しくみ - ノード昇格 ● プライマリ ○ GET_LOCK成功 ● バックアップ ○ GET_LOCK待ち ○ INSERTは可 ○ プライマリが落ちると 直ちに昇格 15
Slide 16
Slide 16 text
16 TheSchwartzからの移行
Slide 17
Slide 17 text
元のワーカーの想定 package My::Worker use parent qw(TheSchwartz::Worker); sub work { my ($class, $job) = @_; ... $job->completed; } 17
Slide 18
Slide 18 text
TheSchwartz::Fireworq ワーカーをweb app化: app.psgiに以下を追加 enable ‘TheSchwartz::Fireworq’, path => ‘/work’; 18
Slide 19
Slide 19 text
TheSchwartz::Fireworq ジョブの投入側: クライアントが変わるだけ my $client = TheSchwartz::Fireworq->new( server => 'http://localhost:8080', # Fireworq worker => 'http://localhost:5000/work', # ワーカー ); $client->insert('My::Worker', { @_ }); 19
Slide 20
Slide 20 text
20 Fireworqの 運用プラクティス
Slide 21
Slide 21 text
複数キューの使い分け ● 時間のかかるジョブはキューを別にする ● ジョブカテゴリは細かく分けておく ○ カテゴリごとに配送先キューを設定するため 21
Slide 22
Slide 22 text
スロットリング ● 前提: ジョブは羃等にしておく ● TheSchwartzではuniqkeyで可能だった ○ 本当の意味のスロットリングではない ● 自前でやる必要がある ○ キーごとに最終実行予定時刻を記録すれば可能 ○ 投入ジョブの実行予定より後の予定があればスキップ ○ なければrun_afterでインターバルを空けて投入 22
Slide 23
Slide 23 text
失敗時の再送 ● 自動で再送される ○ 指定したmax_retriesの回数以内の場合 ○ ジョブを掴んでいる途中でFireworqが落ちた場合 ● それでも失敗したもの(permanent failure) ○ GET /queue//failedで一覧が取れる ○ POST /job/で必要に応じて再投入する 23
Slide 24
Slide 24 text
Mackerelで監視 ● mackerel-plugin-fireworq ○ キューやノードの状態のメトリックを取る ● mackerel-check-fireworq ○ ジョブの失敗(permanent failure)をアラート 24
Slide 25
Slide 25 text
25 まとめ
Slide 26
Slide 26 text
まとめ ● Fireworqはジョブキュー ○ 言語非依存でスケールする ○ ワーカーもweb appのためわかりやすい ● TheSchwartzからの移行は簡単 ● 本番運用に必要なものは揃っている ● コントリビュータ・メンテナ募集中 26
Slide 27
Slide 27 text
27 質問?
Slide 28
Slide 28 text
28 FAQ
Slide 29
Slide 29 text
Q. HTTP以外はサポートしないの? A. ● gRPCとか? HTTP/2? ○ サポートしてもよいかも ○ コントリビュータ歓迎 ● 必要なほどパフォーマンスがシビアな状況? ○ 今のところ聞いたことがない ○ 試してみてHTTPでは無理だったらおしえてください 29
Slide 30
Slide 30 text
Q. MySQL以外のストレージではダメ? A. ● 内部コード的には変えられる ○ インタフェースさえ満たせばなんでもよい設計 ● 当初はRedisエンジンも実装予定だった ○ 単にめんどうでやってないだけ ○ コントリビュータ歓迎 30
Slide 31
Slide 31 text
31 おわり