mymysql和go-mysql-driver是兩個現在都很流行的go的mysql驅動,這篇文章目的是要將這兩個驅動進行一下比較
兩個mysql驅動的下載地址:
https://github.com/ziutek/mymysql
http://code.google.com/p/go-mysql-driver/
首先是性能測試
准備工作:
在mysql建表和初始化數據(db是test)
drop table if exists admin; CREATE TABLE `admin` ( `adminid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL DEFAULT '' COMMENT '后台用戶名', `password` char(32) NOT NULL DEFAULT '' COMMENT '密碼,md5存', PRIMARY KEY(`adminid`) ) COMMENT='后台用戶信息表' COLLATE='utf8_general_ci' ENGINE=InnoDB; insert into admin set adminid=1, username='admin', password='21232f297a57a5a743894a0e4a801fc3';
兩邊的庫代碼和測試代碼
已經將gomysqldriver和mymysql的代碼放到github上了,有興趣的去里面看看。
https://github.com/jianfengye/MyWorks/tree/master/gomysqltest
代碼里面注意的幾點就是我們測試了get,insert,update三個操作,並且insert的時候不指定主鍵,讓其自增,innodb的表,這樣讓mysql處理插入操作盡可能快。
下面運行go test -bench=".*" -v -benchmem
mymysql的表現:
go-mysql-driver的表現:
輸出的數據分析:
Benchmark的測試用例名 benchtime內調用了多少次 每次調用耗時(納秒) 每次調用耗內存 每次調用分配內存次數
比如:
mymysql 的Benchmark_getAdmin在1s內一共調用了2000次,每次調用使用了974622納秒,使用內存大小為13444Byte,分配內存的alloc調用了220次
可以看出,go-mysql-driver的每個命令運行的時間是比mymysql多,但是內存是使用的情況卻比mymysql少。
猜測原因由於go-mysql-driver是使用默認的database/sql和database/sql/driver接口,由於接口是官方提供的,估計耗時多在方法匹配上,調用內存方面由於是官方的database/sql來進行連接等分配,寫的會比mymysql寫的好一些。
下面比較兩邊的profile
在兩個項目下都調用
go test -bench=".*" -c
go test -bench=".*" -cpuprofile="cpu.prof" -memprofile="mem.prof" -blockprofile="block.prof" -memprofilerate=1 -blockprofilerate=1
依次調用
go tool pprof mymysql.test cpu.prof
go tool pprof mymysql.test cpu.prof
go tool pprof mymysql.test cpu.prof
生成svg文件
具體可以參考我之前的一篇文章 go的pprof使用(http://www.cnblogs.com/yjf512/archive/2012/12/27/2835331.html)
我這里已經將它們都生成好了並命名為諸如mymysql_cpu.svg放在github上,你也可以直接去下載看
https://github.com/jianfengye/MyWorks/tree/master/gomysqltest
怎么看svg
關於pprof這里有一篇權威文章:cpuprofile(http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html)
先要明白幾個名詞
sample
sample就是“取樣”。pprof是基於取樣調查的,比如我每納秒取樣一次,收集這個時候程序的運行函數棧,知道現在是運行在那個函數中,然后把這些信息放在pprof文件中提供分析。
node
node就是函數調用信息,哪個函數中被調用了,調用了多少次
方法名
本方法占用sample次數(占所有sample的總數)
本方法的下行方法調用次數(占所有sample的比例)
“本方法占用sample的次數”就是除了調用下行的方法之外的其他代碼占用的方法數,當然是越小越好,越小說明了除了下行的方法之外的代碼幾乎不占用cpu時間。node的大小和這個值是正相關的
“下行方法調用次數”就是下行方法的調用中占用了多少個sample。
如果上面兩個值相等,那么“下行方法調用次數”就會被被忽略。這個一般只出現在edges中。
比如sweepspan就是下行方法占用37個sample,本身只占用了1個sample。
edges
edges就是終結點
runtime.mcmp就是自身是終結點,沒有下行方法,所以下行和本方法占用的sample相等。
基本信息解讀
比如:
mymysql.test是可執行文件名
Total samples:總的統計sample(打點數)
Focusing on:關注的sample。為什么有關注sample這么一說呢,並不是說所有的node和edges都是有用的信息,有的不重要的node和edges是會被忽略的。Focusing on samples就是除了這些不重要的node和edges之外的sample。
Dropped nodes:參考Focusing on。被忽略的node。
Dropped edges: 參考Focusing on。被忽略的edges。
ps: 這里默認的total sample是等於focusing sample的。你在pprof的時候可以使用--ignore參數來忽略掉那些不重要的node或者edges
明白了這些就知道了,看圖應該從最大的node往小的方向看,分析下占用資源多的函數在那里,是否可以優化這個函數或者方法。
比如可以看一下
gomysqldriver_cpu.svg這個例子
它有個比較占用sample的分支是
它的源頭在parseDSN
看到代碼里面去,會發現是解析dsn這步的時候使用了正則,導致運行Open的時候運行速度下降了。
所以說如果parseDSN這個函數的參數不是dsn string,而是使用map直接指定username,password等,這里的速度就會上去了。當然這其實也是不可以的,因為database/sql/driver的Open方法定義的參數就是一個string。
總結:
pprof圖將代碼流程完完全全地展現在我們面前。所以說呢我們可以做這么幾件事情:
1 根據pprof優化代碼
2 根據pprof學習一個完全陌生的開源軟件
3 根據pprof學習go的一個程序是怎么運行的
4 項目上線前的性能測試和壓力測試(在ab之外的有一個好的選擇了)
mymysql和go-mysql-driver的測試總結
根據以上的比較,我還是傾向於使用go-mysql-driver。原因有幾個:
1 go-mysql-driver是實現了golang標准庫database/sql的產物。底層實現比較有保證
2 go-mysql-driver雖然每個命令的運行時間比mymysql長,但是內存使用少得非常明顯,這點兩方算打平。
3 go-mysql-driver實現了database/sql,如果數據庫換成其他的話,不需要更改應用邏輯的代碼。
4 go-mysql-driver實現了database/sql,這個接口的設計也是非常好的,基本和php中的pdo一樣,上手和學習成本低。