前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用golang编写的pt-fingerprint

使用golang编写的pt-fingerprint

原创
作者头像
保持热爱奔赴山海
修改2024-05-03 19:49:08
920
修改2024-05-03 19:49:08
举报
文章被收录于专栏:饮水机管理员饮水机管理员

上一篇中,提到了使用pt-fingerprint来做sql指纹采集,实际发布到生产环境后,发现有些问题。

1、处理的sql如何用到了反引号,则会报错,例如:

代码语言:txt
复制
pt-fingerprint --query "SELECT id,`group`,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num  FROM sbt1 WHERE id=19765"

zsh: command not found: group
select id,,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num from sbt1 where id=?

2、性能不太给力,每次执行需要0.03s到0.04秒

试了下小米的soar,sql指纹采集的性能也不给力。

找了挺久,发现percona这篇博客,使用golang重写的sql指纹采集(除此之外,还带有日志分析的功能)

因为percona提供的是package的方式,如果需要打包成程序,还需要写点代码 ,下面简单记录下编译方法:

编译方法

代码语言:bash
复制
假设GOPATH路径为:/home/gocode/


cd /home/gocode
cd src
mkdir github.com
cd github.com 

git clone https://github.com/percona/go-mysql.git
cd go-mysql 

git checkout master
go mod init
go mod tidy
go mod vendor

make install

# 切换到query目录下
cd query


新建 main.go 文件,内容如下:
package main

import (
	"fmt"
	"os"
	"github.com/percona/go-mysql/query"
)

func main() {
	// 仅从命令行参数读取查询语句,如果没有提供,则报错退出
	if len(os.Args) <= 1 {
		fmt.Println("Error: Query string not provided.")
		os.Exit(1)
	}
	q := os.Args[1]
	f := query.Fingerprint(q)
	fmt.Println(f)
}


# 测试
go run main.go 'update sbt1 set sex ="M" where id between 1 and 100 and age !=12  limit 10 '


# 打包
go build main.go

# 列出文件
# root @ localhost in /home/gocode/src/github.com/go-mysql/query
$ ll
total 1.9M
-rw-r--r-- 1 root root 1.8K 2024-04-28 13:52 doc_test.go
-rw-r--r-- 1 root root  24K 2024-04-28 13:52 query.go
-rw-r--r-- 1 root root  19K 2024-04-28 13:52 query_test.go
-rw-r--r-- 1 root root  367 2024-04-28 13:55 main.go
-rwxr-xr-x 1 root root 1.9M 2024-04-28 13:55 main   --> 生成的可执行的二进制文件

# 还可以移动到/bin目录下
cp main /bin/go-pt-fingerprint

性能对比

代码语言:txt
复制
import time
import subprocess

sql="""
EXPLAIN SELECT  id,tag_id,tag_name,group_id,group_name,agent_id,create_user,create_time,update_user,update_time  FROM sbt1 
 WHERE (tag_id = '1111111111' AND del_flag = 0)
"""

s1=time.time()
for i in range(10000):
    cmd = subprocess.Popen(
        r"go-pt-fingerprint "
        + '"'
        + str(sql).replace("`", "").replace('"', "'")
        + '"',
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
print("go版本 ",time.time()- s1)


s2=time.time()
for i in range(10000):
    cmd = subprocess.Popen(
        r"pt-fingerprint --query " 
        + '"' 
        + str(sql).replace("`", "").replace('"', "'") 
        + '"',
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
print("perl版本 ",time.time()- s2)

结论:

go版本 8.751 秒

perl版本 44.137秒

golang版本的pt-fingerprint性能是perl版本的5倍左右。

遇到的问题

代码语言:txt
复制
如果 sql里面有反引号,  pt-fingerprint 执行会遇到异常,如下:
$ pt-fingerprint --query "SELECT id,`group`,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num  FROM sbt1 WHERE id=19765"
zsh: command not found: group
select id,,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num from sbt1 where id=?

经测试,go版本的也存在这种问题
$ ./main "SELECT id,`limit`,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num  FROM sbt1 WHERE name between '2023-02-01' and '2023-05-01' and sex='M' order by id desc limit 100,20 "         
select id,cputime unlimited filesize unlimited datasize unlimited stacksize 8mb coredumpsize 0kb memoryuse unlimited maxproc ? descriptors ? memorylocked 8mb addressspace unlimited maxfilelocks unlimited sigpending ? msgqueue ? nice ? rt_priority ? rt_time unlimited,shop_id,org_name,pid,is_show,org_level,root_id,path,agent_num from sbt1 where name between ? and ? and sex=? order by id desc limit ?,?


解决办法:
在使用前,先处理一次,使用replace将反引号去掉

对于sql归一化,业内还有很多工具,例如:

1、tidb sql parser

2、jsqlparser

3、druid ,示例可以参考这篇

考虑到java启动比较慢,推荐使用文本的percona方案或者tidb的方案。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编译方法
  • 性能对比
  • 遇到的问题
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com