垂直切分
按照业务对数据表分类,然后把一个数据库拆分多个独立的数据库。比如一个电商系统中拆分为网站系统和仓库系统。
作用
垂直切分可以把数据库的并发压力分散到不同的数据库节点;
缺点
- 数据切分并不能减少单表的数据量;
- 不能跨MySQL节点做表连接查询,只能通过接口请求;
- 跨节点的事务需要用分布式事务机制来完成
水平切分
按照某个字段的某种规则,把数据切分到多张数据表。
缺点
- 不同的数据表切分规则不一致,要根据实际的业务来确定;
- 集群扩容较为麻烦,需要迁移大量的数据。
冷热数据分离
添加新的分片,硬件成本和时间成本很大,所以需要慎重;
可以对分片数据做冷热数据分离,把冷数据移除分片来缩表。
先垂直切分还是水平切分
按照实际出发,如果是从一个小项目慢慢演进的,从几千的活跃用户到几万的用户,可以先采用水平切分,因为设计改动程序部分的比较少,引入MyCat中间件,定时归档数据还是可以吃得住的。
如果做一个项目,预先定义的目标就是几十万的用户,那么就先考虑垂直切分了,因为负载高,需要分摊数据到不同的服务器。
安装、配置MyCat中间件
保存了水平切分的规则,直接可以切分和整合数据。
下载地址:http://www.mycat.org.cn/
安装Openjdk8
docker pull adoptopenjdk/openjdk8
docker tag adoptopenjdk/openjdk8 openjdk8
docker rmi adoptopenjdk/openjdk8
创建mycat容器
docker run -d -it --name mycat1 -v mycat1:/root/server --privileged --net=host openjdk8
开放端口
8066:做数据处理,执行的SQL是传到这个端口
9066:获取MyCat状态信息
firewall-cmd --zone=public --add-port=8066/tcp --permanent
firewall-cmd --zone=public --add-port=9066/tcp --permanent
firewall-cmd --reload
下载MyCat并上传到容器对应的数据卷路径下,并进行解压
配置MyCat
MyCat配置文档:http://www.mycat.org.cn/document/mycat-definitive-guide.pdf
配置PXC集群负载均衡
为了高可用,需要配饰两个MyCat,第二个MyCat处于待机的状态,当第一个宕机之后才会启用。
MyCat中主要的三个配置文件:
server.xml:配置MyCat的端口,全局主键的生成方式,虚拟的逻辑库和虚拟的账户。
schema.xml:配置数据库连接,数据表采用怎么样的数据切分规则。
rule.xml:定制数据切分的规则
MyCat运行的时候会把自己虚拟成MySQL数据库,包括虚拟的逻辑库和数据表。
配置server.xml
到MyCat的路径下,修改server.xml
配置schema.xml
读写分离
- 数据库中间件把读写任务分别发送给不同节点,可以降低单一节点的负载;
- PXC集群不需要设置读写分离,做负载均衡即可;
- Replication集群主从节点功能明确,需要做读写分裂。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"password="123456">
</writeHost>
</dataHost>
dataHost 这个配置是可以配置集群的
name:集群别名,随便取
maxCon,minCon:连接池的最大连接数和最小连接数
balance:0表示不使用读写分离,所有的读写请求都发送给写节点
writeType:1表示读写请求随机发送给可用的节点
dbType:mysql代表的是配置的是mysql集群
dbDriver:mycat自带的数据库驱动
switchType:1代表mycat会使用自己的心跳监测结果去判断那个节点宕机了
slaveThreshold:100表示如果从库的时间落后于主库的时间超过100秒就被剔除,mycat就不会从这个从节点读取数据
heartbeat:心跳监测执行的SQL语句,也可以更改,比如select 1,只要有返回响应就行,表示没有宕机
writeHost :配置MySQL节点,有多少节点就配置多少个writeHost 标签
host:自定义名称
url:节点地址+端口
user:节点的数据库登录账号
password:节点的数据库登录密码
配置的schema标签的name要跟server.xml中配置的名字一致,这里配置了两个PXC集群,第一个配置完之后就只需要复制一份,然后改一下对应的节点配。
配置Replication集群读写分离
1写3读
读节点需要嵌套在写节点中
<dataHost name="rep1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="r1w1" url="10.1.7.7:9003" user="root"
password="123456">
<readHost host="r1r1" url="10.1.7.10:9003" user="root"
password="123456" />
<readHost host="r1r2" url="10.1.7.13:9003" user="root"
password="123456" />
<readHost host="r1r3" url="10.1.7.14:9003" user="root"
password="123456" />
</writeHost>
</dataHost>
balance=“3”:3表示写节点和读节点是分开的,工作平行
配置虚拟逻辑库和关系表
MyCat并不存储数据,所以必须要配置可以使用的虚拟逻辑库和关系表
dataNode
逻辑库配置
MyCat不仅可以水平切分还可以垂直切分
<dataNode name="dn1" dataHost="pxc1" database="neti" />
<dataNode name="dn2" dataHost="pxc2" database="neti" />
<dataNode name="dn3" dataHost="rep1" database="neti" />
<dataNode name="dn4" dataHost="rep2" database="neti" />
<dataNode name="tdn1" dataHost="pxc1" database="t1" />
<dataNode name="tdn2" dataHost="pxc2" database="t1" />
<dataNode name="tdn3" dataHost="rep1" database="t2" />
<dataNode name="tdn4" dataHost="rep2" database="t2" />
接着就是为这些数据库节点来创建上面对应配置的数据库
PXC-pn1:neti、t1
PXC-pn5:neti、t1
Rep-rn1:neti、t2
Rep-rn5:neti、t2
其他的节点会自动同步主节点的表
schema 标签
虚拟逻辑库
schema标签中必须要有table
<schema name="t2" checkSQLschema="false" sqlMaxLimit="100" randomDataNode="dn1">
<table name="teacher" type="global" dataNode="tdn3,tdn4" />
<table name="student" rule="mod-long" dataNode="tdn3,tdn4" />
</schema>
checkSQLschema:true表示MyCat在执行SQL语句的时候会把SQL语句中逻辑库的名字去掉,直接使用表名;false反之
sqlMaxLimit:100表示每次查询最多返回100条数据
table:
name:虚拟表的名称
type:gobal表示这是全局表,不做水平切分;mod-long主键求模切分
dataNode:表放置的逻辑库位置
server.xml
把我们刚才增加的表给添加上
<property name="schemas">neti,t1,t2</property>
<user name="admin" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">neti,t1,t2</property>
<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
修改mod-long算法
可以修改mod-long的分片值,默认是3,可以修改为其他的数值。在rule.xml中找到,比如我是两个节点,就把3改为2。
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
启动MyCat
MyCat日志文件主要有console.log和mycat.log,存放在logs目录(老版本的mycat是没有logs文件,需要自己另外创建)。
需要给mycat文件夹下的bin文件夹下的.sh文件赋予可以执行权限
chmod -R 777 ./*.sh
运行mycat,在bin文件夹下执行
./startup_nowrap.sh
在初始化启动之后,虚拟逻辑库中是不存在真实的表的,需要进行SQL创建,不能用可视化工具创建。
CREATE TABLE teacher ( id INT UNSIGNED PRIMARY KEY, NAME VARCHAR ( 200 ) NOT NULL );
CREATE TABLE student ( id INT UNSIGNED PRIMARY KEY, NAME VARCHAR ( 200 ) NOT NULL );
往MyCat节点中t2数据库的teacher表写入数据,那就会把数据同步到Rep的所有节点上(因为在schemal.xml中配置了这两个集群);往student表中写入数据,会根据id进行分片保存,根据ID的模来进行两个分片的数据分发保存。
可以通过EXPLAIN查看数据同步到哪些节点上
Mycat全局主键
本地文件方式
MyCat按照计数器的方式自增长的主键值
计算数器的参数被保存在文本文档汇总
缺点
当MyCat宕机,备用MyCat无法读取宕机的MyCat当前的计数器,无法同步数据。
数据库方式
MyCat按照计数器的方式生成自增长主键值
计数器的参数被保存到数据库中
这种方式数据库是可以进行数据同步的,这样当一台宕机之后,另一台下的数据库是记录了当前计数器的值。
缺点
无论是使用PXC还是Replication都会有问题。
当使用PXC的时候,因为要同步所有的节点,当写的数据过多的时候,会导致压力过大。
当使用Replication的时候,如果写入数据过多,导致主节点宕机,从节点还没来得及同步,当第二个MyCat来生成主键的时候就导致了全局主键生成冲突。
本地时间戳
MyCat根据本地时间戳和机器ID,生成一个18位的主键值
缺点
因为生成的主键值都是偶数,所有无法用在主键求模切分规则上。
Zookeeper时间戳方式
利用Zookeeper生成时间戳主键值,主键字段必须使用bigint类型。
Zookeeper生成时间戳主键值包含奇数和偶数,可以用户主键值求模切分。
可以对Zookeeper建立集群,实现分布式生成主键值。
安装Zookeeper
下载镜像
docker pull zookeeper
启动容器
docker run -d --name z1 -p 2181:2181 -p 3888:3888 -p 2888:2888 --net=swarm_mysql zookeeper
配置ZK时间戳主键
编辑mycat的server.xml文件,修改:
<property name="sequnceHandlerType">3</property>
编辑myid.properties文件,配置参数信息
loadZk=true # 表示利用ZK去生成主键值
zkURL=10.1.7.7:2181 #ZK的地址
clusterId=mycat-cluster-1 # mycat集群的名字,自定义
myid=mycat_fz_01 # mycat主机的名字,自定义
clusterSize=1 # 集群节点数量
clusterNodes=mycat_fz_01 # 节点构成(引用myid的名字),如果有多个就用,隔开
热加载 mycat配置文件
一定要保证ZK容器正在运行,不然mycat会闪退
注意这里的MyCat-管理需要使用9066端口去访问
在mycat节点上运行
reload @@config_all;
使用下面两条其一就可以获取到生成的主键值
SELECT 'next value for MYCATSEQ_GLOBAL'
SELECT
NEXT
VALUE
FOR MYCATSEQ_GLOBAL