-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
リアクションごとにノートのリアクション情報が更新されるのは重い #11093
Comments
もしくは非正規化して持っててもいいけど、更新は定期的にまとめて行うようにするとか |
SlackとかDiscordがどういう実装してるのか気になるな |
投稿とかリノートされた時にブワーってつく傾向にあるから、Redisで短期間のキャッシュを持ち、反応が落ち着いたらDBに反映というのが良さそう |
問題は、RedisはJSONに対応してないからオブジェクトの特定のキーの値をアトミックにインクリメントするみたいな処理がおそらく出来ないこと |
|
という流れになると思うけど、2を処理している最中に新しくキーが追加されたらそれが処理されないまま3に進んでキーが削除され、間違った値がDBにベイクされてしまう問題が発生するなど、意外と面倒かも |
良い実装方法募集中 |
あとノートの数が多い場合、今よりだいぶマシになるとはいえやっぱり2の負荷が高そう |
PostgreSQLにおいて、あるレコードに対して1秒間に大量の書き換えがある場合の、一般的なパフォーマンス改善策ってなんだろう |
クエリの書き方によっては別にそうでもない可能性はあるな |
Redisにキャッシュしつつ、Redisにキャッシュがない場合だけDBから集計する感じでいけないかな |
reactionsテーブルに対してノートIDの配列を渡したら以下のような結果が返ってくるSQL募集中 [{
noteId: "hoge",
reactions: {
'foo': 10,
'bar': 5,
}
}, {
noteId: "huga",
reactions: {
'foo': 20,
'buzz': 4,
'bar': 2,
}
}, {
...
}] |
投稿日時が今からT以内の投稿であれば、リアクションされていれば高確率でRedisにキャッシュされているはずなのでRedisからキャッシュを読み、全面的にそれを採用しRedisになかったとしてもDBには問い合わせない(「その投稿にリアクションがされていない」ことと「リアクションされているがRedisにキャッシュされていない」ことの区別が不可能なため、パフォーマンスを優先しRedisにない場合はリアクションされていないと見做す) が良いかも |
問題としては
の負荷が高い可能性があるという点 |
実際にいっぱいリアクション付いた投稿に対して |
SELECT "noteId", "reaction", COUNT(*) AS "reactionCount"
FROM note_reaction
WHERE "noteId" IN ('9dh0bkw15q', '9dmmip9y48')
GROUP BY "noteId", "reaction"; で |
よさそう |
同じ種類のリアクション100個にたいして100レコードが返ってくるというのを避けられればどんな形式でも良い |
でもCOUNTって絶対遅いよね |
インデックスあっても遅いかしら |
note_reactionが762万レコードあるけど↑のようなSQLだと一瞬だったわ(INだと流石にインデックスが効いてるか) |
|
ioのDBでめちゃくちゃリアクション付いてる投稿とかめちゃくちゃ古い投稿とか全くリアクション付いてない投稿などいろいろ指定してクエリしてみてどれくらい時間かかるか計測しようとしている |
ちなみにioではnote_reactionレコードは1億くらいあるっぽい |
(ちなみにSQLはChatGPT頼り) |
#10173 |
150msくらいだった |
今後もリアクションのレコード数は増加していくことを考えると、やっぱりノートからreactionsを消すことは現実的ではなさそうで、「noteにreactionsは持ちつつもその更新は一定間隔でbulk updateする」が落としどころかもなあ |
おごごごご |
Redisのリアクションイベントを拾って一定間隔(実行完了から1秒後みたいなインターバルにする?)でDBに適用するというDBキューがあればいいのか |
リアクションイベントをメモリに保持しておく必要があるんだからキューじゃダメでデーモンじゃないとか |
This comment was marked as off-topic.
This comment was marked as off-topic.
それが今の状態ですね |
あーテーブルは同じか |
テーブル分けたとしても結局そのテーブルの更新が重くなる |
テーブルを分けるならそれをRedisに保持しておくほうがいいんじゃないかと(整合性は知らない) |
要するに以下のような要求がある。 これを実現するには以下のようにすればよいはず。 読み出し方法 書き込み方法 この方法の肝は、PostgreSQLの非正規化テーブルへ値をコピーする操作の後にリアクションが入って、Redisのexpireが延期された(「Redisからの削除がやっぱりなしで」になった)としても、PostgreSQLの非正規化テーブルが予定より早く更新されたというだけで、全体の不整合を引き起こさない点にあります。 |
PostgreSQL(というかTypeORM)、それぞれ異なる値でのbulk updateに対応してない可能性があるな |
やっぱり対応してなかった |
やる必要がある |
hash使えそう |
Summary
Issueあった気がしたけど見当たらなかった
例えば1秒間に100回リアクションがつく場合リアクションレコードの挿入に加えて、100回ノートレコードの更新(=PostgreSQLでは実質的にノートテーブルの新規挿入&削除)が走ることになりかなり負荷が高い
そのためノートレコードごとにリアクション情報を非正規化して持つのをやめたいが、ノート取得するたびにリアクションを集計してくるのもかなり負荷が高いと思われるので、何かいい解決策を考える必要がある
例えばRedisにうまいことキャッシュできないかしら
案
The text was updated successfully, but these errors were encountered: