What happens on the server when a MySQL client connection is lost?
3
votes
1
answer
2260
views
Imagine the following situation:
You have a MySQL server
S
and two clients, A
and B
.
Both clients connect to S
(e.g. using the CLI).
A
starts a transaction and then locks a table with WRITE
permissions and inserts a row into the table.
Now B
tries to select all rows from the table and - of course - has to wait until A
has committed AND unlocked the table.
Imagine that A
's connection is interrupted before it is able to commit or rollback. In my special use-case, the connection might be interrupted at any point in time.
I tested this scenario using three virtual machines which are connected to a common virtual bridge. Using brctl
I can simply remove individual VMs in order to simulate connection interruptions.
### The result
Client B
is stuck, because it waits for the table to get unlocked.
Typing SHOW PROCESSLIST
in the CLI of the server shows me this:
+----+------+-----------------+----------+---------+------+---------------------------------+----------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+------+-----------------+----------+---------+------+---------------------------------+----------------------------+----------+
| 8 | root | B:38129 | foo | Query | 1676 | Waiting for table metadata lock | select blockname from root | 0.000 |
| 9 | root | A:54806 | foo | Sleep | 1679 | | NULL | 0.000 |
| 12 | root | localhost | NULL | Query | 0 | init | show processlist | 0.000 |
+----+------+-----------------+----------+---------+------+---------------------------------+----------------------------+----------+
So the server thinks that the connection from A
is still alive, while it already was lost _minutes_ ago. Having a look at netstat
also tells me that the connection is still considered to be ESTABLISHED
and still alive.
I also observed the bridge: Not a single packet from S
to A
.
Client B
is stuck forever. I have to restart the whole server to unlock the table.
### What I expected
I want my server to detect (after some predefined time) that the connection to A
is lost even if A
did not send any more queries. Then I want my server to rollback any uncommitted transactions and finally to unlock the table.
How can I realise this?
Why aren't there any TCP keepalives from S
to A
?
Is it possible to define any kind of timeouts?
---
I played around with the variables wait_timeout
, innodb_lock_wait_timeout
, and interactive_timeout
.
* interactive_timeout
is not interesting because my productive system will not use the CLI.
* innodb_lock_wait_timeout
seems not to be respected in any way.
* wait_timeout
indeed improves my situation: idling sessions are killed after the timeout. But I only want them to be killed in case of connection interruption. I want to keep the connection alive to improve performance (save tcp handshakes, SQL logins, db selection...)
Asked by rralf
(139 rep)
Apr 15, 2015, 11:00 PM
Last activity: May 20, 2021, 01:23 PM
Last activity: May 20, 2021, 01:23 PM