先介绍几个概念
1.数据库中间件
Mycat 是数据库中间件,就是介于数据库与应用之间,进行数据处理与交互的中间服 务。从原有的一个库,被切分为多个分片数据库,所有的分片数据库集群构成了整个完整的数据库存储。
2.逻辑库(schema)
对实际应用来说,并不需要知道中间件的存在,业务开发人员只需要知道数据库的概念, 所以数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。
3.逻辑表
既然有逻辑库,那么就会有逻辑表,分布式数据库中,对应用来说,读写数据的表就是逻辑表。逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。
4.分片表
分片表,是指那些原有的很大数据的表,需要切分到多个数据库的表,这样每个分片都有一部分数据,所有分片构成了完整的数据。
5.非分片表
一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。可以在多个节点允许重复,避免跨库操作。
6.ER 表
关系型数据库是基于实体关系模型(Entity-Relationship Model)之上,通过其描述了真实世界 中事物与关系,Mycat 中的 ER 表即是来源于此。根据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据 Join 不会跨库操作。
7.分片节点(dataNode)
数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。
8.节点主机(dataHost)
数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost), 为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
9.分片规则(rule)
一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务 规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。
目前使用mysql5.x的版本
Mycat安装步骤
1.上传mycat文件并解压,注意mycat需要基于jdk环境
2.拷贝mycat到/usr/local目录下
cp mycat/ /usr/local/ -rf
3.修改/etc/profile的环境配置文件,如下所示
JAVA_HOME=/usr/local/java
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME
export PATH
export CLASSPATH
export MYCAT_HOME=/usr/local/mycat
export PATH=$MYCAT_HOME/bin:$PATH
4.修改mycat所在虚拟机的host文件,添加一个地址映射
192.168.181.158 mycat
5.启动mycat,默认端口为8066,需要开启8066端口
mycat start
6.安装mysql数据库,这里至少装两个体现分库的作用
Mycat实现读写分离和水平分片
1.首先可以建立两个mysql数据库,其中一个在192.168.181.138上,主要用于数据的写入,还有一个在192.168.181.158上,用于数据的存储。当然根据实际业务可以进行增加。
2.在192.168.181.138的数据库中,建立三个库,比如名字为tao1,tao2,tao3,然后将表结构导入这三个数据库中,这样以后的数据将分布在这三个库中保存。
3.在192.168.181.158数据库中,重复步骤2,新建三个库为tao1,tao2,tao3,导入表结构。
4.修改mycat中的配置文件schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--schema声明虚拟库-->
<schema name="ego" checkSQLschema="true" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<!--table表示虚拟表 name表示虚拟表的名字 dataNode表示对应的数据库分片 rule表示分片规则,和rule.xml规则相匹配-->
<table name="tb_content_category" dataNode="dn1,dn2,dn3" rule="mod-long">
<!-- tb_content内容表
childTable : 声明er关系表,是tb_content_category的字表
name :子表的表名
primaryKey : 指定字表的主键
joinKey : 指定子表的外键
parentKey :子表外键,关联主表的哪一个列
-->
<childTable name="tb_content" primaryKey="id" joinKey="category_id" parentKey="id"/>
</table>
<!-- 声明商品类目表tb_item_cat -->
<table name="tb_item_cat" dataNode="dn1,dn2,dn3" rule="item_id_mod-long">
<!-- 商品表tb_item -->
<childTable name="tb_item" primaryKey="id" joinKey="cid" parentKey="id">
<!-- 配置tb_item_desc -->
<childTable name="tb_item_desc" primaryKey="item_id" joinKey="item_id" parentKey="id"/>
<!-- 配置tb_item_param_item -->
<childTable name="tb_item_param_item" primaryKey="id" joinKey="item_id" parentKey="id"/>
</childTable>
<!-- 商品规格参数模版表tb_item_param -->
<childTable name="tb_item_param" primaryKey="id" joinKey="item_cat_id" parentKey="id"/>
</table>
<!-- 配置tb_order -->
<table name="tb_order" dataNode="dn1,dn2,dn3" rule="mod-long">
<!-- tb_order_item 订单明细表-->
<childTable name="tb_order_item" primaryKey="id" joinKey="order_id" parentKey="order_id"/>
<childTable name="tb_order_shipping" primaryKey="order_id" joinKey="order_id" parentKey="order_id"/>
</table>
<!-- 声明用户信息表tb_user -->
<table name="tb_user" dataNode="dn1,dn2,dn3" rule="mod-long"/>
</schema>
<!--声明数据分片-->
<!--dataHost分片主机-->
<!--database分片对应的后台物理表-->
<dataNode name="dn1" dataHost="tao" database="tao1"/>
<dataNode name="dn2" dataHost="tao" database="tao2"/>
<dataNode name="dn3" dataHost="tao" database="tao3"/>
<!--配置物理分片主机-->
<!--balance=1表示写的主机空闲可以参与到读的主机中-->
<dataHost name="tao" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!--实现与后台主机之间的心跳检测-->
<heartbeat>select user()</heartbeat>
<!--声明写的主机-->
<writeHost host="node1" url="192.168.181.138:3306" user="root" password="root">
<!-- can have multi read hosts -->
<!--声明读的主机-->
<readHost host="node2" url="192.168.181.158:3306" user="root" password="root"/>
</writeHost>
<!--<writeHost host="hostS1" url="localhost:3316" user="root" password="123456"/>-->
</dataHost>
</mycat:schema>
这里tables中的表要根据自己的表设计去配置,childTable表示子表,它是跟着主表一起走的,避免跨库查询操作。
4.修改mycat中的配置文件server.xml,主要修改user
<user name="root">
<property name="password">123456</property>
<property name="schemas">ego</property>
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">ego</property>
<property name="readOnly">true</property>
</user>
5.重启mycat
实现主从同步
在写入数据的时候,需要在每一个分片中同步写入,即node1,node2中的数据要保持同步
1.在node1中和node2中配置hosts文件,两个文件都需要配置一下
192.168.181.138 node1
192.168.181.158 node2
2.修改 192.168.181.138(Master) 负责写入的mysql的my.cnf文件,比如使用yum安装方式该文件在/etc 下,然后添加两项内容
log_bin=mysqllog.bin
server-id=1
3.修改 192.168.181.158 的my.cnf文件,因为它是从数据库,只负责读取,所以只需要修改server-id=2
4.修改 192.168.181.138(Master) /var/lib/mysql/auto.cnf文件
server-uuid=aa886e0c-1bab-11e9-8ce4-000c296c4355 //把最后的5改为1
5.修改 192.168.181.158 /var/lib/mysql/auto.cnf文件 ,将最后的一个数字改为2
6.重启mysql的服务器
7.在192.168.181.138(Master)安装mysql-connector-python rpm和mysql-utilities rpm,解压。
rpm -ivh <mysql-connector-...rpm>
rpm -ivh <mysql-utilities-...rpm>
8.设置mysql(Master)复制的安全级别
set global validate_password_policy=0;
set global validate_password_length=6;
9.Master 执行 shell 脚本
mysqlreplicate --master=root:"root"@192.168.181.138:3306 --slave=root:"root"@192.168.181.158:3306 --rpl-user=root:"root"
配置主从mysql的所在ip,最后的账户是访问master的mysql的账户密码
当然如果有多个从mysql,那就执行多次命令即可
一个重要的坑
请使用mysql5.x的版本,mysql8.x的版本在使用mycat的时候会有一些问题。。
通过mycat插入数据请提供列名