分库分表--理论和实践

什么是分区??

将一个表分解成多个区块进行操作和保存,从而降低每次操作的数据,提高性能。

从逻辑上看只有一个表,但在五路上这个表可能是由多个分区组成。

分区能干什么??

分割数据能够有多个不同 的物理路径

可以存储更多的数据;

提高每个分区的读写速度;

涉及sum和count等聚合操作,可以很容易的进行并行运算。

分区类型

range分区:基于一个给定连续区间的列值,将多行分配给分区

list分区:

hash分区:基于定义的表达式的返回值来进行选择分区

key分区:类似于hash分区,由mysql服务器提供其自身的哈希函数

创建分区

1、range分区

2、list分区

3、hash分区

指定被分区的表将要分割成的分区数量

4、key分区


为什么要分库分表??

主从复制+读写分离,可以实现数据高可用,但是无法解决大规模的并发写入问题(innodb的行锁),且单台服务器由于资源的限制导致数据库能承载的数据量和数据处理能力不高。

分库分表的优点

减少增量数据写入时锁对查询的影响;

常见的查询减少了需要扫描的记录,使得单表查询所需要的的检索行数变少,减少了磁盘IO;

解决磁盘系统最大文件的限制;

什么是分库

分库也叫“垂直切分”,就是把原本存储于一个库的表拆分存储在多个库上。通常是将表按照功能模块、关系密切程度划分出来,部署在不同的库上。如果数据库是因为表太多造成海量数据,并且项目的各项业务逻辑划分清晰、低耦合,则首选是分库。

分库的优点:实现简单;

分库的缺点:不利于跨库操作,例如不能对两个库的表进行表连接

什么是分表

分表也叫“水平切分”,就是按照一定的业务规则或逻辑,将一个表的数据拆分成多份,分别存储在多个表结构一样的表中;这多个表可以存在一到多个库中。分表也分“垂直切分”和“水平切分”。

垂直分表

将本来存在一个表的内容,人为划分成多个表。

水平分表

也称“数据分片”。是把一个表复制成同样表结构的不同表,然后把数据按照一定的规则划分,分别存储到这些表,从而保证单表的容量不会太大提升性能。(推荐:单表数据量不能超过500W)

水平分表原理及思路:

导航规则---根据不同的情况,将相同的sql导向不同的库或者表。

基本实现思路:

1、解析路由:

根据业务功能或sql的解析,获得需要访问的数据源及访问的表

2、分别在数据源和表上去执行sql

3、如果涉及到返回结果集的话,就需要做结果集的合并,并按照需要进行二次处理,例如排序、分页

4、如果需要事务的话,就要考虑是使用分布式事务,还是自行实现两阶段提交,或者采用补偿性业务处理的方式

可实现的层面:

水平分表的实现难点:

水平分表的实现面临一系列问题,例如:切分策略、库节点路由、表路由、全局主键生产、跨界店排序、分组、分页、表管理、多数据源事务处理、数据库扩容等。

使用mycat实现mysql分库分表

mycat介绍

mycat是一个开源的分布式数据库系统,是一个实现了mysql协议的服务器。

前端用户可以把它看做一个数据库代理。后端可以用mysql原生协议与多个mysql服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信。

核心是分库分表,即将一个大表水平切分成N个小表。

https://www.toutiao.com/a6603492496779510276/?tt_from=mobile_qq&utm_campaign=client_share&timestamp=1549497188&app=news_article&utm_source=mobile_qq&iid=59568063679&utm_medium=toutiao_android&group_id=6603492496779510276

搭建mycat

  1. 下载mycat
    http://mycat.sourceforge.net/
  2. 安装及修改配置文件
    下载好安装包,解压即可

原理图:

例如使用mycat实现对test1表进行水平分表,分别把数据存储到192.168.0.3(2个节点)和192.168.0.4(1个节点)的节点上

术语:

schema逻辑库:

    mycat中定义的database ,逻辑上存在的,物理上不存在 。主要针对纵向切分提供的概念。

table逻辑表:

   Mycat 中定义的 table.是逻辑上存在,物理上是不存在的. 主要是针对横向切分提供的概念

dataHost数据主机:

   物理 MySQL 存放的主机地址.可以使用主机名,IP,域名定义.

dataNode数据节点:

    配置物理的 database. 数据保存的物理节点.就是 database.

分片规则:

     即控制数据如何访问物理 database 和 table.

配置mycat

Mycat分为3个重要的配置文件,分别为 schema.xml server.xml rule.xml

1、shema.xml

设置  整体的schema拆分任务+节点配置信息+表拆分信息+底层mysql登录信息

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

--schema任务配置

    <schema name="mycat" checkSQLschema="false" sqlMaxLimit="1000">    

 --表test1 拆分的节点以及拆分规则

        <table name="test1" primaryKey="ID" dataNode="dn1,dn3,dn2" rule="auto-sharding-long"/>

 --表test2 拆分的节点以及拆分规则
        <table name="test2" primaryKey="ID"  dataNode="dn2,dn4" rule="rule1"/>

    
    </schema>

--节点信息配置   数据节点、数据主机

  <dataNode name="dn1" dataHost="192.168.0.3" database="db1" />  
    <dataNode name="dn2" dataHost="192.168.0.3" database="db2" />
    <dataNode name="dn3" dataHost="192.168.0.4" database="db3" />
    <dataNode name="dn4" dataHost="192.168.0.4" database="db4" />

      --底层mysql登录方式
    <dataHost name="192.168.0.3" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>

        <writeHost host="mysql1" url="192.168.0.3:3306" user="root"
                   password="123456">

        </writeHost>
    </dataHost>

  --底层mysql登录方式
        <dataHost name="192.168.0.4" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>

        <writeHost host="mysql2" url="192.168.0.4:3306" user="root"
                   password="123456">
        </writeHost>
    </dataHost>

</mycat:schema>

2、server.xml

此文件配置全局防火墙信息

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    <system>
        <!-- 1为开启实时统计、0为关闭 -->
        <property name="useSqlStat">0</property>  
        <!-- 1为开启全加班一致性检测、0为关闭 -->
        <property name="useGlobleTableCheck">0</property>  
        <property name="sequnceHandlerType">2</property>
        <property name="processorBufferPoolType">0</property>m-vy288c43d05418f4 
        <property name="handleDistributedTransactions">0</property>
        
        <!--off heap for merge/order/group/limit      1开启   0关闭-->
        <property name="useOffHeapForMerge">1</property>

        <!--单位为m -->
        <property name="memoryPageSize">1m</property>

        <!--单位为k-->
        <property name="spillsFileBufferSize">1k</property>

        <property name="useStreamOutput">0</property>

        <!--单位为m -->
        <property name="systemReserveMemorySize">384m</property>

        <!--是否采用zookeeper协调切换  -->
        <property name="useZKSwitch">true</property>
    </system>
    
 
    <firewall> 
       <whitehost>
          <host host="127.0.0.1" user="root"/>
          <host host="localhost" user="root"/>
       </whitehost>
       <blacklist check="false">
       </blacklist>
    </firewall>

    <user name="root">
        <property name="password">123456</property>
        <property name="schemas">mysql</property>
    </user>
        
</mycat:server>

3、rule.xml

此配置文件配置的是表的拆分规则,以及拆分规则底层文件配置,

分片规则:

https://www.cnblogs.com/756623607-zhang/p/6656022.html

<?xml version="1.0" encoding="UTF-8"?>
<--c language governing permissions and - limitations under the License. -->
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">

--表test1拆分规则配置
    <tableRule name="test1">
        <rule>
            <columns>ID</columns>
            <algorithm>rang-long</algorithm>
        </rule>
    </tableRule>

--表test2拆分规则配置

    <tableRule name="test2">
        <rule>
            <columns>ID</columns>
            <algorithm>func1</algorithm>
        </rule>
    </tableRule>

    <function name="murmur"
        class="io.mycat.route.function.PartitionByMurmurHash">
        <property name="seed">0</property>
        <property name="count">2</property>
        <property name="virtualBucketTimes">160</property>
        
    </function>

    <function name="crc32slot"
              class="io.mycat.route.function.PartitionByCRC32PreSlot">
        <property name="count">2</property>
    </function>
    <function name="hash-int"
        class="io.mycat.route.function.PartitionByFileMap">
        <property name="mapFile">partition-hash-int.txt</property>
    </function>

  <--范围约定--->
    <function name="rang-long"
        class="io.mycat.route.function.AutoPartitionByLong">
        <property name="mapFile">autopartition-long.txt</property>
    </function>

autopartition-long.txt

0-5000000=0

5000001-10000000=1

# range start-end ,data node index

# K=1000,M=10000.

0-500M=0

500M-1000M=1

1000M-1500M=2

0-10000000=0

10000001-20000000=1


 

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">3</property>
    </function>

    <function name="func1" class="io.mycat.route.function.PartitionByLong">
        <property name="partitionCount">8</property>
        <property name="partitionLength">128</property>
    </function>

固定分片hash算法

如果需要平均分配设置:平均分为4分片,partitionCount*partitionLength=1024

<function name="func1" class="org.opencloudb.route.function.PartitionByLong">

    <property name="partitionCount">4</property>

    <property name="partitionLength">256</property>

  </function>


   

<function name="latestMonth"
        class="io.mycat.route.function.LatestMonthPartion">
        <property name="splitOneDay">24</property>
    </function>
    <function name="partbymonth"
        class="io.mycat.route.function.PartitionByMonth">
        <property name="dateFormat">yyyy-MM-dd</property>
        <property name="sBeginDate">2015-01-01</property>
    </function>
    
    <function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
            <property name="mapFile">partition-range-mod.txt</property>
    </function>
    
    <function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
        <property name="totalBuckets">3</property>
    </function>
</mycat:rule>

4、底层mysql配置
Mysql需要授予mycat所在主机的登录权限

5、测试

(1)开启mycat

(2)在mycat所在主机登录mysql

(3)插入三条数据,在mycat 所在主机select会显示所有数据

由于test1表使用了“范围约定”拆分规则,则

192.168.0.3中结果如下:(1,aa),(5000000,aa)

192.168.0.4中结果如下  (500001,aa)

springboot整合mycat

猜你喜欢

转载自blog.csdn.net/qq_24271537/article/details/109561009