1 -【 MySQL 集群 】- 4 MyCat 分片集群分表分库策略

1 数据库集群会产生哪些问题?

  1. 自增 ID 问题
  2. 数据关联查询问题(水平拆分)
  3. 数据同步问题

2 数据库集群如何考虑数据库自增唯一性?

在数据库集群环境下,默认自增方式存在问题,因为都是从 1 开始自增,可能会存在重复,应该设置每台节点自增步长不同。

查询自增的步长:

SHOW VARIABLES LIKE 'auto_inc%'

修改自增的步长:

SET @@auto_increment_increment=10;

修改起始值:

SET @@auto_increment_offset=5;

假设有两台 mysql 数据库服务器:

  • 节点①自增 1 3 5 7 9 11 ….
  • 节点②自增 2 4 6 8 10 12 ….

注意:在最开始设置好了每台节点自增方式步长后,确定好了 mysql 集群数量后,无法扩展新的 mysql,不然生成步长的规则可能会发生变化。

推荐:使用 雪花算法redis 解决数据库自增唯一性

3 数据库分表分库策略

数据库分表分库原则遵循:垂直拆分水平拆分

垂直拆分:就是根据不同的业务,分为不同的数据库,比如会员数据库、订单数据库、支付数据库等,垂直拆分在微服务项目中用的非常常见。

  • 优点:拆分后业务清晰,拆分规则明确,系统之间整合或扩展容易。
  • 缺点:部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度,存在 分布式事务问题

水平拆分:是把同一个表拆到不同的数据库中。

  • 相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中,主要有 分表分库 两种模式。
  • 该方式 提高了系统的稳定性跟负载能力,但是跨库 join 性能较差。

4 使用 MyCat 实现水平分片策略

MyCat 支持 10 种分片策略:

  1. 求模算法
  2. 分片枚举
  3. 范围约定
  4. 日期指定
  5. 固定分片 hash 算法
  6. 通配取模
  7. ASCII 码求模通配
  8. 编程指定
  9. 字符串拆分 hash 解析

详细:http://www.mycat.io/document/mycat-definitive-guide.pdf

4.1 分片枚举 算法

分片枚举:根据不同的枚举(常量),进行分类存储。

这种规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国的省份区县固定的,这类业务使用这一规则。

配置如下:

  1. 案例步骤:创建数据库:userdb_1userdb_2userdb_3
  2. 修改 partition-hash-int.txt 规则
    wuhan=0
    shanghai=1
    suzhou=2
    

根据地区进行分库:湖北数据库、江苏数据库、山东数据库。

应用场景:根据地区进行查找数据等

配置步骤

1、创建三个数据库:

在这里插入图片描述

都创建表:

在这里插入图片描述

2、修改配置文件:

枚举配置文件:partition-hash-int.txt

wuhan=0
shanghai=1
suzhou=2

配置 分库分表 规则的文件:rule.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
 
    <tableRule name="role2">
             <rule>
                  <columns>name</columns> <!-- 根据数据库里面的 name 自动进行分片枚举 -->
                <algorithm>hash-int</algorithm>
                </rule>
    </tableRule>
	
	<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
		<property name="mapFile">partition-hash-int.txt</property> <!-- 指定枚举文件 -->
		<property name="type">1</property> <!-- 1表示非数值类型;0为数值类型 -->
		<property name="defaultNode">1</property> <!-- 默认存放路径为 1 -->
	</function>
	
</mycat:rule>

schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 -->
    <schema name="user_db" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
	 
	  <table name="user_info" dataNode="dn$1-3" rule="role2" /> 
	
	</schema>
        <!-- database 是MySQL数据库的库名 -->
    <dataNode name="dn1" dataHost="localhost1" database="user_db1" />
	<dataNode name="dn2" dataHost="localhost1" database="user_db2" />
	<dataNode name="dn3" dataHost="localhost1" database="user_db3" />
    <!--
    dataNode节点中各属性说明:
    name:指定逻辑数据节点名称;
    dataHost:指定逻辑数据节点物理主机节点名称;
    database:指定物理主机节点上。如果一个节点上有多个库,可使用表达式db$0-99,     表示指定0-99这100个数据库;

    dataHost 节点中各属性说明:
        name:物理主机节点名称;
        maxCon:指定物理主机服务最大支持1000个连接;
        minCon:指定物理主机服务最小保持10个连接;
        writeType:指定写入类型;
            0,只在writeHost节点写入;
            1,在所有节点都写入。慎重开启,多节点写入顺序为默认写入根据配置顺序,第一个挂掉切换另一个;
        dbType:指定数据库类型;
        dbDriver:指定数据库驱动;
        balance:指定物理主机服务的负载模式。
            0,不开启读写分离机制;
            1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡;
            2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡;
    -->
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <!-- 可以配置多个主从 -->
        <writeHost host="hostM1" url="192.168.153.101:3306" user="root" password="123456">
            <!-- 可以配置多个从库 -->
            <readHost host="hostS2" url="192.168.153.12:3306" user="root" password="123456" />
        </writeHost>
    </dataHost>
</mycat:schema>

server.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
   

   <!-- 读写都可用的用户 -->
    <user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">user_db</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">user_db</property>
        <property name="readOnly">true</property>
    </user>

</mycat:server>

测试

启动 MyCat

/usr/local/mycat/bin/mycat start

查看日志:

cat /usr/local/mycat/logs/wrapper.log

在这里插入图片描述

MyCat 连接中插入以下数据:

在这里插入图片描述

会按照之前的规则分别存到对应的数据库中,缺省的存在第一个数据库中。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

问题:如果查询时不按此字段查询,那么会扫描每个数据库

4.2 取模 算法

根据 id 进行十进制取模运算,运算结果为分区索引 。

注意:数据库节点分片数量无法更改,和 ES 集群非常相似的。

配置步骤

1、创建三个数据库:

在这里插入图片描述

都创建表:

在这里插入图片描述

2、修改配置文件:

配置 分库分表 规则的文件:rule.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
 
    <tableRule name="role2">
             <rule>
                  <columns>id</columns> <!-- 根据数据库里面的 id 自动进行分片 -->
                  <algorithm>mod-long</algorithm>
             </rule>
    </tableRule>
	
	<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
		<!--指定分片数量,不可以被更改-->
		<property name="count">3</property>
	</function>
	
</mycat:rule>

schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 -->
    <schema name="user_db" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
	 
	  <table name="user_info" dataNode="dn$1-3" rule="role2" /> 
	
	</schema>
        <!-- database 是MySQL数据库的库名 -->
    <dataNode name="dn1" dataHost="localhost1" database="user_db1" />
	<dataNode name="dn2" dataHost="localhost1" database="user_db2" />
	<dataNode name="dn3" dataHost="localhost1" database="user_db3" />
    
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <!-- 可以配置多个主从 -->
        <writeHost host="hostM1" url="192.168.153.101:3306" user="root" password="123456">
            <!-- 可以配置多个从库 -->
            <readHost host="hostS2" url="192.168.153.12:3306" user="root" password="123456" />
        </writeHost>
    </dataHost>
</mycat:schema>

server.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
   
    <!-- 读写都可用的用户 -->
    <user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">user_db</property>
    </user>

    <!-- 只读用户 -->
    <user name="user">
        <property name="password">user</property>
        <property name="schemas">user_db</property>
        <property name="readOnly">true</property>
    </user>

</mycat:server>

测试

启动 MyCat

/usr/local/mycat/bin/mycat start

查看日志:

cat /usr/local/mycat/logs/wrapper.log

在这里插入图片描述

插入以下数据:

在这里插入图片描述

可以看到在三个数据库中分别存储的为:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5 使用 MyCat 分表分库原理分析

修改 /usr/local/mycat/conf/log4j2.xml 日志级别为 debug

vi /usr/local/mycat/conf/log4j2.xml

在这里插入图片描述

查看日志:

tail -200f /usr/local/mycat/logs/mycat.log

执行下面的 SQL 语句:

在这里插入图片描述

日志:

在这里插入图片描述

执行下面的 SQL 语句:

在这里插入图片描述

日志:

在这里插入图片描述

Mycat 中的路由结果是通过分片字段和分片方法来确定的,如果查询条件中有 id 字段的情况还好,查询将会落到某个具体的分片。

如果查询没有分片的字段,会向所有的 db 都会查询一遍,然后封装结果集给客户端。

执行 LIMIT 查询:

所有数据:

在这里插入图片描述

SELECT * FROM user_info LIMIT 0,2

会向每个库都发送查询语句,会随机选择一条查询语句的结果:

在这里插入图片描述

在这里插入图片描述

由于每个数据库都有两条数据,所以会随机选择一个库中的数据做展示

执行下面语句:

SELECT * FROM user_info LIMIT 0,3

在这里插入图片描述

在这里插入图片描述

会先随机取一个库中的两条数据,再随机再其他两个数据库中拿取一条数据

执行 ORDER BY 查询:

SELECT * FROM user_info ORDER BY id LIMIT 0,3

在这里插入图片描述

发布了687 篇原创文章 · 获赞 229 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_42112635/article/details/105187107