-
-
Notifications
You must be signed in to change notification settings - Fork 85
Supavisor V2 #408
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
Supavisor V2 #408
Conversation
|
Hey, @supabase/dashbit, we have prepared improvements for Supavisor and would love to hear your feedback. There are a lot of changes, so feel free to review whatever you like. We are particularly interested in your opinion on the ProxyHandler. The corresponding implementation is here: |
|
Exciting work! Do you have any numbers or results into the performance of this new version?
I haven't reviewed the code yet, so I will try to verify this as well, but remember that, if the client crashes for some reason, you most likely can't assert for certain the state of the socket: for example, was something only partially written to it? So you may need to drop the connection altogether or do some sort of cleanup (if possible), like make sure to abort transactions and other things. I am not sure how much state can be carried around. |
|
Two additional questions for now:
|
|
Two more:
|
😊😊😊
We are still measuring performance for different scenarios. When the pooler is on the same machine as the database, Supavisor outperforms or performs the same as PgBouncer. However, it is slightly slower when a Supavisor cluster of two nodes is in the same AWS zone as the database.
We keep a linked DbHandler which originally created the socket, and if the client goes down, DbHandler will be respawned with a new direct connection.
I spent some time finding bottlenecks, and the biggest ones were metrics collection (shout out to @hauleth who fixed that) and the synchronous calling between ClientHandler and DbHandler to avoid overwhelming the mailboxes. So far, we haven't added anything new to Poolboy, except our previous changes for idle timeout.
DbHandler is still responsible for establishing direct connections in transaction mode, reconnecting in idle state, and it has been extended with handler_call to change ownership of the TCP socket. However, the connection logic for talking with the database during transactions is located in ProxyDb. In the future, we will remove the old module.
Not at the moment, but it could potentially become a problem. The update is already quite complex, so I don't want to add further complications. We can always add this feature later
Hmm, it should not use SSL for proxying to another node. The main reason for authentication was to provide an additional security guard. It's not very resource-intensive but can prevent accidental connections if the client has some issues with authentication. |
|
Fantastic. I have already reviewed the code and I will do another pass later. My only suggestion so far would be to have a custom tcp handshake for the proxy, so you have only a single special port instead of a pool of them and there is no need for additional auth. For security, you can put a 20-40 bytes random token on Syn instead of the Ranch port, and the new handshake uses a key plus this token for connecting. But as you said, I don't think it is a necessary change at this moment.
This is great! As far as I know, no other "bouncer" offers clustering anyway, and slightly slower would certainly be expected. |
a good call, thanks! |
josevalim
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did another review of the proxy modules and I have dropped only two additional comments. :)
|
Moved |
In this PR, Supavisor has been adapted for Erlang 27 and Elixir 1.17. The metrics backend has been changed from PromEx to Peep, and the most significant change is the introduction of ProxyHandler for processing transaction mode.
The ProxyHandler first authenticates the incoming connection through auth_query. If there is no connection pool, it creates one and also launches a Ranch on a free port, saving the port and host in the corresponding Syn record.
If the pool is on the same node as the client connection, we locally change the owner of the TCP socket for each transaction to the direct connection with the database. After the transaction is completed, the client process returns ownership of the TCP socket to the DbHandler.
If the pool is on a different node, the client process connects to the Ranch of the corresponding pool on the other node, switches to session mode, and forwards everything (works like proxy). The local Ranch operates the same way as when the client connection is on the same node as the connection pool.
With this handler, erldist is used only for synchronizing Syn. Forwarding query data between nodes is done via TCP sockets (Ranch)