[MDEV-9622] MariaDB client connection hangs when semi-sync is enabled but not connected Created: 2016-02-24 Updated: 2016-04-08 Resolved: 2016-04-08 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Replication |
| Affects Version/s: | 10.1.11 |
| Fix Version/s: | N/A |
| Type: | Bug | Priority: | Major |
| Reporter: | Joseph Glanville | Assignee: | Kristian Nielsen |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Environment: |
Ubuntu 14.04, official MariaDB packages. |
||
| Description |
|
When using semi-sync replication with the master configured to block writes until the number of semi-sync slaves is > 1 with a long (or infinite) timeout there seems to be a bug when inserting data when a slave is disconnected. Specifically if a write query is executed it's successfully blocked however once the slave is connected the client connection isn't unblocked (and never receives any data indicating success or failure of the query). Things however get more strange as the query is actually successfully executed on connection of the slave and the data is properly replicated. You can reproduce this by doing the following. Start a master server. Enable semi-sync replication with the following: CREATE USER 'flynn'@'%' IDENTIFIED BY 'flynn' Execute a query that would write data. The bug is reproducible with DDL and DML, CREATE DATABASE is probably the easiest option. Note that your client will now be hung. This goes for any connector and the mysql command line client. Create a slave from a backup of the master, populating the GTID of the master (or at the time of backup if the master has progressed): INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so' The master should now be writable again but your initial write should still be hung. Let me know if any additional information can be supplied, happy to do the leg work running debug builds etc. |
| Comments |
| Comment by Joseph Glanville [ 2016-02-24 ] |
|
So playing with this some more suggests this is only a problem in single threaded/connection applications. Because of how the semi-sync logic works sleeping threads are only woken up when a new write is processed. In the case of an infinite timeout this means that unless you do another write on another connection your previous connection will never unblock. The reason why this is important is the semantics of the timeout. The following only applies to applications that don't do concurrent writes. Would there be a way to wake connections up when a new slave is connected or better yet when a segment > the wait position has been transferred to a slave? |
| Comment by Joseph Glanville [ 2016-02-24 ] |
|
Another reasonable solution would be to have an option to change the behaviour on timeout from switching semi-sync off to returning an error to the client and rolling back the transaction. |
| Comment by Joseph Glanville [ 2016-02-24 ] |
|
I have found what I believe to be the root cause, which is that when using purely GTID replication the initial binlog dump doesn't result in waiting sessions being woken up because it relies on a comparison of the log file names/positions which may not be set on CHANGE MASTER when using purely GTID replication. Changing my test case to also set MASTER_LOG_FILE and MASTER_LOG_POS worked around the issue. Should I update the original issue to reflect the root cause? |
| Comment by Elena Stepanova [ 2016-02-24 ] |
|
When you do SET GLOBAL gtid_slave_pos = MASTER_GTID, which GTID do you set, exactly? |
| Comment by Joseph Glanville [ 2016-02-24 ] |
|
I set the GTID of the most recent entry in physical backup used to create the slave. It appears ActiveTranx::compare doesn't know how to handle GTID replication, or at least it's not aware of it and something should be converting to the old log file name + pos format before calling it. |
| Comment by Elena Stepanova [ 2016-02-24 ] |
|
I asked because I can easily reproduce the behavior if I use GTID of the hanging event, but not with the GTID of the last executed event. |
| Comment by Joseph Glanville [ 2016-02-24 ] |
|
Ahh, looks like I had a bug in my test script that was trying to replicate the hang. After I got past this one I ran into a different issue which I am not sure is actually solvable. Basically I have a system that sets up an automated chain replicated MariaDB setup. Normally it's setup with 3 nodes, one master with a semi-sync slave and an async slave replicating from the semi-sync one. Primary -> Sync -> Async. Now when this is being setup each pulls a physical backup from it's upstream peer using xtrabackup. All of this works fine except in one special case. Which is when someone attempts to call something like CREATE DATABASE while xtrabackup is trying to pull the first physical backup in order to setup the semi-sync slave. What happens here is that the CREATE DATABASE transaction goes into the active transactions hash table and the database starts waiting on a slave to replicate it. Is there anyway to avoid this scenario? The only hunch I have right now is because the underlying filesystem is ZFS is looking into whether I can create a consistent snapshot without needing to call FLUSH TABLES WITH READ LOCK or other massive database lock. Is it possible to take a consistent backup this way or prevent DDL like CREATE DATABASE from locking up the database until the semi-sync slave is online? Like a stronger version of @@read_only? |
| Comment by Kristian Nielsen [ 2016-02-24 ] |
|
The GTID set in gtid_slave_pos is the last event executed on the slave. I am not much familiar with semisync, but I'd expect that then the GTID will I think that is what Elena was refering to, so I agree, that seems right. |
| Comment by Joseph Glanville [ 2016-02-26 ] |
|
Seeing as I have gotten to the bottom of this and it's clear it's not actual a MariaDB bug but rather an interaction between semi-sync replication, locks and innobackupex/xtrabackup this should probably be closed as invalid. |
| Comment by Kristian Nielsen [ 2016-04-08 ] |
|
Closing as per discussion in comments |