ジョブキューシステムFireworqのアーキテクチャ設計と運用時のベストプラクティス
by
INA Lintaro
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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 おわり