Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: queueing bulk follow/unfollow and block/unblock #10544

Merged
merged 13 commits into from
Apr 12, 2023
Merged

feat: queueing bulk follow/unfollow and block/unblock #10544

merged 13 commits into from
Apr 12, 2023

Conversation

nmkj-io
Copy link
Contributor

@nmkj-io nmkj-io commented Apr 9, 2023

What

フォロー・フォロー解除とブロック・ブロック解除をジョブキューに切り出す。

Resolves #10527

Why

フォローインポートやアカウント引っ越しで大量のフォロー・フォロー解除が発生した際にサーバーが応答不能にならないようにするため。

Additional info (optional)

フォローインポートやアカウント引っ越しのような限定的な場面ではジョブの順序などは考慮しなくてよいと思われます。また、ブロックはフォローに優先されるためフォローインポートとブロックインポートを両方ジョブにしてもよいと判断しました。

以下はテスト用のAPIを作って試した結果です。(コミットには含めていません)

4000ローカルユーザー(Misskey)+2500リモートユーザー(Mastodon)でテストした結果:

テスト環境: 4コア8GB KVM Core i7-11700K(Postgres, Redis, Mastodon 4.1.2 を同じKVMマシン内で実行)

  1. ローカルユーザー3人がローカルユーザー4000人を同時インポート(12,000フォロージョブ) ✔️
  2. ローカルユーザー5人がリモートユーザー2500人を同時インポート (12,500フォロージョブ+deliverジョブ) ✔️
  3. 12,500のリモートフォローを一斉解除(12,500フォロー解除ジョブ) ✔️
  4. ローカルユーザー100人がローカルユーザー4000人を同時インポート(400,000フォロージョブ) ✔️
  5. ローカルユーザー500人がリモートユーザー2500人を同時インポート(1,250,000フォロージョブ+deliverジョブ) ✔️
  6. ローカルユーザー4000人がリモートユーザー2500人を同時インポート(10,000,000フォロージョブ) ❗
    • MisskeyのRedisがメモリ不足に陥りジョブが失敗するようになったがサーバーは応答不能にならず。
  7. ローカルユーザー4000人がローカルユーザー4000人を同時インポート(16,000,000フォロージョブ) ❗
    • 同上
  8. ローカルユーザー100人がローカルユーザー4000人をフォローした後同時ブロック(400,000ブロックジョブ) ✔️
    • その後同時に全ブロック解除(400,000ブロック解除ジョブ) ✔️

4以降のケースで全ジョブの完了に30分以上を要しました。いずれも応答不能にはなっていません。

Checklist

  • Read the contribution guide
  • Test working in a local environment
  • (If needed) Update CHANGELOG.md
  • (If possible) Add tests

@github-actions github-actions bot added the packages/backend Server side specific issue/PR label Apr 9, 2023
@codecov
Copy link

codecov bot commented Apr 9, 2023

Codecov Report

Merging #10544 (a1ee673) into develop (39cf80e) will decrease coverage by 1.23%.
The diff coverage is 30.75%.

@@             Coverage Diff             @@
##           develop   #10544      +/-   ##
===========================================
- Coverage    75.11%   73.89%   -1.23%     
===========================================
  Files          886      727     -159     
  Lines        87116    67562   -19554     
  Branches      5910     5594     -316     
===========================================
- Hits         65439    49925   -15514     
+ Misses       21677    17637    -4040     
Impacted Files Coverage Δ
...ages/backend/src/queue/DbQueueProcessorsService.ts 42.85% <0.00%> (-1.41%) ⬇️
...c/queue/processors/ImportMutingProcessorService.ts 23.30% <0.00%> (-0.47%) ⬇️
packages/backend/src/queue/types.ts 0.00% <0.00%> (ø)
...ackages/backend/src/queue/QueueProcessorService.ts 15.47% <3.84%> (-0.55%) ⬇️
...queue/processors/ImportBlockingProcessorService.ts 24.75% <10.52%> (+1.67%) ⬆️
...ueue/processors/ImportFollowingProcessorService.ts 24.75% <10.81%> (+0.99%) ⬆️
...end/src/server/api/endpoints/admin/suspend-user.ts 52.74% <22.22%> (-2.81%) ⬇️
packages/backend/src/core/QueueService.ts 32.47% <29.78%> (+0.60%) ⬆️
...c/queue/processors/RelationshipProcessorService.ts 39.70% <39.70%> (ø)
...eue/processors/DeleteDriveFilesProcessorService.ts 25.00% <50.00%> (ø)
... and 13 more

... and 169 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@nmkj-io nmkj-io marked this pull request as ready for review April 9, 2023 10:03
@github-actions github-actions bot requested review from rinsuki and tamaina April 9, 2023 10:03
@nmkj-io nmkj-io changed the title feat: queueing follow/unfollow feat: queueing follow/unfollow and block/unblock Apr 9, 2023
@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 9, 2023

Misskey ↔ Mastodon の通信は一旦外のVPSを経由させるようにしたので、deliver・inboxキューの遅延も含まれていると思われます。

@nmkj-io nmkj-io changed the title feat: queueing follow/unfollow and block/unblock feat: queueing bulk follow/unfollow and block/unblock Apr 9, 2023
@syuilo
Copy link
Member

syuilo commented Apr 10, 2023

良さそうです👍
13.11.2のリリースが終わり次第マージします

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

forで大量にQueueを追加しているけど、dbQueue.addBulkを使っていい感じにできないかしら

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

(できそうなのでできたらコードを変えて欲しい

@nmkj-io nmkj-io marked this pull request as draft April 11, 2023 10:08
@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

リファクタリングの余地はあるかと思いますが、フォローとブロックのインポートで addBulk を使うようにしました。

例えば ImportFollowingProcessorService.tsprocessDb でフォロージョブを一つだけ作成するようにしましたが、これは Bull の finished() が保証されていないがゆえ CSV の一行に対する findOneByresolveUser の結果を process が待たなくていいようにするためにこうしました。

追加の変更として、インポート時は followblocksilent=true を渡すことでフォローイベント大発生によるホームTL連続更新・通知キュー失敗を抑制するようにしました。

@nmkj-io nmkj-io marked this pull request as ready for review April 11, 2023 10:59
@github-actions github-actions bot requested a review from syuilo April 11, 2023 10:59
@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

実験では 4000 アカウントを一気にフォローインポートしましたが、実際は CSV ファイルのサイズ制限で引っかかるので silent=true でTLのAPI呼び出しを抑制するかの判断はおまかせします。(消せば元通りフォロージョブ完了の度にイベントが飛んでタイムラインのAPIが呼ばれます)

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

指示が間違ってた(relationshipQueue.addBulkを使うと言った方が適切だった

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

指示が間違ってた(relationshipQueue.addBulkを使うと言った方が適切だった

一応 relationshipQueue.addBulk を使うようにはなってます。ただし、

例えば ImportFollowingProcessorService.ts の processDb でフォロージョブを一つだけ作成するようにしましたが、これは Bull の finished() が保証されていないがゆえ CSV の一行に対する findOneBy や resolveUser の結果を process が待たなくていいようにするためにこうしました。

とあるように、ImportFollowingProcessorService.tsprocessfindOneByresolveUser を移して for で回すぐらいなら createFollowJobaddBulk に1ジョブしか渡さない代わりに resolveUser をジョブにしたという感じです。

どちらがよいでしょう?

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

ようは createImportFollowingToDbJob から addBulk にしてしまうか、 findOneByresolveUserprocess 内の for で回したあとで createFollowJobaddBulk を使わせるかの違いです。

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

  • UserをめちゃくちゃコピーしてRedisに持たせるとメモリがヤバそう(なのでRedisに渡すデータはstringにしたい)
  • 一行一行findOneByするのもSQLを大量発行することになるので良くない

ので、

一行一行findOneByするからキューにしてるんだわこれ

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

さっき10人ごとにって言ったけどあんまり良くないな
(idじゃなくてusernameLowerなのでArrayで受け取ったところで探すのに時間かかる)

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

userオブジェクトをBullに無限に突っ込む操作だけはやめた方が良さそう

(processDbごとにfindしてもキャッシュが効くだろうしなんとかなる

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

processDb には ThinUser 渡して、キャッシュが効くのを期待して中で findOne させるというのはどうでしょう?

createFollowJob も同様だとすると RelationshipProcessorService.ts の processFollow 内でも findOne するので二回呼びますが、キャッシュが効いて影響なしならいけるかと。

ただしSQL発行量は指数的に増えるんじゃないかと思います。

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

というかprocessDbでフォローインポートしたユーザーを読み出す必要はないはず

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

ImportFollowingProcessorServiceでインポート操作を行ったユーザーをfindOneByする意味自体が薄い

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

ImportFollowingProcessorServiceでインポート操作を行ったユーザーをfindOneByする意味自体が薄い

でしたら、 processDb はそのままインポートしたユーザーの ThinUser を createFollowJob に渡して、findOne は UserFollowingService の follow まで遅らせることができますね。

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

でしたら、 processDb はそのままインポートしたユーザーの ThinUser を createFollowJob に渡して、findOne は UserFollowingService の follow まで遅らせることができますね。

そう

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

意味が薄いとは言ったけど、processの最初でユーザーの存在確認をするのはまあいたずら防止程度の意味はありそうなのでそのままでいいかと

とにかくBullにUserを突っ込むのは極力やめる方針で

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

(というかidからfindOneする処理ぐらいは流石に回数を重ねても問題ない)

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

では RealtionshipProcessorService がジョブの最小単位なのでそこに ThinUser を渡して中で findOne するようにしますね。(processFollowでは不要なのでそのまま受け渡し)

@nmkj-io nmkj-io marked this pull request as draft April 11, 2023 13:54
@nmkj-io nmkj-io marked this pull request as ready for review April 11, 2023 14:36
@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

Bull に渡すユーザーを全てThinUserに置き換えました。RelationshipProcessorService で findOneByOrFail を呼ぶようにしました。
(不正・存在しないユーザーIDなら単純にジョブがfailになって除去される。)

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

すみません、suspend-userでfollowerとfolloweeが逆になってたので修正(83, 84行目)

@tamaina
Copy link
Contributor

tamaina commented Apr 11, 2023

silent=true でTLのAPI呼び出しを抑制する

これはめちゃくちゃいいアイデアだと思います

いくつかリファクタリングなどを追加したので、この状態でもう一度テストしていただけるとありがたいです

@nmkj-io
Copy link
Contributor Author

nmkj-io commented Apr 11, 2023

リファクタリングありがとうございます。100アカウントx4000フォローの400,000ジョブでテストしたところ、フォロー・ブロックインポート共に正常に動作しました。4000x4000の16,000,000ジョブはRAM 8GBではRedisがメモリ不足になりましたが、ThinUserに変える前よりは多くのジョブがさばけました。(メモリ不足になっても落ちずにそのまま止まったジョブから再開しました)

adminのsuspend-userとremove-all-followingのAPIについてもUnfollowのジョブが多くなる可能性があるのでsilent=trueにしておきました。

@tamaina
Copy link
Contributor

tamaina commented Apr 12, 2023

@syuilo We're ready for merge

@syuilo syuilo merged commit da83322 into misskey-dev:develop Apr 12, 2023
@syuilo
Copy link
Member

syuilo commented Apr 12, 2023

👍🏻👍🏻👍🏻

@nmkj-io nmkj-io mentioned this pull request Apr 12, 2023
11 tasks
@nmkj-io nmkj-io deleted the follow-queue branch April 12, 2023 01:42
@syuilo syuilo mentioned this pull request Apr 12, 2023
Ry0taK pushed a commit to MisskeyIO/misskey that referenced this pull request Apr 13, 2023
* Refactor sw (misskey-dev#10579)

* refactor(sw): remove dead code

* refactor(sw): remove dead code

* refactor(sw): remove dead code

* refactor(sw): remove dead code

* refactor(sw): remove dead code

* refactor(sw): remove dead code

* refactor(sw): 冗長な部分を変更

* refactor(sw): 使われていない煩雑な機能を削除

* refactor(sw): remove dead code

* refactor(sw): URL文字列の作成に`URL`を使うように

* refactor(sw): 型アサーションの削除とそれに伴い露呈したエラーへの対処

* refactor(sw): `append` -> `set` in `URLSearchParams`

* refactor(sw): `any`の削除とそれに伴い露呈したエラーへの対処

* refactor(sw): 型アサーションの削除とそれに伴い露呈したエラーへの対処

対処と言っても`throw`するだけ。いままでもこの状況ではエラーが投げられていたはずなので、この対処により新たな問題が起きることはないはず。

* refactor(sw): i18n loading

* refactor(sw): 型推論がうまくできる書き方に変更

`codes`が`(string | undefined)[]`から`string[]`になった

* refactor(sw): クエリ文字列の作成に`URLSearchParams`を使うように

* refactor(sw): `findClient`

* refactor(sw): `openClient`における`any`や`as`の書き換え

* refactor(sw): `openPost`における`any`の書き換え

* refactor(sw): `let` -> `const`

* refactor(sw): `any` -> `unknown`

* cleanup(sw): import

* cleanup(sw)

* cleanup(sw): `?.`

* cleanup(sw/.eslintrc.js)

* refactor(sw): `@typescript-eslint/explicit-function-return-type`

* refactor(sw): `@typescript-eslint/no-unused-vars`

* refactor(sw): どうしようもないところに`eslint-disable-next-line`を

* refactor(sw): `import/no-default-export`

* update operations.ts

* throw new Error

---------

Co-authored-by: tamaina <tamaina@hotmail.co.jp>

* Update CHANGELOG.md (misskey-dev#10591)

* feat: queueing bulk follow/unfollow and block/unblock (misskey-dev#10544)

* wrap follow/unfollow and block/unblock as job queue

* create import job to follow in each iteration

* make relationship jobs concurrent

* replace to job queue if called repeatedly

* use addBulk to import

* omit stream when importing

* fix job caller

* use ThinUser instead of User to reduce redis memory consumption

* createImportFollowingToDbJobの呼び出し方を変える, 型補強

* Force ThinUser

* オブジェクト操作のみのメソッド名はgenerate...Data

* Force ThinUser in generateRelationshipJobData

* silent bulk unfollow at admin api endpoint

---------

Co-authored-by: tamaina <tamaina@hotmail.co.jp>

* perf(backend): ノート作成時のアンテナ追加パフォーマンスを改善

* update CHANGELOG.md

* refactor: サウンド関連の設定をpizzaxに移行 (misskey-dev#8105)

* enhane: unison-reloadに指定したパスに移動できるように

* null

* null

* feat: ログインするアカウントのIDをクエリ文字列で指定する機能

* null

* await?

* rename

* rename

* Update read.ts

* merge

* get-note-summary

* fix

* swパッケージに

* add missing packages

* fix getNoteSummary

* add webpack-cli

* ✌️

* remove plugins

* sw-inject分離したがテストしてない

* fix notification.vue

* remove a blank line

* disconnect intersection observer

* disconnect2

* fix notification.vue

* remove a blank line

* disconnect intersection observer

* disconnect2

* fix

* ✌️

* clean up config

* typesを戻した

* backend/src/web/index.ts

* notification-badges

* add scripts

* change create-notification.ts

* Update packages/client/src/components/notification.vue

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* disconnect

* oops

* Failed to load the script unexpectedly回避
sw.jsとlib.tsを分離してみた

* truncate notification

* Update packages/client/src/ui/_common_/common.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* clean up

* clean up

* refactor

* キャッシュ対策

* Truncate push notification message

* fix

* wip

* clean up

* migration

* migration

* comment

* move soundConfigStore

* ✌️

* clean up

* クライアントがあったらストリームに接続しているということなので通知しない判定の位置を修正

* components/drive-file-thumbnail.vue

* components/drive-select-dialog.vue

* components/drive-window.vue

* merge

* fix

* remove reversi setting

* Service Workerのビルドにesbuildを使うようにする

* return createEmptyNotification()

* fix

* fix

* i18n.ts

* update

* ✌️

* remove ts-loader

* fix

* fix

* enhance: Service Workerを常に登録するように

* pollEnded

* pollEnded

* URLをsw.jsに戻す

* clean up

* clean up

* update sounds.vue

* update

* fix type

* ✌️

* ;v;

---------

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* enhance: カスタム絵文字関連の変更 (misskey-dev#9794)

* PackedNoteなどのemojisはプロキシしていないURLを返すように

* MFMでx3/x4もしくはscale.x/yが2.5以上に指定されていた場合にはオリジナル品質の絵文字を使用する

* update CHANGELOG.md

* fix changelog

* ??

* wip

* fix

* merge

* Update packages/frontend/src/scripts/media-proxy.ts

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* merge

* calc scale

---------

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* feat: role timeline

Resolve misskey-dev#10581

* feat(server): Misskey Webでユーザーフレンドリーなエラーページを出す (misskey-dev#10590)

* (add) user-friendly error page

* Update CHANGELOG.md

* (add) cache-control header

* Add ClientLoggerService

* Log params and query

* remove error stack on client

* fix pug

* 文面を調整

* :art]

---------

Co-authored-by: tamaina <tamaina@hotmail.co.jp>

* test(backend): Add tests for users (misskey-dev#10546)

Co-authored-by: tamaina <tamaina@hotmail.co.jp>

* fix(backend): カスタム絵文字でリアクションできないことがある問題を修正

* Update CustomEmojiService.ts

* fix type

* Use unique identifier for each follow request (misskey-dev#10600)

Co-authored-by: anemone <anemoneya@icloud.com>

* fix type in CustomEmojiService

* fix type in CustomEmojiService 2

* fix

* Update CHANGELOG.md

* fix(server): アンテナとロールTLのuntil/sinceプロパティが動くように (misskey-dev#10605)

* fix(server): アンテナとロールTLのuntil/sinceプロパティが動くように

* fix

* Update CHANGELOG.md

* Update about-misskey.vue

* 🎨

* fix(backend): チャンネルのピン留めされたノートの順番が正しくない問題を修正

Fix misskey-dev#10541

* New Crowdin updates (misskey-dev#10585)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Chinese Simplified)

* 13.11.3

* [ci skip] remove outdated comment

* [ci skip] improve readability

* 一部の Workflow を削除

---------

Co-authored-by: okayurisotto <aytkzm@gmail.com>
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
Co-authored-by: futchitwo <74236683+futchitwo@users.noreply.github.com>
Co-authored-by: Namekuji <11836635+nmkj-io@users.noreply.github.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
Co-authored-by: Nanashia <nanashia.128@gmail.com>
Co-authored-by: hutchisr <42283663+hutchisr@users.noreply.github.com>
Co-authored-by: anemone <anemoneya@icloud.com>
Co-authored-by: Ebise Lutica <7106976+EbiseLutica@users.noreply.github.com>
@tamaina
Copy link
Contributor

tamaina commented Apr 13, 2023

リモートユーザーばっかだとsilentあんま意味ない感じがした

@tamaina
Copy link
Contributor

tamaina commented Apr 13, 2023

あとマシンの性能一杯一杯まで使ってジョブキューをこなそうとするのが厳しい感じがある

(各種キューにリミッターが欲しい)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
packages/backend Server side specific issue/PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

フォロー/フォロー解除をジョブキューにする
3 participants