Joining some large rooms, such as #freenode_#haskel:matrix.org (1.4k members), fails because synapse eats up all the available memory leading to it being forcefully stopped. I've configured my system to limit synapse to 3.5 GB of RAM. Upon joining, synapse first spends some time doing some processing (seeing high CPU usage, RAM usage close to baseline 500 MB) and after a while the RAM consumption starts to steadily climb until it reaches the 3.5 GB mark when it has to be killed.
Here are the logs from the moment of joining the room up until synapse getting killed
ram-crash.redacted.log
The request for joining the room comes in at line 28. On line 564 synapse stopped printing anything to the logs and just maintained high CPU usage while steadily growing RAM consumption for ~1 minute until being killed.
Joining other large rooms, e.g., #matrix:matrix.org (3.2k members), #synapse:matrix.org (1.2k members), works fine (haven't monitored RAM consumption when joining but i had the same limits set). Some other person on #synapse:matrix.org reported joining a room with ~20k people with RAM consumption going up to ~1.1 GB, which leads me to suspect that i might be seeing something abnormal in my case. Am i?
Other than this issue, synapse seems to be working fine. I'm willing to repeat this and do some profiling if necessary.
#freenode_#haskel:matrix.orgVersion: 1.12.1
Install method: NixOS
Platform: latest NixOS master branch (commit 01c8795673ecff6272895a085e9fe1ffa3b33620) running on a rockpro64 sbc (with a custom patched kernel).
The "size" of a Matrix room isn't described by its number of users but the number of state events (e.g. joins, leaves, kicks, bans, changes of name, topic, power level rules, join rules, etc.) in its history. To summarise, there is a component to Matrix called the state resolution algorithm that's in charge of resolving clashes between two servers that got out of sync regarding what state a given room currently is. This algorithm works through the whole state of the room, and needs to load most (if not all) state events in that room in memory to work. This is what's making Synapse so hungry on RAM when trying to join a large room, because it needs to retrieve and authenticate every state event, which can be expensive for old rooms. If you're interested, how exactly this algorithm works has been explained recently on the matrix.org website: https://matrix.org/docs/guides/implementing-stateres
IIRC this is also the reason why some rooms can't be joined from small homeservers on modular.im.
The above is more a point of context and details than "it has a reason so it's not an issue" (because it definitely is an issue), and I don't think there's an open issue about that on this repo so I'll keep that one open to track the status of this.
@babolivier: This algorithm [...] needs to load most (if not all) state events in that room in memory to work.
Every algorithm can be implemented using few RAM, but then maybe requiring more I/O to persistent storage (such as a DB) and being slower. This is a tradeoff decision.
The current implementation decisions exclude users of cheap hardware (for home servers) to join larger rooms. IMO this is a bug, isn鈥檛 it?
If the algorithm implementation would be tied more to the DB and the DB would appropriately implement caching, the memory usage behavior would probably be automatically more adaptive to the amount of available memory and maybe not that much slower with much RAM.
Another idea: Repeatedly check available free memory during execution of the algorithm, and if the requirements are not met, abort cleanly, send an error message to the user, and fall back to some (maybe less secure) alternative, instead of hoping for the OOM killer to do the right thing (after a phase in which the whole system nearly freezes).
What I think is, why don't we just give these chore to the homeserver of that room resides?
Say that I wanna join to X homeserver room, Just talk to X HS "Hey, I wanna join "xyz" room" and our HS also saving the state that we join "xyz" room of X HS. Then, event history sync and Future transaction like texts, media etc... just make our homeserver proxying that straight from X Homeserver ( I guess media delivery also using this approach too)
Why every server that wanna join these room need to process every state/event and all of that logic? I think that can be bypassed.
Federation is the core of matrix. By using these approach, every person even with a very small resource computing like Raspberry PI can spin their own homeserver and join to any room they like.
Bootstrapping room state quickly from a data/db sync, I like the idea.
@mxvin a room is replicated to _all_ homeservers that participate in that room, they don't live on a single server like in XMPP.
Similar issues for me. Though not sure if it's because of RAM consumption. I used htop to track the processes and RAM almost never goes above 500MB.
Currently running a homeserver on a Raspberry Pi 4 B with 4GB RAM. Initially, I was running on a Raspberry Pi 3 with 1 GB RAM. I've been able to join rooms like Element Android (2.5k), Synapse Admins (719). I'm using SQLite DB at the moment.
Trying to join a room like Matrix HQ (7.8k) though takes an extremely long time to try to join the room. Eventually, my server crashes and I get a 502 Bad Gateway error.
@lqdev First switch from sqlite to postgres. You shouldn't federate with sqlite.
Thanks @ptman I'll give that a try.
@ptman federation is a bit snappier after migrating to Postgres. Thanks for that suggestion. Though I'm still intermittently running into issues. I'm guessing part of that is the fact I have everything running on a RPi. To clarify, it appears it's large rooms that are bridged that I have trouble with, so I can see how that might be an issue (i.e. #techlore:matrix.org)
Most helpful comment
@lqdev First switch from sqlite to postgres. You shouldn't federate with sqlite.