TiDB 性能测试最佳实践

【是否原创】是
【首发渠道】TiDB 社区
【首发渠道链接】其他平台首发请附上对应链接
【目录】
【正文】

一、前言

TiDB 作为 New SQL 数据库的代表,其在高性能,高可拓展性,高可用性等方面表现尤为突出。TiDB 也凭借这些特性获得越来越多客户的使用。在数据库选型过程中使用专业的软件得出可靠的数据往往比数据库厂商各自标榜的性能指标要来的更真实更有说服力。本篇文章就简单谈谈使用 Sysbench,PProf 这些测试工具测试 TiDB 的方法。

二、Sysbench测试

SysBench 是一个基于 LuaJIT 的可编写多线程基准测试工具。它最常用于数据库基准测试,但也可用于创建不涉及数据库服务器的任意复杂工作负载。Sysbench 提供十分方便的安装方式。Sysbench 在Github 的地址:https://github.com/akopytov/sysbench。在README中指明,通过二进制包安装,只需要两行命令。例如 Debian/Ubuntu:

curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench

上面简单介绍了 Sysbench 的安装。那么在安装完成之后,在 /usr/share/sysbench/ 下会有一些脚本文件。这些 lua 脚本就是 Sysbench自身提供的测试脚本。根据脚本的名称可以简单推测一下它们的作用。bulk_insert.lua 这个脚本是测试大批量插入时的性能表现。oltp_delete.lua 是测试数据库删除数据的能力。总的来说,Sysbench 本身自带的测试脚本涵盖数据库插入、删除、读写、只读、只写等常见性能测试场景,使用这些自带脚本测试可以初步的判断一个数据库性能的大致水平。

那么接下来就是使用 Sysbench 对数据库进行性能测试。按照 Sysbench 规定的语法,调用不同的脚本对 TiDB 进行性能测试。Sysbench 规定的语法很简单,一般都是 Sysbench 然后后面跟上键值对形式的参数说明,比如:–tables=10 指明测试将创建10张表。

当你想调用自带脚本时,只需要在 Sysbench 命令后指定脚本的简称即可,比如 Sysbench oltp_delete … 将运行删除的性能测试。也可以指定脚本的路径,比如 Sysbench /usr/share/sysbench/oltp_delete … 这条语句与上面提到的命令效果相同。

然后就是数据库连接相关的配置。它有两种配置方式,一种直接以键值对参数的形式写在 Sysbench 命令后面。比如 sysbench … --mysql-host=127.0.0.1 指定测试主机位于 127.0.0.1 的 mysql 数据库。这种方式直接暴露数据库连接信息,尤其是密码也会明文显示。这样做不太安全。还有另外一种方式就是将数据库连接信息写进配置文件,然后使用 --config-file 指定配置文件路径。

配置文件内容示例:

mysql-host=127.0.0.1
mysql-port=4000
mysql-user=root
mysql-password=
mysql-db=test
db-driver=mysql

除了连接信息可以写在配置文件中,与数据库压测指标相关的配置也可以写进去。比如 table-size=1000。

讲完基本使用方式,下面是一些示例命令:

sysbench oltp_read_write --config-file=tidb-config --tables=20 --table-size=100000  --report-interval=10 --threads=100  --time=100  prepare

sysbench oltp_read_write --config-file=tidb-config --tables=20 --table-size=100000  --report-interval=10 --threads=100  --time=100  run

sysbench oltp_read_write --config-file=tidb-config --tables=20 --table-size=100000  --report-interval=10 --threads=100  --time=100  cleanup

标准的调用方式分为单个三个阶段,prepare(创建表,索引,准备数据)、run(运行测试)、cleanup(删除测试数据,保持工作空间干净)上面的命令指定测试数据库读写能力,数据库连接信息通过 tidb-config 配置文件获取。指定创建 20 张表。每张表10w行数据。运行时每10秒报告一次实时性能情况。并发访问的线程数有100个。总运行时100秒。

在 Sysbench 测试过程中,如果所设参数导致的数据量过大,测试的 TiDB 压力过大,那么测试的等待过程将十分漫长。我们可以编写自动化测试 shell 脚本,将过程中产生的测试结果保存到文本中。等待测试完成,文本中将会保存测试时的结果。这种方式适用于在数据库压力测试或者要同时对数据库读写,删除,插入等多方面性能进行测试的情况。保存中间测试结果是 run 阶段的结果。使用追加写入文本的命令保存中间测试结果:

sysbench oltp_read_write .....   run  >> result.log

上文所说是使用 Sysbench 自带测试脚本进行测试的内容。但是在实际测试需求中,我们面对的应用场景往往比较复杂。对于定制化的环境,我们需要对定制化的环境中常见的业务场景所产生的 sql 进行测试。这往往比使用自带的脚本测试数据更加有说服力。那么接下来就简单说说自定义 Sysbench 测试脚本的基本思路以及简单实现,

sysbench测试脚本使用 lua 语言编写。如果要让 sysbench 能够使用我们自己编写的脚本进行测试,首先需要实现 Sysbench API 所要求的几个核心函数:thread_init,thread_done, 和event。

以下代码就是一个简单自定义脚本示例:

function thread_init(thread_id)
db_connect()
end
 
function event(thread_id)
local table_name = "t1"
db_query("begin")
    
-- 在 lua 中代表注释
-- 点查
db_query("SELECT name FROM "..table_name.." WHERE id = "..math.random(100000))

db_query("commit")
end

sysbench 运行该脚本时,首先进到 thread_init 方法,进行初始化工作。从具体代码来看,初始化阶段主要是做了连接到数据库的工作。

第二点,根据 sysbench 命令行中指定行为 (prepare, run, cleanup) 进到不同函数进行操作。上面代码只实现了 event 函数,也就是说,运行该脚本只有 run 这个选项。

使用如下命令运行脚本:

sysbench test.lua --config-file=tidb-config --threads=200 --report-interval=5  --time=120 run

三、PProf 测试

PProf 是成熟的测试工具 Profiling 的 go 实现。内置的 CPU, Mem, Block Profiler,可以跟踪程序在运行中的方法调用栈,并统计相关的资源开销和时间消耗,极大程度上帮助我们进行性能测试和瓶颈定位。

TiDB 是使用 Go 编写的项目,我们可以使用 PProf 对其进行性能测试。

在程序中引入 net/http/pprof 包,然后在主程序的最前面加上调用语句,只需要一句就可以启动 PProf,可以看出使用起来是非常方便的。

import (
    "net/http"
    _ "net/http/pprof"
)
 
 
func main(){
    go func() {
       fmt.Println(http.ListenAndServe("0.0.0.0:8005", nil))
    }()
 
 
    // 下面写正常的业务代码
    ......
}

启动程序后,可以直接访问:http://host:8005/debug/pprof/ 来查看

其中有很多的子文件可以打开:

allocs : 过去所有内存分配的样本

block : 导致同步原语阻塞的堆栈跟踪

cmdline : 当前程序的命令行调用

goroutine : 当前所有 goroutine 的堆栈跟踪

heap : 活动对象的内存分配抽样,可以指定 gc Get 参数,以便在获取堆样本之前运行 gc

mutex : 互斥锁竞争者的堆栈跟踪

profile : CPU配置文件。您可以在seconds GET参数中指定持续时间,获取配置文件后,使用go tool pprof命令来调查概要文件。

threadcreate : 导致创建新OS线程的堆栈跟踪

trace : 跟踪当前程序的执行。您可以在seconds GET参数中指定持续时间。获取跟踪文件后,使用go tool trace命令来调查跟踪。

使用交互式命令行查看

go tool pprof http://host:8005/debug/pprof/profile?seconds=60

执行该命令后等待 60s 即可进入到交互式命令模式(后面的 profile 可以换成其他的参数,例如 heap,mutex 等等)

进入交互式命令模式后可以输入一系列指令进行详细的记录查看,例如 Top10 查看耗时最长的前10个记录,其余的指令可以通过 pprof help 来查看详情

flat : 给定函数上的运行耗时

flat% : 同上的CPU运行耗时的总比例

sum% : 给定函数累计使用 CPU 总比例

cum ; 当前函数加上它之上的调用运行总耗时

cum% : 同上的CPU运行耗时总比例

最后一列 : 函数名

通过 web 指令查看可视化界面

如果想要查看图形化界面,则需要安装 Graphviz

sudo apt-get install graphviz

安装 Graphviz后,在交互命令行中输入 web 即可,可以通过可视化图形来查看方法之间的调用关系和每一个方法的资源开销与时耗

使用 go-torch 工具生成火焰图

go-torch 是 uber 开源的一个工具,可以直接读取 pprof 的 profiling 数据,生成一个火焰图 svg 的文件,通过浏览器即可打开,查看整个火焰图(该图为可交互的)

地址:GitHub - uber-archive/go-torch: Stochastic flame graph profiler for Go programs

安装 go-torch 和 FlameGraph

go get github.com/uber/go-torch

cd $GOPATH/src/github.com/uber/go-torch

git clone https://github.com/brendangregg/FlameGraph.git

cp FlameGraph/flamegraph.pl /usr/local/bin

使用 go-torch 生成 svg 文件

go-torch 的具体指令可以通过 go-torch -h 来查看

go-torch -u http://host:8005 -t 60 -f cpu.svg

-u 指定相关 url 当没有后缀的时候 默认为 http://localhost:8080/debug/pprof/profile

-t 指定监控的时间为 60s

-f 指定文件名,当前目录下生成 cpu.svg

查看火焰图

当生成 svg 文件后,我们可以直接将其用浏览器打开

火焰图调用顺序从下往上,宽度代表其占用的时间,由于火焰图是可交互的,可以用鼠标点击每一个小方块进去看其具体的信息和其内部函数的调用

四、总结

上面大致介绍了两种性能测试工具。一个是 Sysbench,它的应用场景主要是测试数据库的各方面性能的指标数据。比如读写,插入,删除这些方面的QPS,TPS,最大最小时延,平均时延等重要指标。这样得出的数据具有说服力。在保持 sysbench 测试参数一致,数据库部署环境一致的情况下,同时对 TiDB, MySQL,PostgreSQL等数据库进行测试,得出的数据可以作为不同数据库性能高低的重要评价指标。另外一个是 PProf。这个工具可以具体查看到 TiDB 执行命令时的堆栈调用以及耗时情况。它可以帮助我们在进行 TiDB 性能调优的过程中,发现异常耗时的程序段,精确定位问题代码,快速解决性能异常问题。熟练使用 TiDB 性能测试工具将帮助我们极大地提升 TiDB 相关开发任务地效率。

2赞

棒棒棒