Mycat對於導入和擴容遷移性能壓測
1. 測試環境
1.1. 硬件環境
機器ip | OS | CPU | CPU Processors | 內存 |
172.16.54.135 | CentOS Linux release 7.1.1503 | Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz | 24 | 64G |
172.16.54.136 | CentOS Linux release 7.1.1503 | Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz | 24 | 64G |
172.16.54.138 | CentOS Linux release 7.1.1503 | Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz | 24 | 64G |
1.2. 軟件環境
軟件名稱 | 版本 |
Jdk | 1.8.0_45 |
Mycat | 1.4.1 |
Mysql | 5.6 |
PostgreSQL | 9.2.14 |
2. 對於Mysql壓測
2.1. 基本配置
wrapper.conf
# Java AdditionalParameters #wrapper.java.additional.1= wrapper.java.additional.1=-DMYCAT_HOME=. wrapper.java.additional.2=-server wrapper.java.additional.3=-XX:MaxPermSize=64M wrapper.java.additional.4=-XX:+AggressiveOpts wrapper.java.additional.5=-XX:MaxDirectMemorySize=5G wrapper.java.additional.6=-Dcom.sun.management.jmxremote wrapper.java.additional.7=-Dcom.sun.management.jmxremote.port=1984 wrapper.java.additional.8=-Dcom.sun.management.jmxremote.authenticate=false wrapper.java.additional.9=-Dcom.sun.management.jmxremote.ssl=false # Initial JavaHeap Size (in MB) #wrapper.java.initmemory=3 wrapper.java.initmemory=3072 # Maximum JavaHeap Size (in MB) #wrapper.java.maxmemory=64 wrapper.java.maxmemory=3072
schema.xml
<schemaname="testdb" checkSQLschema="false"sqlMaxLimit="100"> <table name="user"dataNode="dn1,dn2" rule="mod-long"/> </schema> <dataNode name="dn1"dataHost="mycat" database="db1"/> <dataNode name="dn2"dataHost="mycat2" database="db1"/> <dataHost name="mycat"maxCon="1000" minCon="10" balance="0"writeType="0" dbType="mysql" dbDriver="native" switchType="1"> <heartbeat>selectuser()</heartbeat> <writeHosthost="host1" url="dev-2:3306" user="test"password="test"/> </dataHost> <dataHost name="mycat2"maxCon="1000" minCon="10" balance="0"writeType="0" dbType="mysql" dbDriver="native" switchType="1"> <heartbeat>selectuser()</heartbeat> <writeHosthost="host2" url="dev-3:3306" user="test"password="test"/> </dataHost>
數據庫腳本
create databasedb1; create tabledb1.user(id int, user_name varchar(20), email varchar(20), phone varchar(20));
2.2. 導入方案
由於Mycat支持Mysql協議,所以Mycat對於Mysql數據導入方案有三種:
用jdbc直接進行insert操作
根據官網測試結果:在16核上insert性能可以達到12w/s
本輪測試數據量200w,測試工具爲testtool.tar.gz。結論:tps約8w
用mysqldump操作
mysqldump操作原理與insert相同,數據量100w,沒有預熱。結論tps:3w
用load data infile操作
官網說法:是insert性能的幾十倍,如下
Load data功能在1.4版本+支持,經過測試發現,如果導入數據量比較大(大於10w),則會出現文件找不到情況,官網羣中有人出現同樣問題,原因待查。
根據其他人測試結果:loaddata local infile命令64M23萬條數據用到500多M內存
2.3. 擴容遷移方案
從schema db1遷移擴容到db2。由於mycql不支持自動擴容,所以需要手動進行rehash。
目前方案有:
將數據導出本分,清空數據,通過上述導入方案的三種方式進行擴容遷移
性能結果如上測試
手動遷移(注意:此方案只適合單節點遷移):
1) 使用mycat的RehashLauncher重新進行hash算法,得出rehash的id列表
2) 在mysql上使用mysqldump根據rehash的id列表,導出數據
3) 在mycat上mysqldump,導入數據
4) 在mysql上刪除遷移的數據
對於1)步驟,有2個bug:
取得id值時錯誤
此bug已經提交到mycate1.4和mycat master分支,並已合併
hash後的host比較錯誤
此bug已經提交到1.4分支,並已合併
對於2),3),4)步驟可以採用shell腳本自動運行,官網腳本如下:
# arg1=start, arg2=end, format: %s.%N function getTiming() { start=$1 end=$2 start_s=$(echo$start | cut -d '.' -f 1) start_ns=$(echo$start | cut -d '.' -f 2) end_s=$(echo $end |cut -d '.' -f 1) end_ns=$(echo $end |cut -d '.' -f 2) time=$(( ( 10#$end_s- 10#$start_s ) * 1000 + ( 10#$end_ns / 1000000 - 10#$start_ns / 1000000 ) )) echo "$timems" } #rehash節點 rehashNode=$1 #mycat節點 expanNode=$2 #遷移數據 order_fn="$3" #遷移數據庫 rehash_db=db1 #遷移表 rehash_table=user #mysql配置 mysql_port=3306 mysql_user=test mysql_pwd=test #mycat配置 mycat_port=8066 mycat_user=mysql mycat_pwd=123456 mycat_db=testdb start=$(date +%s.%N) if [ "$#" = "0" ]; then echo "Please input parameter, for example:" echo "ReRouter.sh 192.168.84.13 192.168.84.14/home/mycat/T_CMS_ORDER" echo " " exit fi; echo "需要進行遷移的主機總量爲:$#, 主機 IP 列表如下:" for i in "$@" do echo "$i" done echo " " #取出 rehash 需要的 SerNum(已經用 in 拼接好) for n in `cat $order_fn` do condOrder=$n done echo "************* 導出 *************" date # 1) 首先調用 mysqldump 進行數據導出 echo "開始導出主機:$ 表:T_CMS_ORDER." mysqldump -h$rehashNode -P$mysql_port -u$mysql_user-p$mysql_pwd $rehash_db $rehash_table --default-characterset=utf8 --extende d-insert=false --no-create-info --add-locks=false--completeinsert --where=" id in $condOrder " >./T_CMS_ORDER_temp.sql echo "導出結束." echo " " echo "************* 導入 *************" date # 2) 調用 mycat 接口進行數據導入 echo "開始導入 T_CMS_ORDER 表數據" mysql -h$expanNode -P$mycat_port -u$mycat_user -p$mycat_pwd$mycat_db --default-character-set=utf8 < ./T_CMS_ORDER_temp.sql echo "導入結束." echo " " echo "************* 刪除數據 *************" date # 3) 當前兩步都無誤的情況下,刪除最初的導出數據. echo "開始刪除已導出的數據表:." mysql -h$rehashNode -Pmycat_port -u$mysql_user-p$mysql_pwd -e "use $rehash_db;DELETE FROM $rehash_table WHERE id in $condOrder ; commit; " echo "刪除結束." echo " " echo "************* 清空臨時文件 *************" date # 4) 清空臨時文件 rm ./T_CMS_ORDER_temp.sql echo "清空臨時文件" echo "#####################主機:$rehashNode 處理完成#####################" date echo " " echo "ReHash 運行完畢." end=$(date +%s.%N) getTiming $start $end
此腳本運行1)執行的文件,會報如下錯誤:
這是由於1)會一次性根據id列表,採用in語句查詢出所有數據,當數據量過大時,報錯。本輪測試採用優化方案:
1)步驟每1w爲一行
RehashLauncher代碼如下:
public class RehashLauncher { private final class RehashRunner implements Runnable { private final File output; private final String table; private RehashRunner(File output, String table) { this.output = output; this.table = table; } public void run(){ int pageSize=500; int page=0; List<Map<String, Object>> list=null; int total=0; int rehashed=0; String hostWithDatabase=args.getHostWithDatabase(); PrintStream ps=null; try { ps=new PrintStream(output); StringBuilder rehashData = new StringBuilder(); list = JdbcUtils.executeQuery(dataSource, "select " + args.getShardingField() + " from " + table + " limit ?,?", page++ * pageSize, pageSize); while (!CollectionUtil.isEmpty(list)) { for(int i=0,l=list.size();i<l;i++){ Map<String, Object> sf=list.get(i); Integer hash=alg.calculate(sf.get(args.getShardingField()).toString()); String host=rehashHosts[hash]; total++; if(!host.equals(hostWithDatabase)){ rehashed++; rehashData.append(sf.get(args.getShardingField())).append(","); if(rehashed % 10000 == 0){ ps.println("(" + rehashData.substring(0, rehashData.length() - 1) + ")"); rehashData.delete(0, rehashData.length()); } } // ps.println(sf+"=>"+host); } list = JdbcUtils.executeQuery(dataSource, "select " + args.getShardingField() + " from " + table + " limit ?,?", page++ * pageSize, pageSize); } if(rehashData.length() >= 1){ ps.println("(" + rehashData.deleteCharAt(rehashData.length() - 1) + ")"); } // ps.println("rehashed ratio:"+(((double)rehashed)/total)); } catch (Exception e) { throw new RehashException(e); }finally{ if(ps!=null){ ps.close(); } latch.countDown(); } } }
program argument:
-jdbcDriver=com.mysql.jdbc.Driver -jdbcUrl=jdbc:mysql://172.16.54.136:3306/db1 -host=172.16.54.136:3306 -user=test -database=db1 -password=test -tablesFile=F:/certusnetSVN/books/mycat/rehash\tables.txt -shardingField=id -rehashHostsFile=F:/certusnetSVN/books/mycat/rehash/hosts.txt -hashType=mod -rehashNodeDir=F:/certusnetSVN/books/mycat/rehash/tmp
hosts.txt配置:
172.16.54.136:3306/db1 172.16.54.138:3306/db1 172.16.54.136:3306/db2 172.16.54.138:3306/db2
tables.txt配置:
user
2),3),4)腳本改爲shell多線程,每次處理一行的方案
腳本如下:
# arg1=start, arg2=end, format: %s.%N function getTiming() { start=$1 end=$2 start_s=$(echo $start | cut -d '.' -f 1) start_ns=$(echo $start | cut -d '.' -f 2) end_s=$(echo $end | cut -d '.' -f 1) end_ns=$(echo $end | cut -d '.' -f 2) time=$(( ( 10#$end_s - 10#$start_s ) * 1000 + ( 10#$end_ns / 1000000 - 10#$start_ns / 1000000 ) )) echo "$time ms" } #rehash節點 rehashNode=$1 #mycat節點 expanNode=$2 #遷移數據 order_fn="$3" #遷移數據庫 rehash_db=db1 #遷移表 rehash_table=user #mysql配置 mysql_port=3306 mysql_user=test mysql_pwd=test #mycat配置 mycat_port=8066 mycat_user=mysql mycat_pwd=123456 mycat_db=testdb total_start=$(date +%s.%N) if [ "$#" = "0" ]; then echo "Please input parameter, for example:" echo "ReRouter.sh 192.168.84.13 192.168.84.14 /home/mycat/T_CMS_ORDER" echo " " exit fi; echo "需要進行遷移的主機總量爲:$#, 主機 IP 列表如下:" for i in "$@" do echo "$i" done echo " " #取出 rehash 需要的 SerNum(已經用 in 拼接好) while read condOrder do { file_id=${condOrder:3:10} echo "************* 導出 *************" date # 1) 首先調用 mysqldump 進行數據導出 echo "開始導出主機:$ 表:T_CMS_ORDER." mysqldump -h$rehashNode -P$mysql_port -u$mysql_user -p$mysql_pwd $rehash_db $rehash_table --no-create-info --skip-add-locks -c --where=" id in $condOrder " > ./T_CMS_ORDER_$file_id.sql echo "導出結束." echo " " echo "************* 導入 *************" date # 2) 調用 mycat 接口進行數據導入 echo "開始導入 T_CMS_ORDER 表數據" mysql -h$expanNode -P$mycat_port -u$mycat_user -p$mycat_pwd -D$mycat_db < ./T_CMS_ORDER_$file_id.sql echo "導入結束." echo " " echo "************* 刪除數據 *************" date # 3) 當前兩步都無誤的情況下,刪除最初的導出數據. echo "開始刪除已導出的數據表:." mysql -h$rehashNode -Pmycat_port -u$mysql_user -p$mysql_pwd -e "use $rehash_db; DELETE FROM $rehash_table WHERE id in $condOrder ; commit; " echo "刪除結束." echo " " echo "************* 清空臨時文件 *************" date # 4) 清空臨時文件 rm ./T_CMS_ORDER_$file_id.sql echo "清空臨時文件" echo "#####################主機:$rehashNode 處理完成#####################" date echo " " echo "ReHash 運行完畢." }& done < $order_fn wait echo "操作總消耗時長:" total_end=$(date +%s.%N) getTiming $total_start $total_end
執行結果100w遷移,耗時約:20s
3. 對於postgresql壓測
3.1. 基本配置
schema.xml
<schemaname="testdb" checkSQLschema="false"sqlMaxLimit="100"> <tablename="user_test" dataNode="dn1,dn2"rule="mod-long"/> </schema> <dataNode name="dn1"dataHost="mycat" database="db1"/> <dataNode name="dn2"dataHost="mycat2" database="db1"/> <dataHost name="mycat"maxCon="1000" minCon="10" balance="0"writeType="0" dbType="postgresql" dbDriver="jdbc" switchType="1"> <heartbeat>select1</heartbeat> <writeHosthost="host1" url="jdbc:postgresql://dev-2:5432/db1"user="postgres" password="123456"/> </dataHost> <dataHost name="mycat2"maxCon="1000" minCon="10" balance="0"writeType="0" dbType="postgresql" dbDriver="jdbc" switchType="1"> <heartbeat>select1</heartbeat> <writeHosthost="host2" url="jdbc:postgresql://dev-3:5432/db1"user="postgres" password="123456"/> </dataHost>
postgresql.conf
shared_buffers = 128MB max_connections = 1000 fsync = off wal_buffers = -1 commit_delay = 10000 commit_siblings = 500
數據庫腳本
create databasedb1; create table user_test(idint, user_name varchar(20), email varchar(20), phone varchar(20));
3.2. 導入方案
Mycat對於postgresql的導入方案只有一種,採用jdbc的insert方式。
本輪測試數據量100w,測試工具爲testtool.tar.gz。結論:tps約6w
3.3. 擴容遷移方案
對於postgresql遷移,也只能採用編程程序的方式進行,方案可以參考mysql遷移方案,此輪不再測試。