数据分片

数据分片概述

  • 把数据存储在不同的数据库服务器里
  • 适合数据存储比较多的业务场景
  • 存在瓶颈和单点故障问题

1)分库/分表

  • 将存放在一台数据库服务器中的数据,按照特定方式进行拆分,分散存放到多台数据库服务器中,以达到分散单台服务器负载的效果

在这里插入图片描述

2)水平分割

  • 横向切分:按照表中指定字段的分片规则,将表记录按进行切分,分散存储到多个数据库中
    在这里插入图片描述

3)垂直分割

  • 纵向切分:将单个数据库的多个表按业务类型分类,分散存储到不同的数据库
    在这里插入图片描述

MyCAT

MyCAT是基于JAVA的分布式数据库系统中间件,为高并发环境的分布式存储提供解决方案

  • 适合数据大量写入的存储需求
  • 支持MySQL/Oracle/Splserver/Mongodb等
  • 提供数据分片服务
  • 提供读写分离服务
  • 基于阿里Cobar进行研发的开源软件

分片规则:

  1. 枚举法 sharding-by-intfile
  2. 固定分片 rule1
  3. 范围约定 auto-sharding-long
  4. 求模法 mod-long
  5. 日期列分区法 sharding-by-date
  6. 统配求模 sharding-by-pattern
  7. ASCII码求模通配 sharding-by-prefixpattern
  8. 编程指定 sharding-by-substring
  9. 字符串拆分hash解析 sharding-by-stringhash
  10. 一致性hash sharding-by-murmur

工作过程:

  1. 解析SQL命令涉及到的表
  2. 查看对表的配置,如果有分片规则,则获取SQL命令里分片字段的值,并匹配分片函数,获得分片列表
  3. 将SQL命令发往对应的数据库服务器去执行
  4. 收集和处理所有分片结果数据,并返回到客户端

部署MyCAT

1)部署软件运行环境

yum -y install java-1.8.0-openjdk.x86_64

2)安装服务软件

tar -xvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz  #官网下载
mv mycat /usr/local/

目录结构:

名称 作用
bin/ mycat命令
catlet/ 扩展功能
conf/ 配置文件
lib/ mycat使用的jar包
logs/ mycat启动日志和运行日志
wrapper.log mycat服务启动日志
mycat.log 记录SQL脚本执行后的报错内容

conf目录文件:

文件 作用
server.xml 设置连接账号及逻辑库
schema.xml 配置数据分片存储的表
rule.xml 分片规则
其他文件 分片规则配置文件

3)修改配置文件

  • 配置用户:server.xml
vim /usr/local/mycat/conf/server.xml   <!--根据需要配置-->
    <user name="root">   <!--用户名-->
           <property name="password">123456</property>   <!--密码-->
           <property name="schemas">TESTDB</property>  <!--逻辑库名称-->
    </user>
  • 配置数据分片: schema.xml
配置字段 作用
<schema>…</schema> 定义分片信息
<table>…</table> 定义表
name 逻辑库名或逻辑表名
dataNode 指定数据节点
rule 指定使用的分片规则
type=global 数据不分片存储
sed -i '56,77d' /usr/local/mycat/conf/schema.xml
sed -i '39,42d' /usr/local/mycat/conf/schema.xml  #删除多余的注释,可以不删
vim /usr/local/mycat/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
		<!-- auto sharding by id (long) -->
		<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
             <!-- 设置表的数据存储节点,使用哪个分片规则 -->
		<!-- global table is auto cloned to all defined data nodes ,so can join
			with any table whose sharding node is in the same data node -->
		<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
		<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />    
		<!-- random sharding using mod sharind rule -->
		<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
			   rule="mod-long" />
		<!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
			needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
			rule="mod-long" /> -->
		<table name="employee" primaryKey="ID" dataNode="dn1,dn2,dn3"
			   rule="sharding-by-intfile" />
		<table name="customer" primaryKey="ID" dataNode="dn1,dn2,dn3"
			   rule="sharding-by-intfile">
			<childTable name="orders" primaryKey="ID" joinKey="customer_id"
						parentKey="id">
				<childTable name="order_items" joinKey="order_id"
							parentKey="id" />
			</childTable>
			<childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
						parentKey="id" />
		</table>
		<!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
			/> -->
	</schema>
	<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
		/> -->
	<dataNode name="dn1" dataHost="mysql1" database="db1" />
	<!-- 一个dataNode定义一个节点 -->
	<!-- 节点名,节点主机名,存储数据的库 -->
	<dataNode name="dn2" dataHost="mysql2" database="db2" />
	<dataNode name="dn3" dataHost="mysql3" database="db3" />
	<!-- 使用dataHost定义节点ip -->
	<dataHost name="mysql1" 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="192.168.4.53:3306" user="root"
				   password="123qqq...A">
        <!-- 设置写主机名,ip,端口,用来连接数据库的用户,密码 -->
			<!-- can have multi read hosts -->
	 <!--   <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />  -->   
	 <!-- 不需要读写分离,注释掉readHost -->
		</writeHost>
	</dataHost>
	<dataHost name="mysql2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.4.54:3306" user="root"
                                  password="123qqq...A">
        </writeHost>
    </dataHost>
    <dataHost name="mysql3" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM3" url="192.168.4.55:3306" user="root"
                                   password="123qqq...A">
        </writeHost>
    </dataHost>
</mycat:schema>

4)配置数据库服务器

创建存储数据的库,授权用户,需要和schema.xml文件中的配置对应!

[root@mysql1] mysql -uroot -pPASSWORD
mysql> create database db1;
mysql> grant all on *.* to root@'%' identified by '123qqq...A';

[root@mysql2] mysql -uroot -pPASSWORD
mysql> create database db2;
mysql> grant all on *.* to root@'%' identified by '123qqq...A';

[root@mysql3] mysql -uroot -pPASSWORD
mysql> create database db3;
mysql> grant all on *.* to root@'%' identified by '123qqq...A';

5)启动MyCAT服务

默认端口:8066

[root@mycat] /usr/local/mycat/bin/mycat --help  #查看选项
[root@mycat] /usr/local/mycat/bin/mycat start  #启动
Mycat-server is running (1553).    #正常启动的输出信息

6)排错
启动失败:查找wrapper.log日志
数据读写错误:mycat.log日志

测试配置

存储数据:

建表:建表时表需要有使用分片规则的分片字段
[root@clinet] mysql -hMyCAT服务器ip -P8066 -uUSER -pPASSWORD
mysql> show databases;  #逻辑库,server.xml中定义
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+
1 row in set (0.00 sec)

mysql> use TESTDB
mysql> show tables;   #此处显示的为表名,在配置文件中定义了分片规则,需要create(创建字段),create时需要根据分片规则添加一个字段
+------------------+
| Tables in TESTDB |
+------------------+
| company          |
| customer         |
| customer_addr    |
| employee         |
| goods            |
| hotnews          |
| orders           |
| order_items      |
| travelrecord     |
+------------------+
9 rows in set (0.00 sec)

常用分片规则

1)sharding-by-intfile
  • 枚举法:字段值必须在规则文件定义的值里选择

以employee为例:

[root@mycat ~] cd /usr/local/mycat/conf
[root@mycat conf] vim schema.xml
  <table name="employee" primaryKey="ID" dataNode="dn1,dn2,dn3"
                           rule="sharding-by-intfile" />  
               #该表的分片规则为sharding-by-intfile
[root@mycat conf] vim rule.xml  #查找需要的字段名
<tableRule name="sharding-by-intfile">
      <rule>
             <columns>sharding_id</columns>   #字段名
             <algorithm>hash-int</algorithm>   #使用的算法,根据这个算法名在function词条中找到存放取值的文件
      </rule>
</tableRule>
...
<function name="hash-int"
       class="io.mycat.route.function.PartitionByFileMap">  #算法程序
       <property name="mapFile">partition-hash-int.txt</property>   #记录取值范围的文件
</function>

[root@mycat conf] vim partition-hash-int.txt
10000=0   #等号左边为sharding_id字段的值,右边数字对应数据节点0 -> dn1  
10010=1   #1 -> dn2 
10020=2   #添加此行,对应dn3
[root@mycat conf] ../bin/mycat restart   #重启服务应用配置文件

[root@clinet ~] mysql -hMyCAT服务器ip -P8066 -uUSER -pPASSWORD
mysql> create table employee (
    -> ID int primary key auto_increment,
    -> sharding_id int,  #根据查到的结果创建
    -> name varchar(15),
    -> sex enum('man','woman'),
    -> address varchar(50)
    -> );
mysql> insert into employee(sharding_id,name,sex,address)
    -> values(10000,"natasha","woman","usa");  #插入数据必须指定字段,不可省略
mysql> insert into employee(sharding_id,name,sex,address) 
    -> values(10020,"sarah","woman","usa");  #通过sharding_id字段的值指定该条信息存到哪个存储节点
mysql> insert into employee(sharding_id,name,sex,address) 
    -> values(10010,"bob","man","usa");
2)mod-long
  • 求模法:根据字段值与设定的数字求模结果存储数据

以hotnews为例:

[root@mycat ~] cd /usr/local/mycat/conf
[root@mycat conf] vim schema.xml
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
                  rule="mod-long" />
           #分片规则为mod-long
[root@mycat conf] vim rule.xml  #查找需要的字段名
<tableRule name="mod-long">
        <rule>
               <columns>id</columns>   #分片字段名,可以自定义
               <algorithm>mod-long</algorithm>  #算法
        </rule>  
</tableRule>
...
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
         <!-- how many data nodes -->
         <property name="count">3</property>  #有几个数据节点这个值设置为几
</function>
[root@mycat conf] ../bin/mycat restart   #重启服务应用配置文件

[root@clinet ~] mysql -hMyCAT服务器ip -P8066 -uUSER -pPASSWORD
mysql> create table hotnews ( 
    -> id int primary key auto_increment,
    -> title varchar(50), 
    -> author char(10)
    -> );
mysql> insert into hotnews(title,author) 
    -> values("NEWS","DZH");
附:自增长无法实现

方法1:多节点自增字段的处理

[root@mycat conf] vim server.xml
16     <property name="sequnceHandlerType">0</property>    
#数值为0表示从文件配置里获取自增字段,数值为1代表从数据库获取,数值为2代表从本地时间戳获取

方法2:
建表时自增长字段的字符类型设置为bigint,原因为默认自增字段的值从本地时间戳获取,值的大小超出了int的范围

添加新库新表

[root@mycat conf] vim server.xml   <!-- 添加新库 -->
<user name="root">
        <property name="password">123456</property>
        <property name="schemas">TESTDB,GAMEDB</property>
	    <!-- 写入新库名,以逗号分隔 -->
</user>

[root@mycat conf] vim schema.xml   <!-- 该文件内的表名不能够重复,即使不属于同一个库 -->
<schema name="GAMEDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- 添加新schema标签 -->
        <table name="gamedb_user" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
                           rule="sharding-by-intfile" />
        <table name="gamedb_pwd" primaryKey="ID" autoIncrement="true" type="global" dataNode="dn1,dn2,dn3" />
        <!-- type=global表示不使用分片,把数据复制保存到每一个数据节点 -->
</schema>

[root@mycat conf] ../bin/mycat restart
发布了81 篇原创文章 · 获赞 7 · 访问量 1198

猜你喜欢

转载自blog.csdn.net/weixin_45157506/article/details/103920532
今日推荐