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
Improve performance by making database queries async / figure out better postgres caching. #606
Comments
This is a good idea. I've noticed that basically all DB actions (within a single websocket connection) are synchronous. So the longer operations (like voting), can temporarily block even things like a post loading. |
from masto conversation: An easy path forward for that would be wrapping your shared state in Actually i'm not sure if websockets can do that, maybe look into spinning up a separate SyncActor to manage shared state. Once you have a SyncActor, though, you can say "Spin up this many threads of SyncActors" and actix will go ahead and do that |
Also mentioned in the masto thread: |
I'm pretty bad at async programming, esp with rust. I could def use some help with this. I could use |
I'm really stuck with this. Wasted a day on trying to use I opened up a ticket on actix to see if anyone can help out there: actix/actix-web#1455 . Lemmy very closely follows their websocket_chat example, so this is an issue affecting everyone using that as a basis. |
Unfortunately adding |
@asonix @Nutomic Okay so I finally figured out the blocking issue, and I can't blame rust or async, but postgres materialized views. As usual its one of the two problems in compsci, caching. So all the data in lemmy is stored in very normalized tables, but fetched using views, that often have to do some pretty slow queries... sometimes 500+ ms queries to get things with advanced sorting like a hot sort. So a few months ago I did a lot of work to create materialized views to match every view in lemmy, IE there's a Using postgres' This also means that any action is pretty much locking all reads out until that finishes, which is not good. But then again, using the materialized views in the first place was to make lemmy have really fast read-times, but as a consequence its slowed down both write-times and read-times (while a materialized view is being updated). I'm not really sure the best solution, because using a caching method outside of postgres adds a lot of complication, and also means pushing the same problem elsewhere... If I like a comment, I want to see that result immediately. I don't know all my options, but my current favorite is:
edit: I found an article that might help: https://hashrocket.com/blog/posts/materialized-view-strategies-using-postgresql Instead of a trigger refreshing the whole view, I might be able to do it more atomically. |
Typo I guess? Cant have reads slow down and speed up. |
Kinda, I corrected a little. Reading right now is super-fast, but when refreshing those materialized views, it stalls all current readers. So removing the views would slow down reads overall, but it would be faster than the current "stalled out" I think the solution might not be as difficult as I thought: and that's to not have the triggers run |
My little bit to add. Raddle shows a small "in progress" indicator when pressing up/downvote buttons. If average time of a vote to be recorded in the db is not too much, this approach could be used, in this case the UI behaves both honestly (you see exactly what's happening with no lie about your vote) and immediately/responsively. Not sure though about how users will like this. AFAIK, the UI is doing background update anyway, correct me if I'm wrong. How long could it take for a vote to get finally recorded into db and the counts to be sent back to the frontend? |
I used to show vote progress indicators just like the comment one, but then I made the vote actions semi-async. IE it doesn't wait for the result. Right now to run all the mview refreshes its taking about 2 seconds, but after I make the changes it'll probably be really fast, and I can go back to the indicators. Either way I'm not gonna do this until after a federation merge, because its heavy DB changes. |
Turns out the best way to do this is to just use fast tables, which are built from the views, indexed, and then triggers on the table inserts fetch rows from the views to fill the fast tables. |
This is not important now because CPU load is very low on the server, but something to keep in mind for the future.
The text was updated successfully, but these errors were encountered: