Month: 五月 2015

hanldersocket 167错误的原因

用HandlerSocket大量并发插入数据到多个InnoDB的表(都使用自增id)的时候就会大量出现167的错误,从而TPS下降极为厉害.

让我们来分析这个bug是怎么产生的.

 

我们先来重现这个bug:

先建两个表:

 

然后用HandlerSocket大并发的执行类似这样SQL的命令:

 

那么很快就会出现167的错误

那我们来看看167是什么意思, 167是

 

返回的错误码,即

 

表示已经越界了

查看可能返回HA_ERR_AUTOINC_ERANGE的地方,就在int handler::update_auto_increment()这个方法里,当

 

时,会有问题

而什么时候nr会等于ULONGLONG_MAX呢,看上面的代码

 

在nr= compute_next_insert_id(nr-1, variables); 这一步会导致nr等于ULONGLONG_MAX

那么在get_auto_increment()这步的时候nr返回就必须是0,而nr传进去的时候就是0

那么就是get_auto_increment()没有起效果

我们再看InnoDB的get_auto_increment()实现

 

能导致first_value不改变的请求只有

 

这3个判断都没有满足

而HandlerSocket再并发插入多表时确实可能导致3个条件都不满足.

为什么呢,在于trx->n_autoinc_rows和prebuilt->autoinc_last_value这两个变量

由于新的InnoDB自增id的策略,在多行插入的时候为了减少自增id的锁堵塞,所以会一次生成一个大于auto_increment_offset跨度的id序列,trx->n_autoinc_rows表示就是这个序列的大小

prebuilt->autoinc_last_value表示的是这个表的这个序列的最后一个值

1.第一个条件不满足

大家注意到了n_autoinc_rows是在trx上的,autoinc_last_value是在prebuilt上的,trx又是在THD上的.这就导致多表自增的时候一个表生成的n_autoinc_rows,可能会作用于两个表上.

比如nb_desired_values=2而实际只插入了一条记录,那么循环后trx->n_autoinc_rows = 1 那么换成另一个表的时候后trx->n_autoinc_rows = 1,那么第一个条件就不满足.

2.第二个条件不满足

而第二个条件,即当第二个表也有自增过之后

 

prebuilt->autoinc_last_value必然是大于0的,就是有错误,*first_value=0 最后prebuilt->autoinc_last_value也会等于1,那么这个时候第二个条件也会不满足!

3.第三个条件不满足

而当*first_value=0 时,第三个条件自然也是满足不了的.

所以最后就导致update_auto_increment()返回了167错误~

解决办法:

1.设置innodb_autoinc_lock_mode=0 是InnoDB采用老式的自增id分配算法可以避免这种请求

2.修改HandlerSocket代码,在dbcontext::cmd_insert_internal()的const int r = hnd->ha_write_row(buf)之前加上hnd->start_stmt(thd,TL_WRITE)对trx->n_autoinc_rows进行重置来避免这个问题

多个python环境安装pip

 

python使用nsq简单示例

启动服务:

安装python依赖包

 

编写生产者:nsq.create.py

 

编写消费者:nsq.consume.py

 

测试:

 

osx搭建nsq环境

启动服务:

启动消费者:(接收消息)

 

启动生产者(发送消息)

 

观察结果:

监控nsq:

http://127.0.0.1:4171/