It appears this is caused by a deadlock where Magento is trying to clear out old consumer nonces:
LATEST DETECTED DEADLOCK
------------------------
2017-07-27 05:38:31 2b268f8e2700
*** (1) TRANSACTION:
TRANSACTION 801608608, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1
MySQL thread id 8441440, OS thread handle 0x2b2664f4f700, query id 824710525 10.128.83.103 windsor updating
DELETE FROM `oauth_nonce` WHERE (timestamp <= 1501126711)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 125222 page no 25 n bits 344 index `OAUTH_NONCE_NONCE_CONSUMER_ID` of table `windsor`.`oauth_nonce` trx id 801608608 lock_mode X waiting
Record lock, heap no 269 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 30; hex 303030313365666139353038323531373365383139336335623831666432; asc 00013efa950825173e8193c5b81fd2; (total 32 bytes);
1: len 4; hex 00000002; ascββββ ;;
2: len 6; hex 00002f97b46a; ascββ /ββj;;
3: len 7; hex b9000001640110; ascββββ dββ;;
4: len 4; hex 597975c2; asc Yyu ;;
We had 48460 recent nonces in our table at the time:
mysql> select count(*) from oauth_nonce;
+----------+
| count(*) |
+----------+
|ββββ48460 |
+----------+
The deadlock was caused by the following SQL run by Magento:
DELETE FROM `oauth_nonce` WHERE (timestamp <= 1501126711)
The above doesn't contain a limit (which extends execution time) and also is filtering based on timestamp which doesn't have an index:
mysql> show create table oauth_nonce;
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Tableββββββ | Create Tableββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| oauth_nonce | CREATE TABLE `oauth_nonce` (
ββ`nonce` varchar(32) NOT NULL COMMENT 'Nonce String',
ββ`timestamp` int(10) unsigned NOT NULL COMMENT 'Nonce Timestamp',
ββ`consumer_id` int(10) unsigned NOT NULL COMMENT 'Consumer ID',
ββUNIQUE KEY `OAUTH_NONCE_NONCE_CONSUMER_ID` (`nonce`,`consumer_id`),
ββKEY `OAUTH_NONCE_CONSUMER_ID_OAUTH_CONSUMER_ENTITY_ID` (`consumer_id`),
ββCONSTRAINT `OAUTH_NONCE_CONSUMER_ID_OAUTH_CONSUMER_ENTITY_ID` FOREIGN KEY (`consumer_id`) REFERENCES `oauth_consumer` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='OAuth Nonce' |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Is it enough to add index on timestamp field to avoid deadlock?
That would definitely help (and is what we have done), I think it's best to delete this in increments, including an ORDER BY (for replication) and LIMIT to reduce the overall query time for a large DELETE operation.
Thanks for the details! Would be great if you prepare a pull request including suggested changes. But if not, I believe core team received enough information to elaborate a fix.
@magento-engcom-team does it make sense to use int(x) with order + limit + indexes instead of timestamp? Are we using or plan to use timestamp in the future for oauth nonces?
@KarlDeux timestamp is currently int(10), what exactly are you proposing? Thanks!
@vrann I guess I had brain lag lol... checking this now.
Adding the index allowed me to pass the given scenario. See referenced PR
Hello, @careys7!
Could you help me to reproduce this issue? Here is what I tried:
php bin/magento indexer:reindexNo deadlock. Can you give more details about the tool that was used when you experienced this issue?
Hey @TomashKhamlai we had about 18 requests / sec to the WebAPI at the same time that the cron was trying to clear the nonces out.
See Magento\Integration\Cron\CleanExpiredTokens. I don't know of any issues with the Magento indexes
@TomashKhamlai @careys7,
That is exactly what I did, basically created a siege against the W.API with 20 r/s while the cron was cleaning and had a deadlock. After the indexes didn't get one.
Maybe under a higher load it might encounter a deadlock again but I feel like 20 r/s are fairly good.
Hi @careys7. Thank you for your report.
The issue has been fixed in magento/magento2#13328 by @KarlDeux in 2.2-develop branch
Related commit(s):
The fix will be available with the upcoming 2.2.6 release.
Hi @careys7. Thank you for your report.
The issue has been fixed in magento/magento2#16715 by @rogyar in 2.3-develop branch
Related commit(s):
The fix will be available with the upcoming 2.3.0 release.
Most helpful comment
Adding the index allowed me to pass the given scenario. See referenced PR