TokuDB性能測試報告


一 、背景介紹

近年來,TokuDB作為MySQL的大數據(Big Data)存儲引擎受到人們的普遍關注。其架構的核心基於一種新的叫做分形樹(Fractal Trees)的索引數據結構,該結構是緩存無關的,即使索引數據大小超過內存性能也不會下降,也即沒有內存生命周期和碎片的問題。

特別引人注意的是,TokuDB擁有很高的壓縮比(官方稱最大可達25倍),可以在很大的數據上創建大量的索引,並保持性能不下降。同時,TokuDB支持ACID和MVCC,還有在線修改表結構(Live Schema Modification)以及增加的復制性能等特性,使其在某些特定的應用領域(如日志存儲與分析)有着獨特的優勢。

在TokuDB的應用場景中,通常是數據庫插入操作的量遠遠大於讀取的量,因而本此測試主要針對TokuDB的插入性能以及壓縮比,以InnoDB作為參考基准。

二、測試環境搭建

測試使用的機器為高配機型,內存大於100G,CPU型號為Intel(R) Xeon(R) CPU E5系列,數據盤使用的是SSD硬盤。

MySQL TokuDB版本使用的是 5.6.28-76.1,按照Percona網站上的安裝方法使用插件的方式進行安裝,見官網教程。使用MySQL命令查看:

+--------------------+---------+--------------+------+------------+
| Engine             | Support | Transactions | XA   | Savepoints |
+--------------------+---------+--------------+------+------------+
| InnoDB             | YES | YES | YES | YES | | CSV | YES | NO | NO | NO | | MyISAM | YES | NO | NO | NO | | BLACKHOLE | YES | NO | NO | NO | | MEMORY | YES | NO | NO | NO | | TokuDB | DEFAULT | YES | YES | YES | | MRG_MYISAM | YES | NO | NO | NO | | ARCHIVE | YES | NO | NO | NO | | FEDERATED | NO | NULL | NULL | NULL | | PERFORMANCE_SCHEMA | YES | NO | NO | NO | +--------------------+---------+--------------+------+------------+ 

可以看到TokuDB引擎已經就緒,並被設置為了默認的存儲引擎。

三、測試工具與變量

1、測試工具選擇

現在開源可用的MySQL基准測試工具有很多,如mysqlslap,MySQL Benchmark Suite,Super Smack,Database Test Suite,TPCC和sysbench等。綜合工具的功能、易用性還有流行程度,最終選定操作簡單但功能強大的sysbench作為測試工具。在sysbench 0.5版本中,已經開始支持Lua腳本,使用修改起來非常靈活。另外,測試壓縮比直接使用的mysqldump工具。

2、測試變量

插入性能相關的變量

除去根據機器硬件特性配置的常規優化參數,對於存儲引擎插入性能影響最大的是:是否將事務和binlog同步刷新到硬盤。

需要特別說明的是,還有一個比較重要的指標,即是否開啟了DIRECT IO功能,由於在測試環境InnoDB開啟了DIRECT IO,並能提高整體的性能,而TokuDB在測試機型上無法開啟DIRECT IO功能,所以在這點上InnoDB有相對的優勢。

InnoDB 相關

對於InnoDB來說,控制這個功能的參數為innodb_flush_log_at_trx_commitsync_binlog
innodb_flush_log_at_trx_commit參數指定了InnoDB在事務提交后的日志寫入頻率。具體來說:

  1. innodb_flush_log_at_trx_commit取值為 0 時,log buffer 會 每秒寫入到日志文件並刷寫(flush)到硬盤。但每次事務提交不會有任何影響,也就是 log buffer 的刷寫操作和事務提交操作沒有關系。在這種情況下,MySQL性能最好,但如果 mysqld 進程崩潰,通常會導致最后 1s 的日志丟失。
  2. 當取值為 1 時,每次事務提交時,log buffer 會被寫入到日志文件並刷寫到硬盤。這也是默認值。這是最安全的配置,但由於每次事務都需要進行硬盤I/O,所以也最慢。
  3. 當取值為 2 時,每次事務提交會寫入日志文件,但並不會立即刷寫到硬盤,日志文件會每秒刷寫一次到硬盤。這時如果 mysqld 進程崩潰,由於日志已經寫入到系統緩存,所以並不會丟失數據;在操作系統崩潰的情況下,通常會導致最后 1s 的日志丟失。
    在實際的生產系統中,innodb_flush_log_at_trx_commit會在1和2之間選擇。一般來說,對數據一致性和完整性要求比較高的應用場景,會將其值設置為1。

sync_binlog參數指定了 MySQL 的二進制日志同步到硬盤的頻率。如果MySQL autocommit開啟,那么每個語句都寫一次binlog,否則每次事務寫一次。

  1. 默認值為 0,不主動同步binlog的寫入,而依賴於操作系統本身不定期把文件內容flush到硬盤。
  2. 設置為 1 時,在每個語句或者事務后會同步一次binlog,即使發生意外崩潰時也最多丟失一個事務的日志,因而速度較慢。

通常情況下,innodb_flush_log_at_trx_commitsync_binlog配合起來使用,本次性能測試覆蓋了同步刷新日志和異步刷新日志兩種策略。

TokuDB 相關

TokuDB中與InnoDB類似的指標為tokudb_commit_synctokudb_fsync_log_period。與innodb_flush_log_at_trx_commit的含義類似,tokudb_commit_sync指定當事務提交的時候,是否要刷新日志到硬盤上。

  1. 默認開啟,值為1。也就是每次事務提交時,log buffer 會被寫入到日志文件並刷寫到硬盤。
  2. 如果設置為 0,每次事務提交會寫入日志文件,但並不會立即刷寫到硬盤,日志文件會每隔一段時間刷寫一次到硬盤。這個時間間隔由tokudb_commit_sync指定。

tokudb_fsync_log_period指定多久將日志文件刷新到硬盤,TukuDB的log buffer總大小為 32 MB且不可更改。默認為 0 秒,此時如果tokudb_commit_sync設置為開啟,那么這個值默認為 1 分鍾。

tokudb_commit_synctokudb_fsync_log_period通常也是配合起來使用,本次性能測試覆蓋了兩種典型的組合策略。

壓縮比相關的變量

大多數選擇使用TokuDB的場景,都非常重視它的存儲壓縮比,因而在實際應用場景中總會配套使用某種壓縮算法。當前TokuDB支持的壓縮算法有,quicklz, zlib, lzma, snappy,當然還有不壓縮uncompressed。關於壓縮算法的討論,可以參考官方博客的一篇分析文章

本次測試會結合真實的數據來從壓縮比、耗時兩個方面來檢驗上面幾個不同的壓縮算法。TokuDB可以通過在配置文件中設置tokudb_row_format來指定不同的壓縮算法,它們的取值分別是:TOKUDB_QUICKLZTOKUDB_ZLIBTOKUDB_LZMATOKUDB_SNAPPY。值得注意的是,zlib算法是TokuDB官方最新版本的默認算法,也是現今支持TokuDB的雲服務商的默認推薦算法。

sysbench壓縮工具相關的變量

sysbench針對mysql壓測的參數有很多,這里選取的是與實際應用場景最為相關的兩個參數:表數量以及線程數量。表數量對應的是數據庫實際在同時寫入的表的數量,線程數對應的到MySQL數據庫上的連接。其他的參數,如表的大小,是否是事務等可能影響整體的插入性能,但影響並不顯著,這里只選取最主要的兩個參數進行分析。

3、測試方法

本測試的采用的方式為經典的控制變量法。這里的變量有:采用的存儲引擎類型,是否同步刷新日志,采用的壓縮算法,以及另外兩個與sysbench相關的參數:壓測的線程數量和壓測的表數量。其中,壓縮算法的選擇只是在四種算法中選擇一種,所以並不與其他變量交叉測試。這樣以存儲引擎和同步刷新日志來划分測試,可以將整個測試數據分為四個大類:

  1. InnoDB & 同步刷新日志
  2. InnoDB & 異步刷新日志
  3. TokuDB & 同步刷新日志
  4. TokuDB & 異步刷新日志

在每個大類下,對壓測線程數量和壓測表數量進行交叉測試。壓測表數量取值可能為[1, 2, 4, 8, 12, 16],線程數的可能取值為[1, 2, 4, 8, 16, 24, 32, 48, 64, 80],因而每個大類下進行6 * 10 = 60 次壓測,每次壓測寫入2,000,000 條數據,對每次壓測進行插入性能統計。

四、測試結果分析

1、InnoDB & 同步刷新日志

innodb_flush_log_at_trx_commit設置為1,sync_binlog設置為1,也即是保證數據最安全:同步刷新log到硬盤,並且針對每個事務同步一次binlog。測試的情況見下表:

表數/插入TPS/線程數 1 2 4 8 12 16
1 5645.54 5678.40 5711.15 5687.44 5660.76 5708.54
2 10995.42 10921.06 11023.25 11017.88 11038.06 10902.12
4 18732.14 18724.20 18882.65 18935.62 18890.46 17997.52
8 33291.35 33379.37 33372.19 33842.15 30576.58 34048.53
16 54560.36 56346.20 57358.33 57454.11 57571.72 57989.96
24 66230.44 70813.87 73871.31 68764.22 68019.27 67538.82
32 66855.54 80153.06 84885.82 84387.96 76404.04 84920.13
48 56788.96 85778.22 93914.45 97055.96 84041.31 96790.49
64 55640.96 83342.88 95736.42 92667.25 96560.51 83598.00
80 58408.18 75858.18 60683.99 60491.26 60177.24 64290.13

用更直觀的圖表來展示:

可以看到:

  1. 在線程數比較少的時候(不高於24個,即總CPU數目的一半),數據表的個數對整體的性能影響很小;當線程數較多時才顯示出區別:相同線程數下,增加表數目可提升數據庫整體吞吐量
  2. InnoDB整體性能在48線程時達到頂峰,也即達到CPU的總數目,說明InnoDB能充分利用硬件多CPU的特性
  3. 在線程數或者表數量很小的時候,增加線程數或者表數量可以線性地提升性能,在實際環境中值得注意;而在線程數量超過物理CPU數量時,整體插入性能會下降

2、InnoDB & 異步刷新日志

innodb_flush_log_at_trx_commit設置為2,sync_binlog設置為 0,日志文件會每秒刷寫一次到硬盤,並且不主動同步binlog的寫入,而依賴於操作系統本身不定期把文件內容flush到硬盤。測試的情況見下表:

表數/插入TPS/線程數 1 2 4 8 12 16
1 7751.83 7776.78 7741.86 7739.29 7770.41 7662.18
2 15199.98 14952.94 15252.04 15184.54 15186.76 15176.68
4 29075.83 29194.62 29228.09 29204.63 29625.60 29406.31
8 53578.10 51007.42 53116.44 54029.60 53291.41 52173.69
16 61002.65 71383.45 74656.36 75597.66 76305.24 76412.77
24 52758.54 70906.04 78472.49 81999.99 80430.52 82896.78
32 51740.38 68061.25 79936.12 82063.79 84966.86 83667.26
48 50961.62 65962.79 79952.45 85511.97 86223.38 86718.83
64 53378.76 65758.29 74224.26 76779.63 75368.30 76614.14
80 55056.88 66799.11 73969.11 62867.60 62039.68 63572.61

用更直觀的圖表來展示:

可以看到與InnoDB Sync的情況有所不同:

  1. 異步的情況,隨着線程數的增加,插入性能提升較快,在16個線程的時候已經接近峰值
  2. 插入TPS的峰值比同步情況的峰值低,這個與以往SATA/SAS磁盤環境下的MySQL優化經驗不匹配;通過iostat查看SSD盤的使用率很低,只有百分之幾,因而SSD硬盤條件下的InnoDB的優化策略需要持續改進

3、TokuDB & 同步刷新日志

tokudb_commit_sync設置為1,tokudb_fsync_log_period設置為0,也就是每次事務提交時,log buffer 會被寫入到日志文件並刷寫到硬盤。

表數/插入TPS/線程數 1 2 4 8 12 16
1 6506.16 6533.51 6514.36 6505.52 6581.28 6588.60
2 12335.72 12323.07 12494.74 12572.37 12600.94 12623.45
4 22726.24 23001.47 23331.96 23854.47 24267.20 24060.65
8 34935.53 38952.86 40093.37 41687.61 42472.60 44021.98
16 30777.25 42145.63 50293.47 55585.24 58956.65 59804.16
24 28102.26 38306.27 44420.44 47960.77 50440.59 52436.36
32 26227.49 35677.10 39627.22 40717.32 42562.45 44657.12
48 23335.33 30574.98 34961.22 34289.79 34819.25 35367.41
64 28923.69 36267.50 35228.70 35306.85 30393.76 29644.79
80 28323.74 33808.39 34203.47 35249.88 27757.45 32269.39

用圖表來展示:

可以看到:

  1. 出乎意料的是,TokuDB在線程數16的時候插入TPS達到峰值,也就是說TokuDB並沒有完全利用起多物理CPU的優勢
  2. 對比InnoDB線程數從1~16的情況可以看到,TokuDB在相同條件下比InnoDB的性能還要高;而在線程數增多的時候,TokuDB的插入TPS在逐漸減小,而InnoDB在線程數超過物理CPU個數的時,插入TPS才開始下降,說明TokuDB還有很大的優化空間

4、TokuDB & 異步刷新日志

線程數/插入TPS/表數 1 2 4 8 12 16
1 6478.74 6514.03 6571.31 6555.92 6462.55 6588.75
2 12388.24 12433.75 12417.53 12457.83 12629.21 12597.90
4 22915.61 22265.08 24002.63 24248.57 22596.18 24323.07
8 35078.08 39179.46 39583.82 39505.79 42549.19 43493.89
16 30017.06 42012.43 46019.37 58790.76 60294.11 61057.96
24 27675.70 37873.94 45151.54 45075.48 49145.73 52417.81
32 26078.90 35496.19 39891.16 38888.13 43570.03 44882.92
48 23340.20 32392.89 35164.66 33858.16 34209.27 35350.72
64 29522.80 36475.76 36969.68 32381.53 32160.18 32589.76
80 27976.86 33483.40 34994.01 34977.62 30259.96 32680.34

用圖表來展示:

對比之前的圖標,可以看到:

  1. 與InnoDB不同的是,是否開啟log的同步對TokuDB的插入性能影響不大,TokuDB SyncTokuDB Async兩者的圖形形狀幾乎一樣
  2. 與同步的情況類似,TokuDB在線程數16的時候插入TPS就達到峰值,有很大的優化空間

5、壓縮算法選擇

壓縮算法測試使用的實際的運行數據做測試,原來用InnoDB存儲的日志數據為92GB,用mysqldump工具導出后為79GB。測試表是典型的日志存儲表,其結構如下:

+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | a | int(11) | NO | PRI | NULL | auto_increment | | b | bigint(20) | NO | MUL | 0 | | | c | varchar(30) | NO | | | | | d | varchar(20) | NO | | | | | e | varchar(30) | NO | | | | | f | text | NO | | NULL | | | g | varchar(300) | NO | | | | | h | int(11) | NO | | 0 | | | i | int(11) | NO | | 0 | | | j | int(11) | NO | | 0 | | | k | int(11) | NO | | 0 | | +-------+--------------+------+-----+---------+----------------+ 

依次將TokuDB的tokudb_row_format設置為不同的壓縮算法,得到其導入后的實際存儲空間以及導入時間,測試結果如下:

壓縮算法/項目 存儲大小 導入時間
snappy 12GB 47min40s
quicklz 7.1GB 47min21s
zlib 5.7GB 48min9s
lzma 4.7GB 47min10s

從表中可以觀察到:

  1. 幾種壓縮算法耗時差不多,相差很小
  2. 不同的壓縮算法的壓縮比差異較大,snappy壓縮比較小,約為6.6倍;壓縮比最大的lzma為16.8倍
  3. zlib作為官方選擇的默認壓縮算法,在壓縮比和CPU消耗上有較好的平衡,壓縮比為13.8倍

結合在測試過程中持續觀察CPU的使用情況,lzma算法在運行過程中CPU使用率在600%~700%左右,而zlib算法CPU使用率在80%~180%之間擺動。因而,在實際生產環境中,如果沒有特殊的考慮,建議使用zlib壓縮算法。

五、討論與結論

本次測試以InnoDB為參考,主要測試TokuDB的寫入性能以及存儲壓縮比。通過不同場景下的對比測試,可以得出幾個觀點:

  1. InnoDB現階段插入性能有優勢,性能大約高出30%左右
  2. TokuDB雖然沒有充分利用硬件的能力,但是已經表現出強大的足夠高的性能,考慮到TokuDB的成熟度,后面它還有較大的提升空間,可以持續關注其后續進展
  3. TokuDB選擇日志同步或者異步刷新對性能影響不大,建議默認選擇同步日志保護數據
  4. TokuDB在數據壓縮存儲上有絕對的優勢,十幾倍的壓縮比對於冷備數據存儲有着極大的吸引力

值得一提的是,InnoDB性能表現優異部分原因可歸功於InnoDB的成熟度,可靈活的配置許多參數以適應特定的應用場景,而TokuDB暴露出的優化參數很少,不能根據硬件配置調整一些重要參數。綜上,雖然TokuDB在現階段還沒成熟,但已經表現出強大的性能以及突出的特性,應該作為某些特定應用場景的首選。


 

此文來自騰訊雲數據庫團隊,轉載請注明文章出處,獲取更多雲計算技術干貨,可請前往騰訊雲技術社區,當然我們也會在博客園持續同步更新~

微信公眾號:騰訊雲技術社區( QcloudCommunity)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM