记录线上一次死锁问题

116 阅读2分钟

发生时间:2022年8月10日 19:17:57

事务 1事务 2(已回滚)
Session ID727939584727941241
Thread id62314226231449
请求类型updateupdate
事务ID133197651133197662
涉及表dev.t_tabledev.t_table
等待锁index PRIMARY of table dev.t_table trx id 133197651 lock_mode X locks gap before rec insert intention waitingindex PRIMARY of table dev.t_table trx id 133197662 lock_mode X locks gap before rec insert intention waiting
等待锁索引名PRIMARYPRIMARY
等待锁类型X locks gap before rec insert intention waitingX locks gap before rec insert intention waiting
持有锁index PRIMARY of table dev.t_table trx id 133197651 lock mode S locks gap before recindex PRIMARY of table dev.t_table trx id 133197662 lock mode S locks gap before rec
持有锁索引名PRIMARYPRIMARY
持有锁类型S locks gap before recS locks gap before rec
事务SQLINSERT INTO dev.t_table ( id,create_time ) VALUES('AC1881EE00064CD1716D41DD1D7A3795', '2022-09-13 19:17:22.788')INSERT INTO dev.t_table ( id,create_time ) VALUES('AC1881EE00064CD1716D41DD1D7A3795', '2022-09-13 19:17:40.352')

表作用:是为了防止重复消费的,一条消息发到mq,消费者这边有可能会消费多次这条消息,消费前,用messageId做主键往这张表中插入,如果插入成功,说明这条消息没有被消费,就开始消费,如果没插入成功,说明之前消费过,就不会再消费了。

分析死锁原因:

  • MQ发了两次, 两个相同的消息ID
  • 第一个没提交,长时间没消费成功,事务回滚,消费失败,返回消息给mq服务端,短时间内会再次拉取这条消息消费,也就是重试了
  • 第一个没有执行完事务, 第二个重试的都已经来了
  • 二十几秒,第一个事务还没提交
  • 插入t_unique_message,之后的事务执行时间太久,导致锁释放不掉
  • mq的messageId,就是一种uuid,就是看起来有点顺序而已,也是不重复的字符串
  • 该锁是独占锁(X):独占锁:指该锁一次只能被一个线程所持有。对于ReentrantLock和Synchronized而言都是独占锁。共享锁:该锁可以被多个线程所持有。对于ReentrantReadWriteLock来说,其读锁是共享锁,写锁是独占锁。读锁的共享锁可保证并发读是非常高效的,读写,写读,读读的过程是互斥的。

分析死锁日志