Mycat

数据分片概述

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

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.logmycat服务启动日志
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

读写分离

] vim server.xml
<user name="wordpress">
                <property name="password">wordpress</property>
                <property name="schemas">wordpress</property>
] vim schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

		<schema name="wordpress" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
        </schema>
        <dataNode name="dn1" dataHost="cluster1" database="db1" />
        <dataHost name="cluster1" 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.1.170:3306" user="root"
                                   password="123qqq...A">
                        <readHost host="hostS1" url="192.168.1.173:3306" user="root" password="123qqq...A" />
                        <readHost host="hostS2" url="192.168.1.174:3306" user="root" password="123qqq...A" />
                        <readHost host="hostS3" url="192.168.1.175:3306" user="root" password="123qqq...A" />
                </writeHost>
                <writeHost host="hostM2" url="192.168.1.171:3306" user="root"
                                   password="123qqq...A">
                </writeHost>
                <writeHost host="hostM3" url="192.168.1.172:3306" user="root"
                                   password="123qqq...A">
                </writeHost>
                <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
        </dataHost>
</mycat:schema>

sqlMaxLimit配置默认查询数量
database为真实数据库名
balance=“0”, 不开启读写分离机制,所有读操作都发送到当前可用的writeHost 上。
balance=“1”,全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1,S2 都参与 select 语句的负载均衡。
balance=“2”,所有读操作都随机的在 writeHost、 readhost 上分发。
balance=“3”, 所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有, 1.3 没有。
writeType=“0”, 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties .
writeType=“1”,所有写操作都随机的发送到配置的 writeHost。
writeType=“2”,没实现。
-1 表示不自动切换
1 默认值,自动切换
2 基于MySQL 主从同步的状态决定是否切换

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值