MariaDB 避免死锁
MariaDB Avoid Deadlocks
我最初的错误是
Error No: 1213 - Deadlock found when trying to get lock; try
restarting transaction
好的,所以我写了一个循环,最大重试次数和中间的等待时间来尝试解决死锁问题。
$Try = 0;
while (!$Result = $dbs->query($MySQL)) {
$Try++;
if ($Try === MYSQL_MAX_RETRIES)
HandleMySQLError($dbs->error, $MySQL, false, $Test, $Trace);
else
sleep(MYSQL_RETRY_WAIT);
}
但现在我不断地得到一些原来的错误,还有一个新的错误
Got error 35 "Resource deadlock avoided" during COMMIT
但我似乎无法真正找出这意味着什么或如何解决它?
编辑
我第一次写这篇文章时遗漏了大量信息,但服务器是 Galera 和 MariaDB 集群中的 RedHat 7 AWS EC2(好吧,其中 3 个)。
我的查询运行是对存储过程的调用
call`getchatmessages`('<ChatID>','<UserID>',from_unixtime('<Some Timestamp>'));
而存储过程如下
CREATE DEFINER=`root`@`%` PROCEDURE `getchatmessages`(IN `__ChatID` CHAR(36), IN `__UserID` CHAR(36), IN `__Timestamp` TIMESTAMP(6))
BEGIN
DECLARE `__NewChatMessages` TINYINT(1) DEFAULT 0;
DECLARE `__i` INT(11) DEFAULT 0;
DECLARE `__Interval` INT(11) DEFAULT 100; -- ms
DECLARE `__Timeout` INT(11) DEFAULT 15000; -- ms
while `__NewChatMessages`=0 and `__i`<`__Timeout`/`__Interval` do
select 1 into `__NewChatMessages` from `chatmessages` where `ChatID`=`__ChatID` and `DateTimeAdded`>ifnull(`__Timestamp`,0) limit 1;
update `chatusers` set `DateTimeRead`=now(6) where `ChatID`=`__ChatID` and `UserID`=`__UserID`;
do sleep(`__Interval`/1000);
set `__i`=`__i`+1;
end while;
select `chatmessages`.`Body`, `chatmessages`.`ChatID`, `chatmessages`.`UserID`,
`chatmessages`.`ChatMessageID`, `chatmessages`.`DateTimeAdded`, UNIX_TIMESTAMP(`chatmessages`.`DateTimeAdded`) `Timestamp`, `users`.`FirstName`,
`users`.`LastName`
from `chatmessages`
join `users` using (`UserID`)
where `chatmessages`.`ChatID`=`__ChatID`
and `chatmessages`.`DateTimeAdded`>ifnull(`__Timestamp`,0)
order by `chatmessages`.`DateTimeAdded` desc
limit 100;
END
Galera 集群(MariaDB Galera 集群,3 个节点)中的死锁不是典型的死锁,而是多主冲突的一种通信方式:
http://galeracluster.com/documentation-webpages/dealingwithmultimasterconflicts.html
避免死锁的最简单方法是一次写入1个节点,即配置HA代理只写入1个节点。在您的情况下,您将在 Node1 上 运行 sp(与哪个节点无关,但始终在 1 个节点上,有点 "sticky sessions")。
这个Proc是在事务内部调用的吗?如果是这样,我强烈反对它的设计。你有一个循环,睡眠挂在事务上。
相反,UPDATE
本身就是一个事务。
这实际上可以消除死锁。但是,正如其他答案所讨论的那样,您仍然应该处理死锁。
Edit 由于没有 BEGINs
和 autocommit=ON
,OP 已经遵循了这个建议。唉。
我最初的错误是
Error No: 1213 - Deadlock found when trying to get lock; try restarting transaction
好的,所以我写了一个循环,最大重试次数和中间的等待时间来尝试解决死锁问题。
$Try = 0;
while (!$Result = $dbs->query($MySQL)) {
$Try++;
if ($Try === MYSQL_MAX_RETRIES)
HandleMySQLError($dbs->error, $MySQL, false, $Test, $Trace);
else
sleep(MYSQL_RETRY_WAIT);
}
但现在我不断地得到一些原来的错误,还有一个新的错误
Got error 35 "Resource deadlock avoided" during COMMIT
但我似乎无法真正找出这意味着什么或如何解决它?
编辑
我第一次写这篇文章时遗漏了大量信息,但服务器是 Galera 和 MariaDB 集群中的 RedHat 7 AWS EC2(好吧,其中 3 个)。
我的查询运行是对存储过程的调用
call`getchatmessages`('<ChatID>','<UserID>',from_unixtime('<Some Timestamp>'));
而存储过程如下
CREATE DEFINER=`root`@`%` PROCEDURE `getchatmessages`(IN `__ChatID` CHAR(36), IN `__UserID` CHAR(36), IN `__Timestamp` TIMESTAMP(6))
BEGIN
DECLARE `__NewChatMessages` TINYINT(1) DEFAULT 0;
DECLARE `__i` INT(11) DEFAULT 0;
DECLARE `__Interval` INT(11) DEFAULT 100; -- ms
DECLARE `__Timeout` INT(11) DEFAULT 15000; -- ms
while `__NewChatMessages`=0 and `__i`<`__Timeout`/`__Interval` do
select 1 into `__NewChatMessages` from `chatmessages` where `ChatID`=`__ChatID` and `DateTimeAdded`>ifnull(`__Timestamp`,0) limit 1;
update `chatusers` set `DateTimeRead`=now(6) where `ChatID`=`__ChatID` and `UserID`=`__UserID`;
do sleep(`__Interval`/1000);
set `__i`=`__i`+1;
end while;
select `chatmessages`.`Body`, `chatmessages`.`ChatID`, `chatmessages`.`UserID`,
`chatmessages`.`ChatMessageID`, `chatmessages`.`DateTimeAdded`, UNIX_TIMESTAMP(`chatmessages`.`DateTimeAdded`) `Timestamp`, `users`.`FirstName`,
`users`.`LastName`
from `chatmessages`
join `users` using (`UserID`)
where `chatmessages`.`ChatID`=`__ChatID`
and `chatmessages`.`DateTimeAdded`>ifnull(`__Timestamp`,0)
order by `chatmessages`.`DateTimeAdded` desc
limit 100;
END
Galera 集群(MariaDB Galera 集群,3 个节点)中的死锁不是典型的死锁,而是多主冲突的一种通信方式:
http://galeracluster.com/documentation-webpages/dealingwithmultimasterconflicts.html
避免死锁的最简单方法是一次写入1个节点,即配置HA代理只写入1个节点。在您的情况下,您将在 Node1 上 运行 sp(与哪个节点无关,但始终在 1 个节点上,有点 "sticky sessions")。
这个Proc是在事务内部调用的吗?如果是这样,我强烈反对它的设计。你有一个循环,睡眠挂在事务上。
相反,UPDATE
本身就是一个事务。
这实际上可以消除死锁。但是,正如其他答案所讨论的那样,您仍然应该处理死锁。
Edit 由于没有 BEGINs
和 autocommit=ON
,OP 已经遵循了这个建议。唉。