1.数据库的分区技术
1.1 分区的概念
数据库的分区技术,主要解决海量的数据存储与查询问题。
提高数据库查询效率方法:
1、使用索引技术
2、使用缓存技术
上述两种方法存在缺陷:数据量非常大时不好处理
当 MySQL 数据库一个表的数据量远超过 1000W + 时,会影响服务器的性能吗?
答案:会影响
解决方案:
1、分库分表
2、分区
3、在上述的基础之上,使用索引 + 缓存技术
4、全文检索引擎技术(暂时跟这里无关)
《阿里巴巴的编码规范》推荐单表数据超过 500W,或者文件的容量超 2G,就需要分库分表,或者分区
分区:将一个表从物理上进行拆分成多个文件进行存储,但是从逻辑上来/或者从视图上来看,只有一张表。
1.2 分区有哪些技术?
现在几乎所有的关系型数据都提供了分区技术,但是 mysql 是从 5.1 开始才提供的。它是借鉴 Oracle 分区技术实现的。
Range 分区
基于给定连续区间的列值进行分区,例如:按照员工的工号(no)进行分区,1-10 一个区间,10-20 一个区间,20-40 一个区间,40-……区间
List 分区
基于离散值集合的列值进行分区,例如:存储学生,按照学院的教室编号(no)进行分区,[1,5,8] 在一个区间, [2,4,6]在一个区间,[3,7,9]在一个区间……
Hash 分区
基于估计区间个数的一种分区技术,例如:存储学生,固定的分为:10 个区间,使用学生的学号与 10 进行取余,余数是几就放置在哪个分区文件中
Key 分区
类似于按照 HASH 分区,区别在于 KEY 分区只支持计算一列或多列,且 MySQL 服务器提供自身的哈希函数(例如:密码函数 password()),它还可以操作字符串(性能非常的差,不推荐)
一个区间就对应着一个物理文件
目前来讲,使用最多的是前 3 种分区技术
1.3 分区的具体实现
Rage 分区的实现
使用场景:假设现在有一张表,该表用于保存有 20 家分公司的所有职工数据,
这 20 家分公司编号分别从 1 到 20,如果想要分配到 4 个分区,则需要使用如下的语句
CREATE TABLE t_emps (
id bigint not null auto_increment,
store_id int not null,
user_name varchar(20) null,
job_no int not null,
hired date not null,
remark varchar(200) null,
constraint PK_T_EMPLOYEES primary key clustered (id,store_id)
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (5),
PARTITION p1 VALUES LESS THAN (10),
PARTITION p2 VALUES LESS THAN (15),
PARTITION p3 VALUES LESS THAN (20)
);
复制代码
MYSQL 官网上,要求分区字段为了提升查询效率,也必须添加主键约束
图片1.png
如果未来,我不知道需要开多少家分公司,那么使用可以 MaxValue 作为做大区间。
List 分区的实现
LIST 分区技术与 RANGE 分区技术很类似,只是它操作的不再是连续区间,而是具体的数值
应用场景:假设现在有一张表,该表用于保存有 20 家分公司的所有职工数据,这 20 家分公司编号分别从 1 到 20,如果要按照固定值进行分区,应该使用如下语句:
CREATE TABLE t_emps (
id bigint not null auto_increment,
store_id int not null,
user_name varchar(20) null,
job_no int not null,
hired date not null,
remark varchar(200) null,
constraint PK_T_EMPLOYEES primary key clustered (id,store_id)
)
PARTITION BY LIST (store_id) (
PARTITION p0 VALUES IN (1,2,4,5,6),
PARTITION p1 VALUES IN (3,7,8,9,10),
PARTITION p2 VALUES IN (11,12,13,14,15,16),
PARTITION p3 VALUES IN (17,18,19,20)
);
复制代码
store_id 一定是一个能够参与计算的值,可以是:YEAR(hired)
Hash 分区的实现
使用将要插入到表中的这些行的列值进行计算
应用场景:假设现在有一张表,该表用于保存有 20 家分公司的所有职工数据,
这 20 家分公司编号分别从 1 到 20,如果按照入职时间来进行分区,入职时间是不可预
订的,并且分区数已经固定为 4 个,则应该使用如下语句
CREATE TABLE t_emps (
id bigint not null auto_increment,
store_id int not null,
user_name varchar(20) null,
job_no int not null,
hired date not null,
remark varchar(200) null,
constraint PK_T_EMPLOYEES primary key clustered (id,hired)
)
PARTITION BY HASH(YEAR(hired))
PARTITIONS 4;
复制代码
计算规则:将入职的年份,与 4 进行取余,余数代表着 具体的分区
Key 分区的实现
KEY 分区技术与 HASH 分区技术相似,但是它的基准点可以不是整数类型,可以是如字符串等类型字段。如果放置一个字符串,MYSQL 内部就需要先经过一系列的运算,得到一个数值,然后,将该数值与 4 进行取余,余数就代表分区
CREATE TABLE t_emps (
id bigint not null auto_increment,
store_id int not null,
user_name varchar(20) not null,
job_no int not null,
hired date not null,
remark varchar(200) null,
constraint PK_T_EMPLOYEES primary key clustered (id,user_name)
)
PARTITION BY KEY(user_name)
PARTITIONS 4;
复制代码
1.4 分区的适用场景
2. 数据库的主从复制
2.1 主从复制的概念
大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够。到了数据业务层、数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器来处理如此多的数据库连接操作,数据库必然会崩溃,特别是数据丢失的话,后果更是不堪设想。这时候,我们会考虑如何减少数据库的连接,下面就进入我们今天的主题。
利用主从数据库来实现读写分离,从而分担主数据库的压力。在多个服务器上部署 mysql,将其中一台认为主数据库,而其他为从数据库,实现主 从同步。其中主数据库负责主动写的操作,而从数据库则只负责主动读的操作(slave 从数据库仍然会被动的进行写操作,为了保持数据一致性),这样就可以很大程度上的避免数据丢失的问题,同时也可减少数据库的连接,减轻主数据库的负载。
当连接不够时,解决连接的问题!!!
2.2 主从复制的方式
同步复制
所谓的同步复制,意思是 master 的变化,必须等待 slave-1,slave-2,...,slave-n 完成后才能返回。这样,显然不可取,也不是 MYSQL 复制的默认设置。比如,在 WEB 前端页面上,用户增加了条记录,需要等待很长时间。
异步复制
如同 AJAX 请求一样。master 只需要完成自己的数据库操作即可。至于 slaves 是否收到二进制日志,是否完成操作,不用关心。master 只保证 slaves 中的一个操作成功,就返回,其他 slave 不管。这个功能,是由 google 为 MYSQL 引入的。
2.3 主从复制的原理
整个主从复制的核心:binary.log
注意:从库异步读取主库的变化,不是主库同步向从库推
缺点:应用程序在获取实时性比较高的数据时,可能拿到手上的数据有延迟。所以如果对于实时性比较高的,建议还是从主库获取
2.4 主从复制的目标
1、数据热备,及时备份
2、读写分离,减轻主库的连接压力
2.5 主从赋值的实现
注意:下列操作使用到了 docker 相关知识
准备 3 台数据库
默认情况,mysql 数据库是没有开启 “二进制日志”的,如果需要开启,就需要手动配置
使用如下命令,开启一个 mysql 的容器:
docker run --name mysql01 -p 3306:3306 -v /root/mysql/data-3306:/var/lib/mysql -e MYSQLROOTPASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
复制代码
使用如下命令,从容器中复制 my.cnf 到宿主机:
docker cp mysql01:/usr/local/mysql/my.cnf /usr/local/my.cnf
复制代码
使用 docker stop mysql01 && docker rm mysql01 移除 mysql01 容器
分别修改 3 台数据库对应的配置文件
主节点 my.cnf 的模板
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
# 开启二进制日志记录功能
log-bin=mysql-bin
# 配置集群环境下的 服务ID(不能重复)
server-id=1
# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
复制代码
从节点 s1.cnf 的模板
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
# 开启二进制日志记录功能
log-bin=mysql-bin
# 配置集群环境下的 服务ID(不能重复)
server-id=2
# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
复制代码
从节点 s2.cnf 的模板
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
# 开启二进制日志记录功能
log-bin=mysql-bin
# 配置集群环境下的 服务ID(不能重复)
server-id=3
# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
复制代码
启动 3 台服务器
docker run --name mysql01 -p 3306:3306 -v /usr/local/my.cnf:/etc/mysql/my.cnf -v /root/mysql/data-3306:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
docker run --name mysql02 -p 3307:3306 --link mysql01:mysql01 -v /usr/local/s1.cnf:/etc/mysql/my.cnf -v /root/mysql/data-3307:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
docker run --name mysql03 -p 3308:3306 --link mysql01:mysql01 -v /usr/local/s2.cnf:/etc/mysql/my.cnf -v /root/mysql/data-3308:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
复制代码
开启成功的效果:
备注:
也可以在连接工具上,使用 show binary logs;查看二进制日志是否开启,数值越大的,内容越新。
如果要查看某一个具体文件的内容:可以使用 show binlog events in 'mysql-bin.000003'
主库授权
在主库的连接工具上,执行如下命令:
grant all on *.* to 'feiyu'@'%' identified by '123456';
flush privileges;
复制代码
执行之后,使用show master status
查看主库的最新状态
设置从库读取主库的位置
在从库的连接工具上,分别执行以下语句:
change master to masterhost='mysql01',masteruser='feiyu',masterpassword='123456',masterlog_file='mysql-bin.000003',master_logpos=1173,masterport=3306;
设置从库从哪里获取数据
master_host='mysql01'
主库的位置,一般配置 IP,但是 Docker 容器环境下,可以配置容器的名称
masteruser='feiyu',masterpassword='123456'
从库靠什么账号以及密码登录主库
masterlogfile='mysql-bin.000003',master_log_pos=1173
从库读取主库的哪一个二进制日志文件,从哪一个地方开始读取
master_port=3306
主库的端口号
开启主从复制
在从库的连接工具上,输入以下命令
start slave;
该命令即可开启主从复制
show slave status
查看主从复制是否开启成功
3. 数据库的分库分表
3.1 分库分表的概念
分表:就是将表进行拆分,垂直拆分法和水平拆分法
垂直拆分法:将一个大表中的字段拆分成多个不同的表,然后使用外键进行关联(我们在设计数据库采用的是“范式三原则”,已经实现过了,几乎拆无可拆) 不推荐
水平拆分法:将不同的数据,放置表结构相同的不同的表内部。
分库:同上,就是将数据库进行拆分,垂直拆分法以及水平拆分法
垂直拆分法:将一个数据库的不同的表,按照业务放置在不同的数据库,例如:电商系统拆分为:客户资料数据库,商品数据库,订单数据库,库存数据库,物流数据库……
水平拆分法:将表结构相同的表,拆分到不同的数据库中,例如:人口统计系统中:四川人资料库,河南人资料库,上海人资料库,青海人资料库……
总结一下:拆的原理如上,拆好拆,但是拆了以后不可避免的会出现:分布式事务问题,多个数据库源管理的问题,拆并不是只拆一次
3.2 MyCat 的概述
当业务非常复杂以后,数据库的拆分可能不可避免,多个数据库就需要有一个东西,可以统一管理,mycat 刚好合适。
数据库中间件:应用程序-中间件-数据库集群
myCat 的特点:
1、它给数据库集群提供了一个透明代理
2、它是 Java 语言开发的,调试和配置相对而言就非常的简单
3.3 MyCat 中的常见术语
数据库中间件:位于应用程序与数据库集群中的软件,就叫中间件
逻辑库(schema): 通过 mycat 显示给应用程序看的数据库
逻辑表(table): 显示在逻辑库中的表
分片表:使用的分片规则的逻辑表
不分片表:没有使用 rule=""分片规则的表,就是非分片表
分片节点:数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)
节点主机:数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。节点主机代表每一个单独的数据库!!
分片规则:前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。
3.4 MyCat 如何使用
使用docker search mycat
命令查询是否有 fify/mycat 镜像存在
使用docker pull fify/mycat
将该镜像下载到宿主机
3.4.1 准备 3 台数据库
docker run --name mysql10 -p 3310:3306 -v /root/mysql/data-3310:/var/lib/mysql -e MYSQLROOTPASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
docker run --name mysql11 -p 3311:3306 -v /root/mysql/data-3311:/var/lib/mysql -e MYSQLROOTPASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
docker run --name mysql12 -p 3312:3306 -v /root/mysql/data-3312:/var/lib/mysql -e MYSQLROOTPASSWORD=123456 -d daocloud.io/library/mysql:5.7.4
复制代码
并确保 3 台服务器都能正常运行!!!
3.4.2 进行数据库的准备
分表在 3 台 docker 容器上,创建 3 个不同的数据库
mysql10 ->db1
mysql11 ->db2
mysql12 ->db3
分表在 db1,db2,db3 执行以下语句
CREATE TABLE `t_goods` (
`id` bigint NOT NULL ,
`name` varchar(100) DEFAULT NULL,
`price` double DEFAULT NULL,
`type` varchar(100) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
`data` datetime DEFAULT NULL,
PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
复制代码
分表在 db1,db2 执行以下语句
CREATE TABLE `t_order` (
`id` bigint NOT NULL ,
`order_no` varchar(100) DEFAULT NULL,
`order_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
复制代码
3.4.3 MyCat 环境的准备
Mycat 的官网http://www.mycat.org.cn/上,下载 mycat 的安装包
下载的目录,不是为了安装,而是为了使用它的 conf 配置
3.4.4 配置 MyCat 集群
对于 Mycat 来讲,最重要的配置文件:
schema.xml 用来配置 mycat + mysql 的集群
server.xml 用来配置连接账号信息
配置 Server.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sequnceHandlerType">2</property>
<!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>-->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequnceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭
-->
<property name="useOffHeapForMerge">0</property>
<!--
单位为m
-->
<property name="memoryPageSize">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<!-- 配置应用程序连接 mycat 服务器的账号和密码-->
<!-- 请删除defaultAccount="true"-->
<user name="root" >
<property name="password">123456</property>
<property name="schemas">TESTDB</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">TESTDB</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
复制代码
配置 schema.xml 文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- schema 代表的是逻辑库,而table代表的是需要显示在该数据库中逻辑表-->
<!-- 逻辑库:表示需要显示给应用程序看的数据库
逻辑表:表示在逻辑库中,用户能看到的表
-->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!--rule="sharding-by-murmur" 分片规则 sharding-by-murmur Hash一致算法分片 -->
<table name="t_order" dataNode="dn1,dn2" primaryKey="id" rule="sharding-by-murmur" />
<!--rule="auto-sharding-long" 范围分片算法 id在 0-500M 在dn1节点上,id在500M-1000M
的在dn2节点上,id在1000M-1500M在dn3节点上
-->
<table name="t_goods" dataNode="dn1,dn2,dn3" primaryKey="id" rule="auto-sharding-long"/>
</schema>
<!-- dataNode 的节点,每一个节点都代表一个数据库-->
<!--dataHost 如果不是docker环境,请配置IP地址-->
<!--database 具体的物理库-->
<dataNode name="dn1" dataHost="mysql10" database="db1" />
<dataNode name="dn2" dataHost="mysql11" database="db2" />
<dataNode name="dn3" dataHost="mysql12" database="db3" />
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql10" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host1" url="mysql10:3306" user="root"
password="123456" />
</dataHost>
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql11" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host2" url="mysql11:3306" user="root"
password="123456" />
</dataHost>
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql12" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host3" url="mysql12:3306" user="root"
password="123456" />
</dataHost>
</mycat:schema>
复制代码
将配置文件上传至/usr/local/mycat 目录下
启动 mycat 容器
9066 为管理端口
8066 为数据端口
docker run --name mycat -d -p 9066:9066 -p 8066:8066 --link mysql10:mysql10 --link mysql11:mysql11 --link mysql12:mysql12 -v /usr/local/mycat/conf:/usr/local/mycat/conf/ fify/mycat:latest
--link mysql10:mysql10 链接命令,由于mycat的配置文件中使用到mysql10所以需要链接
复制代码
添加数据,并校验结果
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('1', '小米9', '3800', '数码产品', '河南', '2019-04-09 00:43:32');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('2', '苹果电脑', '15000', '数码产品', '成都', '2019-04-02 00:44:07');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('3', '长虹电吹风', '45', '家用电器', '北京', '2019-04-01 00:46:28');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('5000000', '苏泊尔电饭锅', '380', '家用电器', '北京', '2019-04-01 00:47:17');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('5000001', '火星人集成灶', '18000', '燃气灶具', '武汉', '2019-04-07 00:47:59');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('5000002', '蒙牛纯甄', '8','食品', '新疆', '2019-04-07 00:48:50');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('10000001', '原味道瓜子', '30', '食品', '成都', '2019-04-07 00:49:25');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('10000002', '冷吃兔', '45','食品', '自贡', '2019-04-01 00:49:44');
INSERT INTO t_goods (id,name,price,type,address,data) VALUES ('10000003', '张飞牛肉', '34', '食品', '南充', '2019-04-02 00:50:09');
INSERT INTO t_order (id,order_no,order_time) VALUES(1,'9527','2019-07-28');
INSERT INTO t_order (id,order_no,order_time) VALUES(2,'9528','2019-07-28');
INSERT INTO t_order (id,order_no,order_time) VALUES(5,'9528','2019-08-28');
INSERT INTO t_order (id,order_no,order_time) VALUES(500,'9529','2019-08-28');
复制代码
目前 t_goods 表使用的是 mycat 默认的分配策略,也就是根据 id 来进行分片的,1-5000000 被分配到第一张表,5000001-10000000 被分配到第二张表,10000001-15000000 被分配到第三张表。
t_order 表使用的是 mycat 哈希一致分配策略,也就是根据 id 的 Hash 值在 Hash 环上顺时针寻找距离最近的服务器节点,然后将数据进行存放
3.5 mycat 工作流程
Mycat 的原理并不复杂,复杂的是代码。Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
执行的流程为:
Orders 表被分为三个分片 datanode(简称 dn),这三个分片是分布在两台 MySQL Server 上(DataHost),即 datanode=database@datahost 式,因此你可以用一台到 N 台服务器来分片,分片规则为(sharding rule)典型的字符串枚举 分片规则,一个规则的定义是分片字段(sharding column) +分片函数(rule function),这里的 分片字段为 prov 而分片函数为字符串枚举方式。
以 select * from orders where prov=?语句为例,查到 prov=wuhan,按照分片函数,wuhan 返回 dn1,于是 SQL 就发给了 MySQL1,去取 DB1 上的查询结果,并返回给用户。
3.6 整合主从复制
修改 schema.xml 文件,配置主从复制
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- schema 代表的是逻辑库,而table代表的是需要显示在该数据库中逻辑表-->
<!-- 逻辑库:表示需要显示给应用程序看的数据库
逻辑表:表示在逻辑库中,用户能看到的表
-->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!--rule="sharding-by-murmur" 分片规则 sharding-by-murmur Hash一致算法分片 -->
<table name="t_order" dataNode="dn1,dn2" primaryKey="id" rule="sharding-by-murmur" />
<!--rule="auto-sharding-long" 范围分片算法 id在 0-500M 在dn1节点上,id在500M-1000M
的在dn2节点上,id在1000M-1500M在dn3节点上
-->
<table name="t_goods" dataNode="dn1,dn2,dn3" primaryKey="id" rule="auto-sharding-long"/>
<!--没有使用rule="" 分片规则的表,就是非分片表 -->
<table name="t_user" dataNode="dn4" primaryKey="id"/>
</schema>
<!-- dataNode 的节点,每一个节点都代表一个数据库-->
<!--dataHost 如果不是docker环境,请配置IP地址-->
<!--database 具体的物理库-->
<dataNode name="dn1" dataHost="mysql10" database="db1" />
<dataNode name="dn2" dataHost="mysql11" database="db2" />
<dataNode name="dn3" dataHost="mysql12" database="db3" />
<!-- 主从复制的节点-->
<dataNode name="dn4" dataHost="mysql01" database="woniu" />
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql10" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host1" url="mysql10:3306" user="root"
password="123456" />
</dataHost>
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql11" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host2" url="mysql11:3306" user="root"
password="123456" />
</dataHost>
<!-- dataHost 每个单独的数据库节点的详细配置-->
<dataHost name="mysql12" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host3" url="mysql12:3306" user="root"
password="123456" />
</dataHost>
<!-- dataHost 每个单独的数据库节点的详细配置-->
<!-- balance="1" 表示开启负载均衡,目的是为了:控制从多个从库中,读取数据-->
<dataHost name="mysql01" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!--配置写数据的规则-->
<!--url="mysql10:3306" 配置ip[容器的名称]:端口 用来mycat向 数据库写入数据-->
<!--user="root" password="123456" 用来mycat连接 mysql服务器的账号和密码-->
<writeHost host="host4" url="mysql01:3306" user="root"
password="123456" >
<!--配置数据读取规则-->
<readHost host="hostS1" url="mysql02:3306" user="root" password="123456" />
<readHost host="hostS2" url="mysql03:3306" user="root" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
复制代码
上传 schema.xml 到/usr/local/mycat/conf 下
开启 mycat,检验结果
docker run --name mycat -d -p 9066:9066 -p 8066:8066 --link mysql01:mysql01 --link mysql02:mysql02 --link mysql03:mysql03 --link mysql10:mysql10 --link mysql11:mysql11 --link mysql12:mysql12 -v /usr/local/mycat/conf:/usr/local/mycat/conf/ fify/mycat:latest
复制代码
评论