How come I still get deadlocks even after setting wsrep_retry_autocommit really high? - deadlock

I have a cluster of 3 percona xtradb 5.5.34-55 servers and since they are all writable, I get deadlock errors under any substantial load. Increasing wsrep_retry_autocommit variable helped with it to some extent, but ER_LOCK_DEADLOCK did not disappear completely. So I've tried setting wsrep_retry_autocommit to 10000 (seems to be the maximum), thinking it would make some queries really slow, but none of them would fail with ER_LOCK_DEADLOCK:
mysql-shm -ss -e 'show global variables like "%wsrep_retry_auto%"'
wsrep_retry_autocommit 10000
------------------------
LATEST DETECTED DEADLOCK
------------------------
140414 10:29:23
*** (1) TRANSACTION:
TRANSACTION 72D8, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s), undo log entries 1
MySQL thread id 34, OS thread handle 0x7f11840d4700, query id 982 localhost shm update
REPLACE INTO metric(host, name, userid, sampleid, type, priority) VALUES
('localhost','cpu-3/cpu-nice',8,0,0,0),('localhost','cpu-3/cpu-system',8,0,0,0),
('localhost','cpu-3/cpu-idle',8,0,0,0),('localhost','cpu-3/cpu-wait',8,0,0,0),
('localhost','cpu-3/cpu-interrupt',8,0,0,0),('localhost','cpu-3/cpu-softirq',8,0,0,0),
('localhost','cpu-3/cpu-steal',8,0,0,0),('localhost','cpu-4/cpu-user',8,0,0,0),
('localhost','cpu-4/cpu-nice',8,0,0,0),('localhost','cpu-4/cpu-system',8,0,0,0),
('localhost','cpu-4/cpu-idle',8,0,0,0),('localhost','cpu-4/cpu-wait',8,0,0,0),
('localhost','cpu-4/cpu-interrupt',8,0,0,0),('localhost','cpu-4/cpu-softirq',8,0,0,0),
('localhost','cpu-4/cpu-steal',8,0,0,0)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 344 n bits 488 index `unique-metric` of
table `shm`.`metric` trx id 72D8 lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 72D7, ACTIVE 0 sec updating or deleting
mysql tables in use 1, locked 1
7 lock struct(s), heap size 3112, 141 row lock(s), undo log entries 40
MySQL thread id 50, OS thread handle 0x7f1184115700, query id 980 localhost shm update
REPLACE INTO metric(host, name, userid, sampleid, type, priority) VALUES
('localhost','cpu-3/cpu-nice',8,0,0,0),('localhost','cpu-3/cpu-system',8,0,0,0),
('localhost','cpu-3/cpu-idle',8,0,0,0),('localhost','cpu-3/cpu-wait',8,0,0,0),
('localhost','cpu-3/cpu-interrupt',8,0,0,0),('localhost','cpu-3/cpu-softirq',8,0,0,0),
('localhost','cpu-3/cpu-steal',8,0,0,0),('localhost','cpu-4/cpu-user',8,0,0,0),
('localhost','cpu-4/cpu-nice',8,0,0,0),('localhost','cpu-4/cpu-system',8,0,0,0),
('localhost','cpu-4/cpu-idle',8,0,0,0),('localhost','cpu-4/cpu-wait',8,0,0,0),
('localhost','cpu-4/cpu-interrupt',8,0,0,0),('localhost','cpu-4/cpu-softirq',8,0,0,0),
('localhost','cpu-4/cpu-steal',8,0,0,0),('localhost','cpu-3/cpu-nice',8,0,0,0),
('localhost','cpu-3/cpu-system',8,0,0,0),('localhost','cpu-3/cpu-idle',8,0,0,0),
('localhost','cpu-3/cpu-wait',8,0,0,0),('localhost','cpu-3/cpu-interrupt',8,0,0,0),
('localhost','cpu-3/cpu-softirq',8,0,0,0),('localhost'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 344 n bits 488 index `unique-metric` of table
`shm`.`metric` trx id 72D7 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 344 n bits 504 index `unique-metric` of table
`shm`.`metric` trx id 72D7 lock_mode X locks gap before rec insert intention waiting
*** WE ROLL BACK TRANSACTION (1)
Shouldn't it be retried instead? Is there a way to verify percona actually retried the query 10000 times?

Don't have exact answer to your question, but for any write-intensive loads (if you you try to insert same data as the damn Drupal does), then deadlocks happen, and the only solution for me (still waiting to confirm this is 100% OK solution)- is to use haproxy in front of galera nodes, and define first node (haproxy backend definition) to be used, and other 2 nodes to be used as backup.
This way all mysql traffic will flow from clients, via haproxy to single galera node, and if that node fails, some other node will be used.
Hope that helps...
Andrija

In your answer scalability is a concern since we are in a cluster but make use of only one node is really bad use of resources. So alternatives will be , you can use any loadbalancer , if its haproxy you can create 2 listeners on two ports say 3306 and 3305 ; then say
lister bind to 3306 gets all the write requests from application , backend of this will have node 1 and then node2 and node3 as backup ;
lister bind to 3305 will have all read requests from application , whose backend will have all the nodes specified as normal.
So no its read scalable and write is with limited scalabilty where deadlock can be reduced to very extend.

Related

Can UPDATE referencing fields from the updated table cause deadlock?

I have a query like this:
UPDATE loginlogs SET rxbytes = rxbytes + ?, txbytes = txbytes + ? WHERE logid = ?
from time to time, my DB gets into a deadlock and SELECT * FROM sys.innodb_lock_waits shows pending locks like this:
wait_started wait_age wait_age_secs locked_table locked_index locked_type waiting_trx_id waiting_trx_started waiting_trx_age waiting_trx_rows_locked waiting_trx_rows_modified waiting_pid waiting_query waiting_lock_id waiting_lock_mode blocking_trx_id blocking_pid blocking_query blocking_lock_id blocking_lock_mode blocking_trx_started blocking_trx_age blocking_trx_rows_locked blocking_trx_rows_modified sql_kill_blocking_query sql_kill_blocking_connection
2020-12-27 07:43:32 00:00:04 4 `db`.`loginlogs` PRIMARY RECORD 37075679818 2020-12-27 07:43:32 00:00:04 1 0 19194139 UPDATE loginlogs SET ... HERE logid = 64634225227638257 37075679818:921:15944673:61 X 37075617021 19191704 UPDATE loginlogs SET ... HERE logid = 64634225227638257 37075617021:921:15944673:61 X 2020-12-27 07:43:07 00:00:29 1 0 KILL QUERY 19191704 KILL 19191704
As you can see, the 2 identical queries seem to run at the same time. And the 2nd one is waiting for the first one to complete.
I thought MySQL should handle simple UPDATE queries like this. Do I need to first select the bytes and then do the UPDATE without referencing rxbytes and txbytes in the new values?
BTW this started happening after update from MariaDB 10.4.2 to 10.4.17, therefore I also suspect MariaDB bug and I opened a bug report.
A lock-wait is not a deadlock!
I see this misunderstanding frequently.
What you have shown is a lock-wait. That is, one transaction is waiting for the other. Every UPDATE locks the rows it examines, and any concurrent UPDATE has to wait for the first one to COMMIT to release those row locks. That's a lock-wait. It's normal and common.
A deadlock is different. It's where two transactions get into a mutual lock-wait. UPDATE1 locks some rows, but does not commit yet. Then UPDATE2 tries to update the same rows, and begins waiting. Then the transaction for UPDATE1 tries another locking statement, that needs locks on some rows already held by the transaction for UPDATE2, possibly from a previous statement it ran. Thus both transactions are waiting for the other, and won't COMMIT to release the locks they hold, because they're waiting. The deadlock is so named because there's no way to resolve the mutual wait.
https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks.html says:
A deadlock is a situation where different transactions are unable to proceed because each holds a lock that the other needs. Because both transactions are waiting for a resource to become available, neither ever release the locks it holds.
You won't experience a delay from a true deadlock. MySQL watches for these cyclical lock-waits and forces one of them to rollback its transaction. This happens nearly instantly, so there is virtually no waiting.
So why did this start happening to you when you upgraded from MariaDB 10.4.2 to 10.4.17. Apparently something changed that affects either the number of rows locked, or the duration of the transaction, to make it more likely that you have concurrent transactions conflict in this way.
Or else the software did not change anything related to locking or transactions, but it was your traffic that changed, coincidentally, as you upgraded to the new version of MariaDB.

Object locking in DB2 LUW

Working on object locking in IBM DB2 LUW, I am using Read stability (RS) level locking on my table. This locks the records I have fetched in the Select query ,unless I am done with the transaction and mention COMMIT explicitly and release the lock. During this process, with another query/procedure want to return the locked row for a different purpose. How to go about this?Also, there is a parameter WAIT_FOR_OUTCOME to set lock time, where do I define this timeout?
Insufficient information: What is the effective setting for the CUR_COMMIT database? Also, the locking behavior can change with specific Db2-registry settings which you have not mentioned such as DB2_SKIP_INSERTED , DB2_SKIP_DELETED among others etc.
If the effective value of the CUR_COMMIT database parameter is ON, and the other connection is using CS isolation for the query, then the other connection will get the currently committed value of a locked row (i.e. the writer is not blocking the reader).
If you wish you use wait for outcome, it is a clause applicable to a SELECT statement, refer to the documentation.
Use a special register to have session-specific wait controls via
SET CURRENT LOCK TIMEOUT WAIT n ; (where n is the number of seconds), otherwise either a client-side timeout (if relevant), or the database level LOCKTIMEOUT setting will apply, whichever is lower. Note that the default for LOCKTIMEOUT is -1 (wait forever) which is nearly always unsuitable, typical values are 30 or 60 for OLTP.
Other connections can try using UR isolation per statement (e.g. for the query to select a locked row value).
Up until v11.5.6, Db2 LUW did not allow to specify the lock wait timeout on the statement level. It had no SQL statement syntax for that.
With v11.5.6 or later you can do something like this:
SELECT *
FROM some_table
WHERE col1 = 'Foo'
FOR READ ONLY
WITH RS USE AND KEEP EXCLUSIVE LOCKS
WAIT FOR OUTCOME WAIT 5
;
The above will create an exclusive row-level lock on the row(s) returned by the query. The new addition is the WAIT 5 which means to wait 5 seconds for the lock, otherwise throw error.
Before v11.5.6 the lock timeout could only be specified at the session level or at the server level. Both of these are in mao's answer.
For more information:
https://www.ibm.com/docs/en/db2/11.5?topic=statement-concurrent-access-resolution-clause

MariaDb Slow Query log - only query time is high

I have the following entry in my slow query log:
Query_time: 4.000347
Lock_time: 0.000095
Rows_sent: 0
Rows_examined: 0
update `my_table` set `a` = null, `b` = 'x', c= ... (updating around 20 fields) where `id` = 1234;
id is the primary key in this table; and there is a record which matches this id
A select by PK is fast. And in most cases update by PK runs a lot faster; so I'm trying to work out the cause of the slower ones.
No significant spikes show up on CPU, I/O or memory monitoring; and the load on the system is relatively flat.
There seems to be some pattern with how close to exactly 4 seconds these queries are. Its not like I have a distribution between 2 and 6 seconds; they all right on 4!
The 4 second PK updates show up in little groups; and some of them came 4 seconds; 1 after the other.
All that; seems to indicate something ... odd.
There are over 1000 db connections on the server, so I'm wondering if there could be some thread scheduling stuff clogging things up from time to time?

Behavior of Oracle GoldenGate CSN when multiple replicas exist?

Need to get more details about Oracle GoldenGate CSN.
Following is the system architecture configured.
Source DataBase - Oracle
Target DataBase - Oracle
For each table on souce database, 2 tables (BASE table and DELETE table) are defined on target database.
Configured 2 replicas to transfer data from source to target database.
One replica moves the INSERT/UPDATES to target database and other replica moves the DELETE records to target.
Following is the view defined by GG which gives GoldenGate metadata information.
GoldenGate metadata info
Row with servername ends with 'CRN01A' represents the GG replica for BASE table.
Row with servername ends with 'CRN01D' represents the GG replica for DELETE table.
APPLIED_LOW_POSITION gives 'All messages with commit position less than this value have been applied'.
Our question is if the both replicas will have their own isolated CSN or in synchronization with respect to extract.
Example:
APPLIED_LOW_POSITION initial value - 100 for both BASE table replica and DELETE table replica.
100 INSERTS/UPDATES occured on source DB. BASE table replica APPLIED_LOW_POSITION value changed to 200.
After step2, 3 DELETEs occured on source system. Our question is at this point of time, what will be the APPLIED_LOW_POSITION value for DELETE replica?
Will it be 103 or 203?
Can you please provide your thoughts?
The CSN counter is connected with the CSN number on the source database. It always grows.
If the CSN was equal 100, then some transactions (INSERT) have occurred. It grew to 200.
Then 3 additional DELETE operations were made. And from 200 it would grow to 203.
Those 3 DELETE operations may not be replicated to the INSERT/UPDATE target, so the APPLIED_LOW_POSITION may not change on this target and stay at the 200 level.
But on the DELETE target the APPLIED_LOW_POSITION would rise to 203.

Galera Cluster - Autocommit

I set up a galera cluster with 2 nodes, and I disable autocommit at 2servers.
set autocommit=0;
INSERT data at server1 and COMMIT,but server2 didn't renew data;
server2 need COMMIT; before SELECT;
how do i renew data without COMMIT, except autocommit=1?
You may be referring to "critical read" issues, not autocommit. See the manual on wsrep_sync_wait, which should be SET to 1 before a SELECT that might be reading data from a node other than the one where the data was written. This makes sure the replication is caught up so that you get the 'right' answer.
My Galera blog discusses that aspect, and more.
If you need something than a SELECT to wait, then use, say, 15 for the value in the SET.
(I prefer to explicitly use BEGIN instead of using autocommit=0; then I can pair up the BEGINs and COMMITs in code and not leave a transaction 'open' forever.)

Resources