‣ ‣ ‣ ‣

背景

撕逼星球的plantegg老师提供了一个案例,大体上是阿里云的 sysbench 在压测mysql的时候在mysql 侧kill链接,发现sysbench没有重连QPS始终为0,而某些版本的sysbench则没有问题。

不符合预期的场景

Untitled

符合预期的场景

Untitled

在符合预期的场景中我们发现重连成功。QPS恢复。

差异分析

在之前的文章中定位到大体上是因为依赖的问题造成的,异常的版本本 libmysqlclient_18 正常的版本是 libmysqlclient_21。

两者在接口上大部分传参一直,双方也有各自特有的API 例如 mariadb_reconnect (mariadb独占),mysql_get_ssl_session_reused(mysql 独占) 具体API差异可以查看后边的API文档。

mariadb

sysbench 在重连处的逻辑如下

//sysbench/src/drivers/mysql/drv_mysql.c
static int mysql_drv_reconnect(db_conn_t *sb_con)
{
  db_mysql_conn_t *db_mysql_con = (db_mysql_conn_t *) sb_con->ptr;
  MYSQL *con = db_mysql_con->mysql;
  // 注意这里做了close()
  // 这个函数是libmysqlclient 动态库中提供的函数
  mysql_close(con);
	// 这里调用了自己的函数,返回值是 != 1 就一直循环
  while (mysql_drv_real_connect(db_mysql_con))
  {
    if (sb_globals.error)
      return DB_ERROR_FATAL;

    usleep(1000);
  }
	// 返回了这个表示DB链接又可以使用了,直接用原来的 connection就行。
  return DB_ERROR_IGNORABLE;
}

static int mysql_drv_real_connect(db_mysql_conn_t *db_mysql_con)
{
  MYSQL          *con = db_mysql_con->mysql;
	... 省略了部分代码
	// 这里又调用了 libmysqlclient 中提供的库。
  return mysql_real_connect(con,
                            db_mysql_con->host,
                            db_mysql_con->user,
                            db_mysql_con->password,
                            db_mysql_con->db,
                            db_mysql_con->port,
                            db_mysql_con->socket,
                            CLIENT_MULTI_STATEMENTS
                            ) == NULL;
}

libmysqlclient_18 mysql_close 中的逻辑如下

//mariadb-connector-c/libmariadb/mariadb_lib.c
void STDCALL
mysql_close(MYSQL *mysql)
{
  if (mysql)					/* Some simple safety */
  {

		...省略若干
		// 注意这里
    if (mysql->net.extension)
      free(mysql->net.extension);

    if (mysql->extension)
      free(mysql->extension);

    // 注意这里
    mysql->net.extension = NULL;
    mysql->extension = NULL;

    mysql->net.pvio= 0;
    if (mysql->free_me)
      free(mysql);
  }
  return;
}