【赵渝强老师】MySQL数据库的分库与分表

MySQL数据库目前得到了广泛的应用。在使用过程中会通过搭建MySQL主从复制的架构来提高性能,同时采用分库分表的模式来解决读写分离的问题。MySQL数据库的中间件就是为了更好地使MySQL支持这些应用的场景。主流的MySQL数据库中间件有ProxySQL、Mycat、Atlas和Cobar等等。引入了数据库中间件以后,客户端就不直接操作操作MySQL数据库集群,而是通过数据库中间件进行操作。

一、 Mycat简介与核心对象

Mycat是一个开源的分布式数据库系统,对于数据库用户而言可以把它看作是一个数据库代理。它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL 等主流的关系型数据库,同时也支持MongoDB等NoSQL数据库。Mycat的核心功能是实现数据库的分表分库。MyCat支持标准的SQL语句进行数据的操作,在降低了开发难度的同时提升了开发速度。Mycat可以通过使用MySQL原生协议与MySQL数据库服务器进行通信,并且Mycat基于Java语言开发,因此也可以用DBC协议与大多数主流数据库服务器通信。

视频讲解如下
【赵渝强老师】MySQL数据库的分库分表

下面列举了Mycat中的核心对象以及它们的含义:

  • 逻辑库:由于Mycat相当于是数据库的代理,因此Mycat作为数据库中间件其本身就可以被看做是一个或多个数据库集群构成的逻辑库。开发人员只需要面对该逻辑库进行开发即可。

  • 逻辑表:逻辑库由逻辑表组成。对于分布式数据库来说,客户端操作的就是逻辑表。逻辑表的数据来源是分布在后端一个或多个物理数据库。

  • 分片表:分片表是指将原有的大数据量表切分成多张表,其中的每一张表就是一个分片,其中均包含一部分数据。所有分片数据的合集构成了完整的表数据。

  • 非分片表:针对数据量小的表不需要进行分片,这些表就可以看成是非分片表。其实,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。

  • ER表:ER与关系型数据库中的实体关系模型是类似的,它可以将具有父子关系的表及其数据存放在同一个数据分片上,即子表依赖于父表。ER表通过表分组(Table Group)保证不会跨库操作。

  • 全局表:全局表类似数据库的数据字典。它里面的数据一般不会频繁变动,并且数据规模不大,通常数据量在十万以内。

  • 分片节点:将大数据量表进行切分后,每个表的分片所在的数据库服务器节点就是分片节点。因此,可以把一个数据库实例的服务器就理解成是一个分片节点。

  • 节点主机:每个分片节点(dataNode)不一定都会独占一台机器。在同一个物理主机上可以存在多个分片数据库实例。这样一个或多个分片节点(dataNode)所在的机器就是节点主机。

  • 分片规则:分片规则是指将大数据的表切分到多个数据分片的策略。分片表需要根据分片规则进行数据的切分。

  • 全局序列号:大数据量的表被切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用。为了保证数据具有唯一性的标识,从而引入全局序列号的机制。

下图展示了基于MyCat的MySQL分库分表的结构。

二、 安装部署Mycat

在了解到了Mycat的基本概念与核心对象后,下面通过具体的步骤在proxy的主机上部署Mycat环境。目前Mycat最新的版本是2.0,这里使用一个Mycat的稳定版本(1.6.7.5)来演示。

由于Mycat基于Java语言开发,因此在安装部署Mycat之前需要安装JDK。

(1)使用版本jdk-8u181-linux-x64.tar.gz安装Java运行环境。

powershell 复制代码
mkdir -p /root/training
tar -zxvf jdk-8u181-linux-x64.tar.gz -C /root/training

(2)编辑文件"/root/.bash_profile"设置Java的环境变量。

powershell 复制代码
JAVA_HOME=/root/training/jdk1.8.0_181
export JAVA_HOME

PATH=$JAVA_HOME/bin:$PATH
export PATH

(3)生效环境变量。

powershell 复制代码
source /root/.bash_profile

(4)验证Java环境。

powershell 复制代码
java -version

# 输出的信息如下:
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

(5)下载Mycat-server-1.6.7.5-release-20200410174409-linux.tar.gz安装包。

powershell 复制代码
wget \
http://dl.mycat.org.cn/1.6.7.5/2020-4-10/Mycat-server-1.6.7.5-release-20200410174409-linux.tar.gz

(6)将Mycat安装包解压到目录"/root/training"下。

powershell 复制代码
tar -zxvf \
    Mycat-server-1.6.7.5-release-20200410174409-linux.tar.gz \
    -C /root/training/

(7)编辑文件"/root/.bash_profile"设置Java的环境变量。

powershell 复制代码
export MYCAT_HOME=/root/training/mycat
export PATH=$MYCAT_HOME/bin:$JAVA_HOME/bin:$PATH

(8)生效环境变量。

powershell 复制代码
source /root/.bash_profile

(9)启动Mycat。

powershell 复制代码
mycat start

(10)查看Mycat的状态。

powershell 复制代码
mycat status

# 输出的信息如下:
Mycat-server is running (89121).

三、 使用Mycat实现分库分表

Mycat实现分库分表的核心是在于配置"/root/training/mycat/conf/schema.xml"文件和"/root/training/mycat/conf/rule.xml"文件。前者用于定义Mycat的逻辑库、逻辑表、分片节点和节点主机等信息;而后者主要定义分片的规则。下面通过具体的步骤来演示如何基于Mycat实现后端MySQL数据库的分库与分表。这里将使用mysql11、mysql12和mysql13三台MySQL服务器作为Mycat的后端节点。

(1)在mysql11、mysql12和mysql13上创建数据库"TESTDB",并在该库中创建一张员工表。

sql 复制代码
mysql> create database TESTDB;
mysql> use TESTDB;
mysql> create table emp
      (empno int primary key comment '员工号',
       ename varchar(10)  comment '员工姓名',
       job varchar(10) comment '员工职位',
       mgr int comment '员工老板的员工号',
       hiredate varchar(10) comment '员工的入职日期',
       sal int  comment '员工的月薪',
       comm int  comment '员工的奖金',
       deptno int comment '员工的部门号');

# 这里创建的数据库"TESTDB"也是Mycat默认的逻辑库名称。
# 在文件"/root/training/mycat/conf/schema.xml"中定义了该逻辑库的名称。
# 相关的定义如下:
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">

(2)在mysql11的后端数据库实例上插入10号部门的员工数据。

sql 复制代码
mysql> insert into emp values
       (7782,'CLARK','MANAGER',7839,'1981/6/9',2450,null,10),
       (7839,'KING','PRESIDENT',-1,'1981/11/17',5000,null,10),
       (7934,'MILLER','CLERK',7782,'1982/1/23',1300,null,10);

(3)在mysql12的后端数据库实例上插入20号部门的员工数据。

sql 复制代码
mysql> insert into emp values
      (7369,'SMITH','CLERK',7902,'1980/12/17',800,null,20),
      (7566,'JONES','MANAGER',7839,'1981/4/2',2975,null,20),
      (7788,'SCOTT','ANALYST',7566,'1987/4/19',3000,null,20),
      (7876,'ADAMS','CLERK',7788,'1987/5/23',1100,null,20),
      (7902,'FORD','ANALYST',7566,'1981/12/3',3000,null,20);

(4)在mysql13的后端数据库实例上插入30号部门的员工数据。

sql 复制代码
mysql> insert into emp values
      (7499,'ALLEN','SALESMAN',7698,'1981/2/20',1600,300,30),
      (7521,'WARD','SALESMAN',7698,'1981/2/22',1250,500,30),
      (7654,'MARTIN','SALESMAN',7698,'1981/9/28',1250,1400,30),
      (7698,'BLAKE','MANAGER',7839,'1981/5/1',2850,null,30),
      (7844,'TURNER','SALESMAN',7698,'1981/9/8',1500,null,30),
      (7900,'JAMES','CLERK',7698,'1981/12/3',950,null,30);

(5)编辑文件"/root/training/mycat/conf/server.xml"的内容。

xml 复制代码
......
<!-- 全局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"/>
      <!--增加下面的配置情况下对于192.168.79.*的主机都能以root账户登录-->
	  <host host="192.168.79.*" user="root"/>
   </whitehost>
<blacklist check="false">
</blacklist>
</firewall>

<user name="root" defaultAccount="true">
    <!--root账户登录的密码-->
	   <property name="password">123456</property>
    <!--root账户默认的逻辑库-->
	   <property name="schemas">TESTDB</property>
	   <property name="defaultSchema">TESTDB</property>
	......
</user>
......

(6)编辑文件"/root/training/mycat/conf/schema.xml"的内容,配置逻辑库的表信息与分片的信息。

xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!--定义逻辑库的名称是TESTDB-->
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
        <!--定义一张逻辑表emp,主键是empno-->
        <!--逻辑表emp的数据分片分别位于dn1,dn2,dn3的分片节点上-->
        <!--逻辑表emp的分片路由规则采用mod-long-->
        <table name="emp" primaryKey="empno" autoIncrement="true" 
               dataNode="dn1,dn2,dn3" rule="mod-long"/>
    </schema>
    
    <!--定义分片节点,并指定该分片节点上的分片数据库-->
    <dataNode name="dn1" dataHost="mysql11" database="TESTDB"/>
    <dataNode name="dn2" dataHost="mysql12" database="TESTDB"/>
	 <dataNode name="dn3" dataHost="mysql13" database="TESTDB"/>

    <!--定义节点主机-->
    <dataHost name="mysql11" maxCon="1000" minCon="10" balance="0" 
              writeType="0" dbType="mysql" dbDriver="native" 
              switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="mysql11" url="192.168.79.11:3306" 
                   user="root" password="Welcome_1">
        </writeHost>
    </dataHost>

    <!--定义节点主机-->
    <dataHost name="mysql12" maxCon="1000" minCon="10" balance="0" 
              writeType="0" dbType="mysql" dbDriver="native" 
              switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="mysql12" url="192.168.79.12:3306" 
                   user="root" password="Welcome_1">
        </writeHost>
    </dataHost>

    <!--定义节点主机-->
    <dataHost name="mysql13" maxCon="1000" minCon="10" balance="0" 
              writeType="0" dbType="mysql" dbDriver="native" 
              switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="mysql13" url="192.168.79.13:3306" 
                   user="root" password="Welcome_1">
        </writeHost>
    </dataHost>
</mycat:schema>

(7)修改文件"/root/training/mycat/conf/rule.xml"中定义分片路由规则。

xml 复制代码
......
<tableRule name="mod-long">
   <rule>
      <!--根据员工号empno进行分片路由-->
      <columns>empno</columns>
      <algorithm>mod-long</algorithm>
   </rule>
</tableRule>
......
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <!--由于有3个分片节点,因此采用3为进制的轮询算法进行分片路由-->
    <property name="count">3</property>
</function>
......

(8)重启Mycat。

powershell 复制代码
mycat restart

# 输出的信息如下:
Stopping Mycat-server...
Stopped Mycat-server.
Starting Mycat-server...

# 如果在启动的过程在wrapper.log日志文件中出现了下面的错误:
Startup failed: Timed out waiting for a signal from the JVM.

# 可以在conf/wrapper.conf文件增加下面的参数:
wrapper.startup.timeout=300

# 然后进入mycat的bin目录执行重启操作。
./mycat console 或者./mycat start

(9)借助MySQL的图形客户端工具"Navicat for MySQL"连接Mycat服务器。如下图所示。

(10)连接成功后,可以看到Mycat中存在一个逻辑库"TESTDB"和一张逻辑表"emp",如上图所示。

(11)查询逻辑表"emp"中的数据,这里返回的14条数据分别来自于后端的mysq11、mysql12和mysql13上的MySQL数据库实例。如下图所示。

(12)往逻辑表"emp"中插入3条新的数据,如下图所示。

sql 复制代码
mysql> insert into emp(empno,ename,sal,deptno) values(1,'Tom1',1000,10);
mysql> insert into emp(empno,ename,sal,deptno) values(2,'Tom2',1000,10);
mysql> insert into emp(empno,ename,sal,deptno) values(3,'Tom3',1000,10);

(13)直接在后端的mysq11、mysql12和mysql13上的MySQL数据库实例中查询员工表的数据。这时候会发现新插入的三条数据被存储在不同的节点上。如下图所示。

相关推荐
XDHCOM2 小时前
利用MSSQL解析优化数据库性能,提升效率,驱动业务创新与稳定发展
数据库·sqlserver
·云扬·2 小时前
MySQL分区实战指南:从原理到落地的完整攻略
数据库·mysql
雨墨✘2 小时前
PHP怎么执行Shell命令_exec与shell_exec区别说明【说明】
jvm·数据库·python
Trouvaille ~2 小时前
【MySQL篇】复合查询:多表数据的整合
数据库·sql·mysql·面试·复合查询·基础入门·多表连接
Project_Observer2 小时前
列表视图中的筛选列
大数据·数据库·深度学习·机器学习·深度优先
bukeyiwanshui2 小时前
20260414 正则表达式及shell三剑客
数据库·mysql·正则表达式
cyber_两只龙宝2 小时前
【Oracle】Oracle之SQL中的单行函数
linux·运维·数据库·sql·云原生·oracle
2201_756847332 小时前
mysql字段长度不够用了怎么办_使用alter table扩大varchar长度
jvm·数据库·python
aq55356002 小时前
Laravel4.x革命性升级:现代PHP开发新纪元
数据库·oracle