【 TiDB 使用环境】生产环境
【 TiDB 版本】4.0.13
【遇到的问题】并发查询数据透传问题
【复现路径】就一个简单的inner join查询
【问题现象及影响】生产级大bug
一个select where id=* 条件的查询,在并发情况下查询条件和最终得到的结果是混乱的
比如接口并发多人在请求这个查询 where id=111这一个请求返回的理应是id=111的数据,现在问题是请求id=111的查询,返回的结果有可能是另一个请求id=222 所返回的数据,就是查id=111得到了同时另一个请求id=222的数据
以下详细介绍触发这个bug的流程
先上一段代码这是我复现问题的测试代码,下面去掉了很多没必要的代码
golang写的
“github.com/go-sql-driver/mysql” 数据库连接驱动器
sql Prepare 预处理查询
触发这个问题的条件之一就是下面这段sql用到了 inner join ,去掉inner join关联表就不会有这个问题
users表有两千多万数据,另一个表只有几十条数据
数据表是这样的结构
users表
Id | other |
---|---|
111 | …. |
222 | …. |
userORDER表
tid | disabled | other |
---|---|---|
111 | 1 | …. |
222 | 1 | … |
stmt, err := db.Prepare(SELECT u.id FROM users as u inner join userOrder as o on u.id=o.tid WHERE u.id = (?) and o.disabled=1)
userID := []string{"111", "222"}
for i := 0; i < 60; i++ {//60个并发去查询userID里的两个数据
go func(b int) {
queryID := userID[b%2]
rows, err := stmt.Query(queryID)
var users []Users
for rows.Next() {
var u user
rows.Scan(&u.id)
//验证这个bug
if u.id != queryID {
//这里的不等于条件会成功,查询的id=queryID 那么我得到的c.id也应该是queryID 他们是相等的才对
fmt.Println(queryID, u.id, "----")
}
users = append(users, u)
}
}(i)
}
return
原来怀疑是我代码问题,后面结果各种排查无果,就用 WireShark抓了下包,发现{“111”, “222”}这两个数据的确各发了30次请求,查看Response神奇的事情发生了, 发现上面查询 111结果返回了29次,222返回了31次
所以就发生了上面那个现象,当查询id=1111 得到了一次 id=222的数据,下面有抓包截图
补充说明下,我重新申请了一套服务器另外搭了一套全新的集群版本拓扑图和数据都一样,没重现出这个问题
【附件】
- TiUP Cluster Display 信息