想法來源
平時(shí)都會(huì)遇到一個(gè)問題就是不知道怎么做數(shù)據(jù)庫(kù)自己的 PPE学辱,但是業(yè)務(wù)又天天有問題乃戈,還無法知道如何提前預(yù)判脯宿,DBA 是不是很累,業(yè)務(wù)是不是很慘兼搏,是不是應(yīng)該思考如何解決這個(gè)問題卵慰。(一堆沒用的廢話,堅(jiān)持 DBA 需要強(qiáng)研發(fā)能力佛呻,而不是簡(jiǎn)單的腳本)
解題思路
云上托管 MySQL (RDS)裳朋,其實(shí)已經(jīng)可以完整的獲取所有讀寫SQL,并提供了完善的api吓著,阿里云可以基于全量SQL鲤嫡,AWS 可以基于 MariaDB audit plug-in。小米的 Soar夜矗,還有一堆原來大家都曉得的測(cè)試工具泛范,RDS 基于 api 創(chuàng)建銷毀即可。那是不是想要快速實(shí)現(xiàn)一套壓測(cè)環(huán)境并不是一件很難的事情紊撕。
依靠云上api 快速獲取問題SQL & 表罢荡,靠 Soar 抽樣 Or 全量同步到測(cè)試環(huán)境,最后依靠壓測(cè)工具開始測(cè)試对扶,這樣全部基于業(yè)務(wù)場(chǎng)景的測(cè)試其實(shí)才是最有意義且對(duì)于業(yè)務(wù)最有幫助的(基準(zhǔn)測(cè)試都是用來學(xué)習(xí) Or 硬件選型的)
MySQL 壓測(cè)工具
- sysbench 大家都知道的好東西
- mydbtest 平民軟件開發(fā)的一款 C 語言的 SQL 壓測(cè)工具
- golang-sql-benchmark 可以借鑒之后基于 Go 實(shí)現(xiàn)一個(gè)自己的
Soar Sampling
- 計(jì)算公式:Cardinality = ColumnDistinctCount/TableTotalRows * 100%
- 數(shù)據(jù)采樣算法:PostgreSQL 數(shù)據(jù)直方圖采樣算法
- soar 實(shí)現(xiàn)代碼:sampling.go
The following choice of minrows is based on the paper
"Random sampling for histogram construction: how much is enough?"
by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in
Proceedings of ACM SIGMOD International Conference on Management
of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5
says that for table size n, histogram size k, maximum relative
error in bin size f, and error probability gamma, the minimum
random sample size is
r = 4 * k * ln(2*n/gamma) / f^2
Taking f = 0.5, gamma = 0.01, n = 10^6 rows, we obtain
r = 305.82 * k
Note that because of the log function, the dependence on n is
quite weak; even at n = 10^12, a 300*k sample gives <= 0.66
bin size error with probability 0.99. So there's no real need to
scale for n, which is a good thing because we don't necessarily
know it at this point.
mydbtest 馬甲
本人比較喜歡的一個(gè)工具区赵,C 實(shí)現(xiàn) 1個(gè) cpu 壓死一個(gè) mysql,但是這個(gè)東西純命令行需要自己包裝一層浪南,如下為實(shí)現(xiàn) Demo (有一個(gè)小頁(yè)面就不貼了笼才,代碼爛,各位忍茁缭洹)
func upload(w http.ResponseWriter, r *http.Request) {
//判斷請(qǐng)求方式
if r.Method == "POST" {
//設(shè)置內(nèi)存大小
r.ParseMultipartForm(32 << 20)
//獲取上傳的第一個(gè)文件
file, header, err := r.FormFile("file")
defer file.Close()
if err != nil {
log.Fatal(err)
}
//獲取表單中degree
degree := r.PostFormValue("degree")
if err != nil {
log.Fatal(err)
}
//創(chuàng)建上傳目錄
os.Mkdir("./upload", os.ModePerm)
//創(chuàng)建上傳文件
cur, err := os.Create("./upload/" + header.Filename)
defer cur.Close()
if err != nil {
log.Fatal(err)
}
//把上傳文件數(shù)據(jù)拷貝到我們新建的文件
io.Copy(cur, file)
//mydbtest_linux64.bin query=insert.cnf degree=8
cmdString := fmt.Sprint("./mydbtest_linux64.bin query=./upload/", header.Filename, " degree=", degree)
cmd := exec.Command("bash", "-c", cmdString)
go func() {
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
}()
} else {
//解析模板文件
t, _ := template.ParseFiles("./upload.html")
//輸出文件數(shù)據(jù)
t.Execute(w, nil)
}
}
// curl -X POST -H 'Content-Type: multipart/form-data' -F 'file=@test.txt' -F 'degree=88' http://127.0.0.1:9090/upload
func main() {
http.HandleFunc("/upload", upload)
err := http.ListenAndServe(":23334", nil)
if err != nil {
log.Fatal(err)
}
}
dbtest control
Ps. 全部自行實(shí)現(xiàn)周期太長(zhǎng)骡送,比較喜歡把現(xiàn)有工具做好串聯(lián)打通孵运。