Misskey: DBのクエリが多すぎる

Created on 7 Nov 2020  ·  23Comments  ·  Source: syuilo/misskey

💡 Summary

毎秒800〜1500ぐらいのクエリがPostgreSQLに飛んでいて、PostgreSQLとMisskeyを違うネットワークに置くと極端に重くなる。

参考GIF(内容が見えないようにリサイズしてます)
dJQkjHx4qG

🙂 Expected Behavior

DB内部である程度処理してから結果を返す

☹️ Actual Behavior

全部Misskey側で処理している

📝 Steps to Reproduce

  1. PostgreSQLのログを見れるようにする
  2. ユーザーが多いインスタンスを作る

📌 Environment

Misskey.io v12.54.0

⚙️Server 🐢Performance

All 23 comments

全部Misskey側で処理している の詳細が知りたい

例えばタイムラインを取得するクエリを例にすると、取得されることになる各ノートのユーザー情報を予めJOINするようにしているからDBで出来る限りのことはやっている状態ではなかろうか
https://github.com/syuilo/misskey/blob/30c9c3739f086a7f9df2c4d8ccae78c605a25bb9/src/server/api/endpoints/notes/timeline.ts#L125

packManyがpackを全部並列で呼び出してるのでfindOneが呼ばれまくってると思う
本来はpackManyでよしなにやってpackがpackManyのラッパになっているべき

別プロジェクトだけど例 https://github.com/rinsuki/sea/blob/5766344c7463dd856ea27d83a47245d764b14cac/src/db/repositories/post.ts (これも application は手抜いてfindOneを投稿数ぶん呼んでるのでよくない)

packMany はそれぞれに pack を呼び出していて、pack は渡されたものがオブジェクトなら find せずにそのまま利用しているから新たなクエリは発生しないように見える
https://github.com/syuilo/misskey/blob/30c9c3739f086a7f9df2c4d8ccae78c605a25bb9/src/models/repositories/note.ts#L95

noteのrepositoryだとpopulateEmojisとかだめそう

populateEmojisはカスタム絵文字が含まれてない限りクエリ発火しなさそうだけど populateMyReaction は毎回発火してそう

大きいインスタンスでクエリ数稼いでるのがたぶんこの辺
https://github.com/mei23/misskey-v12/pull/686/files
↑はsaveで無駄にトランザクションとSELECT流してるところを修正しているけど
この辺をクエリ的に減らすのは難しいかも

populateEmojisはカスタム絵文字が含まれてない限りクエリ発火しなさそう

それはそうなんだけどカスタム絵文字がめっちゃ付いてるとだいたいおもしろいのでRNされまくって刺さり度上がりそう (まあコーナーケースではある)

大きいインスタンスでクエリ数稼いでるのがたぶんこの辺

ノート作成はいろいろやることあるからクエリ多いだろうなぁ

write時のクエリを減らすのはめいめいが言っているように厳しそうだけど、read時のクエリはなんか工夫すれば減らせそうな雰囲気はするな

populateEmojis は見る感じやってることが複雑だからDBサイドでやるのは難しそう

packManyの時notesの分集約して一回のクエリで問い合わせればマシになりそう

あと気になっているのはデータベースという割と頻繁にアクセスされるであろうシステムを地理的に離れたサーバーで動かすのは割と良くあることなんだろうか

DB分けないとアプリサーバーの数増やせなくない?

pack系は非アクティブユーザーの分は処理しないからさほど増大しないけど
Note作成後にミュートやアンテナ見る所は休眠ユーザー分も処理するから登録ユーザーが増えるに従って増大していきそう

DB分けないとアプリサーバーの数増やせなくない?

サーバー自体を分けるのはあると思うけど、それを地理的に離れている場合でもやるのかなって思った

離れてると言っても国内だから20msぐらいの遅延だし、地理的に離れてないと以前の震災みたいに影響を受ける

サーバー自体を分けるのはあると思うけど、それを地理的に離れている場合でもやるのかなって思った

2リージョン以上で同じアプリ動かす時には素直にやるとDBをどっちかのリージョンに寄せないといけない気がするけどあんまり詳しくない (まあリードレプリカとかでマシにはなるだろうけどそれでもwriteはプライマリに行くはずだし)

2リージョン以上で同じアプリ動かす時には素直にやるとDBをどっちかのリージョンに寄せないといけない気がする

元々はPgpool-IIでロードバランシングしてたけど、クエリが多すぎるせいかPgpool-II噛ませるだけでかなりパフォーマンスが下がる
今回の構成も最後の方にPgpool-II入れてPostgreSQLでストリーミングレプリケーションしている同一ネットワーク内のDBにウェイトを置いてたけどそれでもめちゃめちゃ重かった

Note作成後にミュートやアンテナ見る所は休眠ユーザー分も処理するから登録ユーザーが増えるに従って増大していきそう

一定期間使用がなかったアカウントのミュートとかアンテナは削除するか一時停止みたいな処理しないとダメかなぁ
まあMisskeyくらいの規模ならデータベースに負荷がかかるほどのミュート/アンテナ設定済み休眠アカウントはなかなか発生しない気はする

負荷を考える上では休眠かどうかは考慮しなくて良いか

需要の無さそうなautoWatch機能を削除したのでノート作成時のクエリが若干減った
https://github.com/syuilo/misskey/commit/9d1fa3f20259cf7c303d49d5aae8e1fecdafc7ed

(需要があったとしてもサーバーサイドでやる必要はない)

Was this page helpful?
0 / 5 - 0 ratings