Bootstrap

mycat2使用

安装部署

下载1:mycat2-install-template-1.21.zip

下载2:mycat2-1.21-release-jar-with-dependencies.jar

解压mycat2-install-template-1.21.zip

unzip mycat2-install-template-1.21.zip

把mycat2-1.21-release-jar-with-dependencies.jar放在mycat/lib中

修改mycat/conf/datasources/prototypeDs.datasource.json配置文件

{
    "dbType":"mysql",
    "idleTimeout":60000,
    "initSqls":[],
    "initSqlsGetConnection":true,
    "instanceType":"READ_WRITE",
    "maxCon":1000,
    "maxConnectTimeout":3000,
    "maxRetryCount":5,
    "minCon":1,
    "name":"prototypeDs",
    "password":"Q61@t6Udu8mW",
    "type":"JDBC",
    "url":"jdbc:mysql://192.168.202.150:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
    "user":"mysteel",
    "weight":0
}

进入到mycat/bin目录,执行以下命令对文件分配权限

chmod 777 ./*

服务启动

./mycat start

客户端进行连接

默认的端口是8066,可以在mycat/conf/server.json中修改

默认的用户名密码是root/123456,可以在mycat/conf/user/root.user.json中修改

此时整体架构图为:

配置逻辑库

mycat默认有个集群,在mycat/conf/clusters/prototype.cluster.json中配置

{
    "clusterType":"MASTER_SLAVE",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetry":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "prototypeDs"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH"
}

默认有两个逻辑库:information_schema,mysql,在mycat/conf/schemas下面配置

当我们在mycat中操作information_schema,mysql逻辑库下面的表时候实际在操作原型库中表

现在让我们来配置新的业务逻辑库(逻辑库的名称要和原型库的名称一致

在客户端执行:

/*+ mycat:createSchema{
    "customTables":{},
    "globalTables":{},
    "normalTables":{},
    "schemaName":"yc_nacos",
    "shardingTables":{},
    "targetName":"prototype"
} */;

会在mycat/conf/schemas目录下自动创建yc_nacos.schema.json文件,并且自动把逻辑库中的逻辑表和原型库中的真实表进行映射

多数据源整合

提供跨数据源的复 杂查询分析能力,实现跨源的数据关联与聚合

创建mysql数据源:

/*+ mycat:createDataSource{
"dbType":"mysql",
"name":"yc-mysql",
"url":"jdbc:mysql://192.168.201.68:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"admin_user",
"password":"mOoBzUHGtqeX"
} */;

配置逻辑库:

/*+ mycat:createSchema{
    "customTables":{},
    "globalTables":{},
    "normalTables":{},
    "schemaName":"oem_mysteel",
    "shardingTables":{},
    "targetName":"yc-mysql"
} */;

oem_mysteel逻辑库下面的mysteel_data_3逻辑表对应的数据源是:192.168.202.150:3306

yc_nacos逻辑库下面的users逻辑表对应的数据源是:192.168.201.68:3306

不同数据源下面的表可以通过mycat进行联合查询

读写分离

在两个数据源(192.168.202.150:3306,192.168.201.68:3306)分别创建master_slave数据库,及在数据库下创建travelrecord表

CREATE database master_slave;
CREATE TABLE master_slave.`travelrecord` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` varchar(100) DEFAULT NULL,
  `traveldate` date DEFAULT NULL,
  `fee` decimal(10,0) DEFAULT NULL,
  `days` int DEFAULT NULL,
  `blob` longblob,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

创建集群:

/*! mycat:createCluster{"name":"prototype","masters":["prototypeDs"],"replicas":["yc-mysql"]} */;

创建逻辑表关联集群

/*+ mycat:createSchema{
    "customTables":{},
    "globalTables":{},
    "normalTables":{},
    "schemaName":"master_slave",
    "shardingTables":{},
    "targetName":"prototype"
} */;

查看集群状态:

/*+ mycat:showClusters{} */;

现在prototypeDs,yc-mysql两个数据源都可以读,我们改成只允许prototypeDs写,yc-mysql读,要修改两个地方

1、修改prototypeDs中的instanceType属性值为WRITE

{
    "dbType":"mysql",
    "idleTimeout":60000,
    "initSqls":[],
    "initSqlsGetConnection":true,
    "instanceType":"WRITE",
    "maxCon":1000,
    "maxConnectTimeout":3000,
    "maxRetryCount":5,
    "minCon":1,
    "name":"prototypeDs",
    "password":"Q61@t6Udu8mW",
    "type":"JDBC",
    "url":"jdbc:mysql://192.168.202.150:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
    "user":"mysteel",
    "weight":0
}

2、修改集群中BALANCE_ALL改成BALANCE_ALL_READ

{
    "clusterType":"MASTER_SLAVE",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "showLog":false,
        "slaveThreshold":0.0
    },
    "masters":[
        "prototypeDs"
    ],
    "maxCon":2000,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "replicas":[
        "yc-mysql"
    ],
    "switchType":"SWITCH"
}

readBalanceType:查询负载均衡策略

BALANCE_ALL(默认值):获取集群中所有数据源

BALANCE_ALL_READ:获取集群中允许读的数据源

BALANCE_READ_WRITE:获取集群中允许读写的数据源,但允许读的数据源优先

BALANCE_NONE:获取集群中允许写数据源,即主节点中选择

switchType

NOT_SWITCH:不进行主从切换

SWITCH:进行主从切换

配置重启之后:

当前主库prototypeDs中master_slave下面的travelrecord数据为:

当前从库yc-mysql中master_slave下面的travelrecord数据为:

现在在mycat客户端插入user_id为1000的数据:

insert into travelrecord(user_id)values ("1000");

此时主库prototypeDs中master_slave下面的travelrecord数据为:

此时从库yc-mysql中master_slave下面的travelrecord数据为:

现在在mycat客户端查询master_slave下面的travelrecord表数据为:

达到了在master_slave(prototypeDs)主库写,master_slave(yc-mysql)从库读的效果

配置prototypeDs,yc-mysql主从同步

可以查看https://yangcai.blog.csdn.net/article/details/122124151这个帖子

此时架构图为:

分库分表

创建数据源,因为我只准备了两个mysql库

/*+ mycat:createDataSource{
"dbType":"mysql",
"name":"m1",
"url":"jdbc:mysql://192.168.201.68:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"admin_user",
"password":"mOoBzUHGtqeX"
} */;
/*+ mycat:createDataSource{
"dbType":"mysql",
"name":"m2",
"url":"jdbc:mysql://192.168.202.150:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"mysteel",
"password":"Q61@t6Udu8mW"
} */;

在mycat/conf/datasources下面会创建m1.datasource.json m2.datasource.json两个文件

创建两个集群:

/*! mycat:createCluster{"name":"c0","masters":["m1"],"replicas":[]} */;
/*! mycat:createCluster{"name":"c1","masters":["m2"],"replicas":[]} */;

在mycat/conf/clusters下面会创建c0.cluster.json c1.cluster.json两个文件

注意:mycat分库分表默认选择的集群名称的规则是c${targetIndex},targetIndex是从0开始计算的

在mycat客户端创建分库分表逻辑库:

create database   sub_base_table;

在mycat/conf/schemas下面会创建sub_base_table.schema.json

在逻辑库下面创建分片表:

CREATE TABLE sub_base_table.`travelrecord` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` varchar(100) DEFAULT NULL,
  `traveldate` date DEFAULT NULL,
  `fee` decimal(10,0) DEFAULT NULL,
  `days` int DEFAULT NULL,
  `blob` longblob,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
)  ENGINE = INNODB DEFAULT CHARSET = utf8 dbpartition BY mod_hash ( user_id ) tbpartition BY mod_hash(id)tbpartitions 2 dbpartitions 2 ;

在sub_base_table.schema.json中的内容为:

{
    "customTables":{},
    "globalTables":{},
    "normalProcedures":{},
    "normalTables":{},
    "schemaName":"sub_base_table",
    "shardingTables":{
        "travelrecord":{
            "createTableSQL":"CREATE TABLE sub_base_table.`travelrecord` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`user_id` varchar(100) DEFAULT NULL,\n\t`traveldate` date DEFAULT NULL,\n\t`fee` decimal(10, 0) DEFAULT NULL,\n\t`days` int DEFAULT NULL,\n\t`blob` longblob,\n\tPRIMARY KEY (`id`),\n\tKEY `id` (`id`)\n) ENGINE = INNODB CHARSET = utf8\nDBPARTITION BY mod_hash(user_id) DBPARTITIONS 2\nTBPARTITION BY mod_hash(id) TBPARTITIONS 2",
            "function":{
                "properties":{
                    "dbNum":"2",
                    "mappingFormat":"c${targetIndex}/sub_base_table_${dbIndex}/travelrecord_${tableIndex}",
                    "tableNum":"2",
                    "tableMethod":"mod_hash(id)",
                    "storeNum":2,
                    "dbMethod":"mod_hash(user_id)"
                }
            },
            "shardingIndexTables":{}
        }
    },
    "views":{}
}

此时m1,m2数据源就会创建分库分表,规则就是sub_base_table_${dbIndex}/travelrecord_${tableIndex},sub_base_table和targetIndex是从0开始计算的

此时架构图为:

全局表

如果项目中有一些数据类似字典常量等字段,这种数据一般数据量不会很大,而且改动也比较少,通常这种表可以不需要进行拆分,把它当做全局表进行处理,每个分片都创建一张相同的表,在所有的分片上都保存一份数据。在进行插入、更新、删除操作时,会将sql语句发送到所有分片上进行执行,在进行查询时,也会把sql发送到各个节点。这样避免了跨库JOIN操作,直接与本分片上的全局表进行聚合操作。

特性:

全局表的插入、更新、删除等操作会实时在所有节点上执行,保持各个分片的数据一致性;

全局表的查询操作,随机从一个节点上进行;

全局表可以跟任何一个表进行 JOIN 操作

在mycat客户端sub_base_table逻辑库执行:

CREATE TABLE sub_base_table.`user_config` (
`user_id` varchar(100)  NOT NULL ,
`user_name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;

此时sub_base_table.schema.json中的内容为:

{
    "customTables":{},
    "globalTables":{
        "user_config":{
            "broadcast":[
                {
                    "targetName":"c0"
                },
                {
                    "targetName":"c1"
                }
            ],
            "createTableSQL":"CREATE TABLE sub_base_table.`user_config` (\n\t`user_id` varchar(100) NOT NULL,\n\t`user_name` varchar(100) DEFAULT NULL,\n\tPRIMARY KEY (`user_id`)\n) BROADCAST ENGINE = InnoDB CHARSET = utf8"
        }
    },
    "normalProcedures":{},
    "normalTables":{},
    "schemaName":"sub_base_table",
    "shardingTables":{
        "travelrecord":{
            "createTableSQL":"CREATE TABLE sub_base_table.`travelrecord` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`user_id` varchar(100) DEFAULT NULL,\n\t`traveldate` date DEFAULT NULL,\n\t`fee` decimal(10, 0) DEFAULT NULL,\n\t`days` int DEFAULT NULL,\n\t`blob` longblob,\n\tPRIMARY KEY (`id`),\n\tKEY `id` (`id`)\n) ENGINE = INNODB CHARSET = utf8\nDBPARTITION BY mod_hash(user_id) DBPARTITIONS 2\nTBPARTITION BY mod_hash(id) TBPARTITIONS 2",
            "function":{
                "properties":{
                    "dbNum":"2",
                    "mappingFormat":"c${targetIndex}/sub_base_table_${dbIndex}/travelrecord_${tableIndex}",
                    "tableNum":"2",
                    "tableMethod":"mod_hash(id)",
                    "storeNum":2,
                    "dbMethod":"mod_hash(user_id)"
                }
            },
            "shardingIndexTables":{}
        }
    },
    "views":{}
}

则在m1,m2中的sub_base_table物理库中都会创建user_config表

普通表

就是常规表

CREATE TABLE sub_base_table.`user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

此时sub_base_table.schema.json中的内容为:

{
    "customTables":{},
    "globalTables":{
        "user_config":{
            "broadcast":[
                {
                    "targetName":"c0"
                },
                {
                    "targetName":"c1"
                }
            ],
            "createTableSQL":"CREATE TABLE sub_base_table.`user_config` (\n\t`user_id` varchar(100) NOT NULL,\n\t`user_name` varchar(100) DEFAULT NULL,\n\tPRIMARY KEY (`user_id`)\n) BROADCAST ENGINE = InnoDB CHARSET = utf8"
        }
    },
    "normalProcedures":{},
    "normalTables":{
        "user":{
            "createTableSQL":"CREATE TABLE sub_base_table.`user` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`name` varchar(100) DEFAULT NULL,\n\tPRIMARY KEY (`id`)\n) ENGINE = InnoDB CHARSET = utf8",
            "locality":{
                "schemaName":"sub_base_table",
                "tableName":"user",
                "targetName":"prototype"
            }
        }
    },
    "schemaName":"sub_base_table",
    "shardingTables":{
        "travelrecord":{
            "createTableSQL":"CREATE TABLE sub_base_table.`travelrecord` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`user_id` varchar(100) DEFAULT NULL,\n\t`traveldate` date DEFAULT NULL,\n\t`fee` decimal(10, 0) DEFAULT NULL,\n\t`days` int DEFAULT NULL,\n\t`blob` longblob,\n\tPRIMARY KEY (`id`),\n\tKEY `id` (`id`)\n) ENGINE = INNODB CHARSET = utf8\nDBPARTITION BY mod_hash(user_id) DBPARTITIONS 2\nTBPARTITION BY mod_hash(id) TBPARTITIONS 2",
            "function":{
                "properties":{
                    "dbNum":"2",
                    "mappingFormat":"c${targetIndex}/sub_base_table_${dbIndex}/travelrecord_${tableIndex}",
                    "tableNum":"2",
                    "tableMethod":"mod_hash(id)",
                    "storeNum":2,
                    "dbMethod":"mod_hash(user_id)"
                }
            },
            "shardingIndexTables":{}
        }
    },
    "views":{}
}

普通表默认指向的集群是prototype,在prototypeDs-sub_base_table中会创建user表

ER表

基于E-R关系进行分片,子表的记录与其关联的父表的记录保存在同一个分片上,这样关联查询就不需要跨库进行查询,要注意的是无需指定ER表,是自动识别的,两表的分片算法一致就可以了

如:travel是travelrecord的附属表

CREATE TABLE sub_base_table.`travel` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `u_id` varchar(100) DEFAULT NULL,
  `travel` date DEFAULT NULL,
   PRIMARY KEY (`id`)
)  ENGINE = INNODB DEFAULT CHARSET = utf8 dbpartition BY mod_hash(u_id) tbpartition BY mod_hash(id) tbpartitions 2 dbpartitions 2 ;

此时sub_base_table.schema.json中的内容为:

{
    "customTables":{},
    "globalTables":{
        "user_config":{
            "broadcast":[
                {
                    "targetName":"c0"
                },
                {
                    "targetName":"c1"
                }
            ],
            "createTableSQL":"CREATE TABLE sub_base_table.`user_config` (\n\t`user_id` varchar(100) NOT NULL,\n\t`user_name` varchar(100) DEFAULT NULL,\n\tPRIMARY KEY (`user_id`)\n) BROADCAST ENGINE = InnoDB CHARSET = utf8"
        }
    },
    "normalProcedures":{},
    "normalTables":{
        "user":{
            "createTableSQL":"CREATE TABLE sub_base_table.`user` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`name` varchar(100) DEFAULT NULL,\n\tPRIMARY KEY (`id`)\n) ENGINE = InnoDB CHARSET = utf8",
            "locality":{
                "schemaName":"sub_base_table",
                "tableName":"user",
                "targetName":"prototype"
            }
        }
    },
    "schemaName":"sub_base_table",
    "shardingTables":{
        "travelrecord":{
            "createTableSQL":"CREATE TABLE sub_base_table.`travelrecord` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`user_id` varchar(100) DEFAULT NULL,\n\t`traveldate` date DEFAULT NULL,\n\t`fee` decimal(10, 0) DEFAULT NULL,\n\t`days` int DEFAULT NULL,\n\t`blob` longblob,\n\tPRIMARY KEY (`id`),\n\tKEY `id` (`id`)\n) ENGINE = INNODB CHARSET = utf8\nDBPARTITION BY mod_hash(user_id) DBPARTITIONS 2\nTBPARTITION BY mod_hash(id) TBPARTITIONS 2",
            "function":{
                "properties":{
                    "dbNum":"2",
                    "mappingFormat":"c${targetIndex}/sub_base_table_${dbIndex}/travelrecord_${tableIndex}",
                    "tableNum":"2",
                    "tableMethod":"mod_hash(id)",
                    "storeNum":2,
                    "dbMethod":"mod_hash(user_id)"
                },
                "ranges":{}
            },
            "partition":{
                
            },
            "shardingIndexTables":{}
        },
        "travel":{
            "createTableSQL":"CREATE TABLE sub_base_table.`travel` (\n\t`id` bigint NOT NULL AUTO_INCREMENT,\n\t`u_id` varchar(100) DEFAULT NULL,\n\t`travel` date DEFAULT NULL,\n\tPRIMARY KEY (`id`)\n) ENGINE = INNODB CHARSET = utf8\nDBPARTITION BY mod_hash(u_id) DBPARTITIONS 2\nTBPARTITION BY mod_hash(id) TBPARTITIONS 2",
            "function":{
                "properties":{
                    "dbNum":"2",
                    "mappingFormat":"c${targetIndex}/sub_base_table_${dbIndex}/travel_${tableIndex}",
                    "tableNum":"2",
                    "tableMethod":"mod_hash(id)",
                    "storeNum":2,
                    "dbMethod":"mod_hash(u_id)"
                }
            },
            "shardingIndexTables":{}
        }
    },
    "views":{}
}

当执行以下sql的时候的就避免了跨库join,跨库join查询的性能非常慢

select * from sub_base_table.`travel`  a  INNER JOIN  sub_base_table.`travelrecord` b on a.u_id = b.user_id 

查看配置的表是否具有ER关系,使用

/*+ mycat:showErGroup{}*/

group_id表示相同的组,该组中的表具有相同的存储分布

多租户

https://yangcai.blog.csdn.net/article/details/123971201

常见问题

1、由于数据源更换为mycat后,tinyint(1)后查询数据异常,实际查询数据库数据是正常的。

解决方式:

1.增加tinyint字段的长度且大于1

2.数据库连接增加配置tinyInt1isBit=false

建议使用第二种.

;