首页 > 其他分享 >自增锁引发的悲剧

自增锁引发的悲剧

时间:2024-01-23 15:07:06浏览次数:29  
标签:insert 自增锁 rx lc lock 引发 悲剧 mode inc

背景

先描述下故障吧

  • step0: 环境介绍
1. MySQL5.6.27
2. InnoDB
3. Centos

基本介绍完毕,应该跟大部分公司的实例一样

CREATETABLE`new_table`(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `x` varchar(200) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5908151 DEFAULT CHARSET=utf8 



CREATE TABLE `old_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `xx` varchar(200) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5908151 DEFAULT CHARSET=utf8
  • step1: 业务需要导入历史数据到新表,新表有写入
1. insertintonew_table(x)selectxxfromold_table

2. 批量插入在new_table上
  • step2: 结果
showprocesslist;

看到好多语句都处于executing阶段,DB假死,任何语句都非常慢,too many connection
  • step3: 查看innoDB状况
showengineinnodbstatu\G

结果:

==lock==
---TRANSACTION 7509250, ACTIVE 0 sec setting auto-inc lock --一堆
TABLE LOCK table `xx`.`y'y` trx id 7498948 lock mode AUTO-INC waiting  --一堆

模拟问题,场景复现

让问题再次发生才好定位解决问题

  • 表结构
| t_inc | CREATETABLE`t_inc`(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `x` varchar(199) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5908151 DEFAULT CHARSET=utf8 |


CREATE TABLE `t_inc_template` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `cookie_unique` varchar(255) NOT NULL DEFAULT '' COMMENT '',
    PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=5857489 DEFAULT CHARSET=utf8
  • step1
session1:insertintot_inc(x)selectcookie_uniquefromt_inc_template;


session2:mysqlslap -hxx -ulc_rx -plc_rx -P3306  --concurrency=10 --iterations=1000 --create-schema='lc' --query="insert into t_inc(x) select 'lanchun';" --number-of-queries=10

产生并发,然其自动分配自增id。
  • step2:观察
| 260126 | lc_rx       | x:22833 | NULL | Sleep   |       8 |                                                        | NULL                                                          |
| 260127 | lc_rx       | x:22834 | lc   | Query   |       8 | executing                                              | insertintot_inc(x)select'lanchun'|
| 260128 | lc_rx       | x:22835 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260129 | lc_rx       | x:22836 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260130 | lc_rx       | x:22837 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260131 | lc_rx       | x:22838 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260132 | lc_rx       | x:22840 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260133 | lc_rx       | x:22839 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260134 | lc_rx       | x:22842 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260135 | lc_rx       | x:22841 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
| 260136 | lc_rx       | x:22843 | lc   | Query   |       8 | executing                                              | insert into t_inc(x) select 'lanchun'                         |
  • step3 show engine innodb status
TABLE LOCKtable`lc`.`t_inc`trx id113776506lockmodeAUTO-INC waiting

一堆这样的waiting

然后卡死

好了问题已经复现,大概也知道是什么原因造成了,那就是:AUTO-INC lock

自增锁

接下来聊聊自增锁

和auto_increment相关的insert种类

  1. INSERT-like
解释:任何会产生新记录的语句,都叫上INSERT-like,比如:

 INSERT, INSERT ... SELECT, REPLACE, REPLACE ... SELECT, and LOAD DATA
 
 
总之包括:“simple-inserts”, “bulk-inserts”, and “mixed-mode” inserts.
  1. simple insert
插入的记录行数是确定的:比如:insert into values,replace
但是不包括: INSERT ... ON DUPLICATE KEY UPDATE.
  1. Bulk inserts
插入的记录行数不能马上确定的,比如: INSERT ... SELECT, REPLACE ... SELECT, and LOAD DATA
  1. Mixed-mode inserts
这些都是simple-insert,但是部分auto increment值给定或者不给定

1. INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

2. INSERT...ONDUPLICATEKEYUPDATE

以上都是Mixed-mode inserts

锁模式

  1. innodb_autoinc_lock_mode = 0 (“traditional” lock mode)
优点:极其安全

缺点:对于这种模式,写入性能最差,因为任何一种insert-like语句,都会产生一个table-levelAUTO-INClock
  1. innodb_autoinc_lock_mode = 1 (“consecutive” lock mode)
原理:这是默认锁模式,当发生bulk inserts的时候,会产生一个特殊的AUTO-INC table-level lock直到语句结束,注意:(这里是语句结束就释放锁,并不是事务结束哦,因为一个事务可能包含很多语句)

对于Simple inserts,则使用的是一种轻量级锁,只要获取了相应的auto increment就释放锁,并不会等到语句结束。

PS:当发生AUTO-INC table-level lock的时候,这种轻量级的锁也不会加锁成功,会等待。。。。

优点:非常安全,性能与innodb_autoinc_lock_mode = 0相比要好很多。

缺点:还是会产生表级别的自增锁

深入思考: 为什么这个模式要产生表级别的锁呢?
因为:他要保证bulk insert自增id的连续性,防止在bulk insert的时候,被其他的insert语句抢走auto increment值。
  1. innodb_autoinc_lock_mode = 2 (“interleaved” lock mode)
原理:当进行bulk insert的时候,不会产生table级别的自增锁,因为它是允许其他insert插入的。

来一个记录,插入分配一个auto 值,不会预分配。

优点:性能非常好,提高并发,SBR不安全
缺点:
    一条bulk insert,得到的自增id可能不连续
    SBR模式下:会导致复制出错,不一致

延伸

当innodb_autoinc_lock_mode = 2 ,SBR为什么不安全

  • master 插入逻辑和结果

表结构:a primary key auto_increment,b varchar(3)

time_logic_clock

session1:bulk insert()

session2: insert like

0

1,A

 

 

1

 

2,AA

2

3,B

 

 

3

4,C

 

 

4

 

5,CC

5

6,D

 

最终的结果是:

a

b

1

A

2

AA

3

B

4

C

5

CC

6

D

  • slave的最终结果

因为binlog中session2的语句先执行完,导致结果为

a

b

1

AA

2

CC

3

A

4

B

5

C

6

D

RBR为什么就安全呢?

因为RBR都是根据row image来的,跟语句没关系的。

好了,通过以上对比分析,相信大家都知道该如何抉择了吧?

总结

  • 如果你的binlog-format是row模式,而且不关心一条bulk-insert的auto值连续(一般不用关心),那么设置innodb_autoinc_lock_mode = 2 可以提高更好的写入性能。



标签:insert,自增锁,rx,lc,lock,引发,悲剧,mode,inc
From: https://blog.51cto.com/u_16532032/9379957

相关文章

  • 2024年世界经济论坛年会,人工智能议题引发热议
    2024年1月15日至19日,瑞士达沃斯举办了第54届世界经济论坛年会。此次论坛汇聚了来自120个国家的2800多位各界领导者,共同探讨和推动国际合作,围绕“重建信任”这一主题讨论经济增长、气候与自然行动、能源安全、技术治理和人类发展等重要议题。论坛设置了包括世界安全合作、创造就业机......
  • APPLICATION_FORM_URLENCODED_VALUE引发的no suitable HttpMessageConverter found fo
     轻松解决feign.codec.EncodeException:Couldnotwriterequest:nosuitableHttpMessageConverterfoundfor 问题:使用feignclient访问其他服务时,报错:feign.codec.EncodeException:Couldnotwriterequest:nosuitableHttpMessageConverterfoundforrequesttype......
  • select count(*) 引发的思考
    1、属性上添加注解:@JsonIgnoreimportcom.fasterxml.jackson.annotation.JsonIgnore;@JsonIgnore@ApiModelProperty("属性")privateLongsqlTotal;privateinttotal;针对Long类型,接口返回时,会转化为字符串,这样做是因为怕前端解析时出现精度问题......
  • 记一次缓存失效引发的惨案!
    对于小猫来讲,最近的一段日子是不好过的,纵使听着再有节拍的音乐,也换不起他对生活的热情。由于上一次“幂等事件”躺枪,他已经有几天没有休息好了。他感觉人生到了低谷。当接手这个商城项目之后,他感觉他一直没有好过。他的内心彷徨,在工位上边写着事故报告,边嘀咕着“今年到底是犯了啥......
  • 2024年世界经济论坛年会,人工智能议题引发热议
    2024年1月15日至19日,瑞士达沃斯举办了第54届世界经济论坛年会。此次论坛汇聚了来自120个国家的2800多位各界领导者,共同探讨和推动国际合作,围绕“重建信任”这一主题讨论经济增长、气候与自然行动、能源安全、技术治理和人类发展等重要议题。论坛设置了包括世界安全合作、创造就业......
  • 2024年世界经济论坛年会,人工智能议题引发热议
    2024年1月15日至19日,瑞士达沃斯举办了第54届世界经济论坛年会。此次论坛汇聚了来自120个国家的2800多位各界领导者,共同探讨和推动国际合作,围绕“重建信任”这一主题讨论经济增长、气候与自然行动、能源安全、技术治理和人类发展等重要议题。论坛设置了包括世界安全合作、创造就业机......
  • 新火种AI|程前怼大佬引发闹剧,但更值得关注的,是大佬的AI观点
    作者:小岩编辑:彩云在2024年开年的一场演讲大会中,知名网红程前直接炮轰了大佬周鸿祎。事件快速发酵,引起了全网的热烈讨论。很多人都在吐槽程前的情商有多低,大佬有多真性情,却全然忘记了周鸿祎此次参会的演讲内容——《2024AI发展的10大趋势》。事实上,相较于八卦,演讲中的内容才是最值......
  • 【小记】BITMAP To BMP 调用 GetDIBits 引发栈内存损坏问题
    BITMAPbitmap;if(!GetObject(hBitmap,sizeof(bitmap),&bitmap)){//外部传入hBitmapreturnfalse;}//创建位图信息头BITMAPINFObitInfo;BITMAPINFOHEADER&bi=bitInfo.bmiHeader;bi.biWidth=bitmap.bmWidth;bi.biHeight=bitmap.bmHeight;bi.biPlane......
  • 关于落户和过年回家引发的焦虑感
    今天在和爸妈讨论在深圳过年很无聊的事情,引发了我的一波焦虑。之前总是听别人说这种焦虑感,这次自己体会到这种感觉,真的很不是滋味。回家的成本计算:单程详情开车:1800km*0.6=1080(燃油费)+1000(过路费)=2080¥,最少24H,还要不间断的连续开,火车:440*4=1760¥,小孩奶瓶,32h飞机:1600*4=64......
  • [转帖]解Bug之路-NAT引发的性能瓶颈
    https://zhuanlan.zhihu.com/p/286532997 解Bug之路-NAT引发的性能瓶颈笔者最近解决了一个非常曲折的问题,从抓包开始一路排查到不同内核版本间的细微差异,最后才完美解释了所有的现象。在这里将整个过程写成博文记录下来,希望能够对读者有所帮助。(篇幅可能会有点长,耐心......