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=-serverwrapper.java.additional.3=-XX:MaxPermSize=64Mwrapper.java.additional.4=-XX:+AggressiveOptswrapper.java.additional.5=-XX:MaxDirectMemorySize=5Gwrapper.java.additional.6=-Dcom.sun.management.jmxremotewrapper.java.additional.7=-Dcom.sun.management.jmxremote.port=1984wrapper.java.additional.8=-Dcom.sun.management.jmxremote.authenticate=falsewrapper.java.additional.9=-Dcom.sun.management.jmxremote.ssl=false# Initial JavaHeap Size (in MB)#wrapper.java.initmemory=3wrapper.java.initmemory=3072# Maximum JavaHeap Size (in MB)#wrapper.java.maxmemory=64wrapper.java.maxmemory=3072
  • schema.xml

                
                
        
         
                
selectuser()
                
                 
                
selectuser()
                
        
  • 数据库脚本

create databasedb1;create tabledb1.user(id int, user_name varchar(20), email varchar(20), phone varchar(20));

2.2.    导入方案

由于Mycat支持Mysql协议,所以Mycat对于Mysql数据导入方案有三种:

  1. jdbc直接进行insert操作

根据官网测试结果:在16核上insert性能可以达到12w/s

本轮测试数据量200w,测试工具为testtool.tar.gz。结论:tps8w

  1. mysqldump操作

mysqldump操作原理与insert相同,数据量100w,没有预热。结论tps3w

  1. load data infile操作

官网说法:是insert性能的几十倍,如下

Load data功能在1.4版本+支持,经过测试发现,如果导入数据量比较大(大于10w),则会出现文件找不到情况,官网群中有人出现同样问题,原因待查。

根据其他人测试结果:loaddata local infile命令64M23万条数据用到500M内存

2.3.  扩容迁移方案

schema db1迁移扩容到db2。由于mycql不支持自动扩容,所以需要手动进行rehash

目前方案有:

  1. 将数据导出本分,清空数据,通过上述导入方案的三种方式进行扩容迁移

性能结果如上测试

  1. 手动迁移(注意:此方案只适合单节点迁移):

  2. 1)        使用mycatRehashLauncher重新进行hash算法,得出rehashid列表

  3. 2)        mysql上使用mysqldump根据rehashid列表,导出数据

  4. 3)        mycatmysqldump,导入数据

  5. 4)        mysql上删除迁移的数据

对于1)步骤,有2bug

  • 取得id值时错误

bug已经提交到mycate1.4mycat 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=3306mysql_user=testmysql_pwd=test #mycat配置mycat_port=8066mycat_user=mysqlmycat_pwd=123456mycat_db=testdb start=$(date +%s.%N) if [ "$#" = "0" ]; thenecho "Please input parameter, for example:"echo "ReRouter.sh 192.168.84.13 192.168.84.14/home/mycat/T_CMS_ORDER"echo " "exitfi;echo "需要进行迁移的主机总量为:$#, 主机 IP 列表如下:"for i in "$@"doecho "$i"doneecho " "#取出 rehash 需要的 SerNum(已经用 in 拼接好)for n in `cat $order_fn`docondOrder=$ndone 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 --extended-insert=false --no-create-info --add-locks=false--completeinsert --where=" id in $condOrder " >./T_CMS_ORDER_temp.sqlecho "导出结束."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.sqlecho "导入结束."echo " " echo "************* 删除数据 *************"date# 3) 当前两步都无误的情况下,删除最初的导出数据.echo "开始删除已导出的数据表:."mysql -h$rehashNode -Pmycat_port -u$mysql_user-p$mysql_pwd  -e "use $rehash_db;DELETE FROM $rehash_tableWHERE id in $condOrder ; commit; "echo "删除结束."echo " "echo "************* 清空临时文件 *************"date# 4) 清空临时文件rm ./T_CMS_ORDER_temp.sqlecho "清空临时文件"echo "#####################主机:$rehashNode 处理完成#####################"dateecho " " 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
> 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
 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/db1172.16.54.138:3306/db1172.16.54.136:3306/db2172.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=3306mysql_user=testmysql_pwd=test#mycat配置mycat_port=8066mycat_user=mysqlmycat_pwd=123456mycat_db=testdbtotal_start=$(date +%s.%N)if [ "$#" = "0" ]; thenecho "Please input parameter, for example:"echo "ReRouter.sh 192.168.84.13 192.168.84.14 /home/mycat/T_CMS_ORDER"echo " "exitfi;echo "需要进行迁移的主机总量为:$#, 主机 IP 列表如下:"for i in "$@"doecho "$i"doneecho " "#取出 rehash 需要的 SerNum(已经用 in 拼接好)while read condOrderdo{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.sqlecho "导出结束."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.sqlecho "导入结束."echo " "echo "************* 删除数据 *************"date# 3) 当前两步都无误的情况下,删除最初的导出数据.echo "开始删除已导出的数据表:."mysql -h$rehashNode -Pmycat_port -u$mysql_user -p$mysql_pwd  -e "use $rehash_db; DELETE FROM $rehash_tableWHERE id in $condOrder ; commit; "echo "删除结束."echo " "echo "************* 清空临时文件 *************"date# 4) 清空临时文件rm ./T_CMS_ORDER_$file_id.sqlecho "清空临时文件"echo "#####################主机:$rehashNode 处理完成#####################"dateecho " "echo "ReHash 运行完毕."}&done < $order_fnwaitecho "操作总消耗时长:"total_end=$(date +%s.%N)getTiming $total_start $total_end

执行结果100w迁移,耗时约:20s

 

3.      对于postgresql压测

3.1.  基本配置

  • schema.xml

                
                
        
         
                
select1
                
                 
                
select1
                
        
  • postgresql.conf

shared_buffers = 128MBmax_connections = 1000fsync = offwal_buffers = -1commit_delay = 10000commit_siblings = 500
  • 数据库脚本

create databasedb1;create table user_test(idint, user_name varchar(20), email varchar(20), phone varchar(20));

3.2.  导入方案

Mycat对于postgresql的导入方案只有一种,采用jdbcinsert方式。

本轮测试数据量100w,测试工具为testtool.tar.gz。结论:tps6w

 

3.3.  扩容迁移方案

对于postgresql迁移,也只能采用编程程序的方式进行,方案可以参考mysql迁移方案,此轮不再测试。