数据分片

数据分片

数据分片的目的

在分布式存储系统中,数据需要分散存储在多台设备上,数据分片就是用来确定数据在多台存储设备上分布的技术

  • 分布均匀: 即每台设备上的数据量要尽可能相近
  • 负载均衡:即每台设备上的请求量要尽可能相近
  • 扩缩容时产生的数据迁移尽可能少

数据库分割方式

  • 水平分割 (横向切分)
    • 按照表中指定字段的分片规则,将表记录按行切分,分散存储到多个数据库中
  • 垂直分割(纵向切分)
    • 将单个数据库的多个表按业务类型分类,分散存储到不同的数据库 不是切割表字段

mycat

mycat概述

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

  • 适合数据大量写入的存储需求
  • 支持Mysql、Oracle、Sqlserver、Mongdb等
  • 提供数据读写分离服务
  • 提供数据切片服务
  • 基于Cobar进行研发的开源软件

mycat分片规则

  • 枚举法 sharding-by-intfile
    • 给字段赋值时,值只能在规定的范围内选择 根据给定的字段值分片数据存储到哪个节点
  • 固定分片 rule1
  • 范围约定 auto-sharding-long
  • 求模法 mod-long
    • 给字段取模 分配到对应的节点服务器
  • 日期列分区法 sharding-by-date
  • 通配取模 sharding-by-pattern
  • ASCLL码求模通配 sharding-by-prefixpattern
  • 编程指定 sharding-by-substring
  • 字符串拆分hash解析 sharding-by-stringhash
  • 一致性hash sharding-by-murmur

mycat工作原理

收到一个SQL命令时

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

分片案例

前置准备
主机名角色数据库IP地址
user客户端192.168.4.50
db2分片服务器192.168.4.51
db3数据库服务器db1192.168.4.53
db4数据库服务器db2192.168.4.54
db5数据库服务器db3192.168.4.55
过程
#4.51 配置分片服务器
yum -y install java-1.8.0-openjdk  #mycat基于Java
which java;java -version   #确认安装和版本
/usr/bin/java 
openjdk version "1.8.0_161"                #版本对的
OpenJDK Runtime Environment (build 1.8.0_161-b14)   
OpenJDK 64-Bit Server VM (build 25.161-b14, mixed mode)

tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /usr/local/  #解压mycat源码包
ls /usr/local/mycat/
bin  catlet  conf  lib  logs  version.txt
#程序 复杂查询 配置文件  包  日志

mycat的server.xml rule.xml schema.xml log4j2.xml 四种配置文件的简述

  • server.xml
    • 配置系统参数
    • 配置用户访问权限
    • 配置SQL防火墙以及SQL拦截功能
  • rule.xml
    • 配置水平分片的分片规则
    • 配置分片规则对应的分配函数
  • schema.xml
    • 配置逻辑库及逻辑表
    • 配置逻辑表所存储的数据节点
    • 配置数据节点所对应的物理数据库服务器的信息
  • log4j2.xml
    • 配置日志展示的格式
    • 配置日志级别
    • 等等
#4.51
#配置mycat配置文件
vim /usr/local/mycat/conf/server.xml    #设置连接账号 测试不用修改啥
========================================
....
<user name="root">        #连接mycat服务时使用的用户名
     <property name="password">123456</property> #用户连接mycat用户时使用的密码
     <property name="schemas">TESTDB</property> #逻辑库名
</user>
<user name="user">
                <property name="password">user</property>
                <property name="schemas">TESTDB</property>
                <property name="readOnly">true</property>    #只读权限,连接mycat服务后只有读记录的权限,不写这一行则是可读可写    
</user>
....
===================================================


vim /usr/local/mycat/conf/rule.xml  #看看就好 没啥改的

#去除本次测试无关配置
cd /usr/local/mycat/conf/
wc -l schema.xml
77 schema.xml

sed -i '56,77d' /usr/local/mycat/conf/schema.xml    #先删除下面的 先删除上面的话 行号会变
sed -i '39,42d' /usr/local/mycat/conf/schema.xml
sed -i '16,18d' /usr/local/mycat/conf/schema.xml

wc -l schema.xml
48 schema.xml   #删除后为48

修改schema.xml

<!--4.51分片服务器操作-->
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">
            	<!--定义逻辑表属性 在哪个节点  使用上面分片规则-->
                <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
                <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
                <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
                <table name="hotnews"  dataNode="dn1,dn2,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>
        </schema>
		
    	<!--定义节点-->
        <dataNode name="dn1" dataHost="mysqla" database="db1" />
        <dataNode name="dn2" dataHost="mysqlb" database="db2" />
        <dataNode name="dn3" dataHost="mysqlc" database="db3" />
    
    	<!--节点信息-->
        <dataHost name="mysqla" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
            	<!--心跳-->
                <heartbeat>select user()</heartbeat>
            	<!--可读可写  如果内嵌readHost  就是定义读写分离-->
                <writeHost host="hostM1" url="192.168.4.53:3306" user="wangxiaoming"
                                   password="123456">
                <!--    <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> -->
                </writeHost>
        </dataHost>
        <dataHost name="mysqlb" 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="wangxiaoming"
                                   password="123456">
                <!--    <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> -->
                </writeHost>
        </dataHost>
        <dataHost name="mysqlc" 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="wangxiaoming"
                                   password="123456">
                <!--    <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> -->
                </writeHost>
        </dataHost>
</mycat:schema>
  • 小结

    • Mycat逻辑表table的九个属性介绍
      • name:对应实际的表名
      • dataNode:逻辑表所在的分片,该属性值需要和dataNode标签的name属性对应
      • rule:逻辑表使用的分片规则名称,规则在conf/rule.xml中配置,该属性值必须与tableRule标签中的name属性对应
      • ruleRequired:是否绑定分片规则,如果为true的话,就一定要配置true
      • primaryKey:逻辑表对应真实表的主键
      • type:逻辑表类型,分为全局表和普通表
      • autoincrement:是否启用自增主键,对应Mysql自增主键,默认时禁用
      • subTable:分表
      • needAddLimit:是否允许自动添加schema标签中设置的limit,默认为true
    • dataHost标签的balance属性
      • 值为0:不开启读写分离机制,所有读操作都发送到当前可用的writehost上
      • 值为1:全部的readhost与standby writehost参与select语句的负载均衡 都有
      • 值为2:所有读操作都随机的在writehost、readhost上分发
      • 值为3:所有读请求随机的分发到writehost对应的readhost执行 writehost不负担读压力,1.4版本及其之后才行

    配置数据库服务器 授权

    #4.53~55执行
    create database db1;    #53~55分别创建对应的数据库db1~db3  schema.xml对应的
    grant all on *.* to wangxiaoming@'%' identified by '123456'; #授权 三台都弄
    
    #可能会密码太简单无法设置
    set global validate_password_policy=0; #密码策略为0,只检查密码长度
    set global validate_password_length=6;  #最短为6
    

    测试授权用户是否成功

    #4.51分片服务器测试
    which mysql || yum -y install mariadb  #看看有没有mysql命令
    mysql -h192.168.4.53 -uwangxiaoming -p123456  #测试53~55
    

    启动服务

    #4.51启动服务   配置文件上面写好了
    /usr/local/mycat/bin/mycat start
    
    ss -nutlp | grep :8066  #查看服务端口是否成功启动
    tcp    LISTEN     0      100      :::8066                 :::*                   users:(("java",pid=108491,fd=76))
    
    ps -C java  #查看进程
       PID TTY          TIME CMD  
    108491 ?        00:00:02 java   #有了
    

    测试配置

    #4.50测试
    mysql -h192.168.4.51 -P8066 -uroot -p123456   #客户端访问分片服务器4.51:8066端口
    #这个root账户是分片服务器的server.xml里面配置的  不是mysql的
    
    mysql> show databases;    #查看下   发现有逻辑数据库TESTDB了
    +----------+
    | DATABASE |
    +----------+
    | TESTDB   |
    +----------+
    1 row in set (0.01 sec)
    
    mysql> use TESTDB
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    mysql> show tables;   #查看下   发现有逻辑表了
    +------------------+
    | Tables in TESTDB |
    +------------------+
    | company          |
    | customer         |
    | customer_addr    |
    | employee         |
    | goods            |
    | hotnews          |
    | orders           |
    | order_items      |
    | travelrecord     |
    +------------------+
    9 rows in set (0.00 sec)
    
    • 这个root账户是分片服务器的server.xml里面配置的 不是mysql的
    • 逻辑数据库在server.xml中定义
    • 逻辑表在schema.xml中定义

分片规则案例

延续上面案例

枚举法 sharding-by-intfile
vim /usr/local/mycat/conf/rule.xml
==================================
<tableRule name="sharding-by-intfile">
                <rule>
                        <columns>sharding_id</columns>  #数据分片字段名
                        <algorithm>hash-int</algorithm> #使用的函数名
                </rule>
</tableRule>
<function name="hash-int" #算法名
                class="io.mycat.route.function.PartitionByFileMap"> #支持类型
                <property name="mapFile">partition-hash-int.txt</property> #函数调用的配置文件
</function>
===================================
#枚举法
#修改partition-hash-int.txt
find / -type f -name partition-hash-int.txt #找到位置

vim /usr/local/mycat/conf/partition-hash-int.txt
=============================================
10000=0		#sharding_id字段值为10000时,数据存储在节点dn1
10010=1		#sharding_id字段值为10010时,数据存储在节点dn2
10020=2     #sharding_id字段值为10020时,数据存储在节点dn3
=======================================================

/usr/local/mycat/bin/mycat stop
/usr/local/mycat/bin/mycat start   #重启服务

#测试  客户端4.50登录分片服务器  存入sharding_id值为上面三种的记录,再去三个节点服务器分别查看验证

本例子说明了:分片规则sharding-by-intfile定义在rule.xml 使用了hash-int算法,值列表文件为partition-hash-int.txt 里面左边值为字段值,右边是存储在哪个对应的服务器

求模法 mod-long
vim /usr/local/mycat/conf/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">
                <property name="count">3</property> #指定求模数字为3
</function>
=================================================

/usr/local/mycat/bin/mycat stop
/usr/local/mycat/bin/mycat start   #重启服务

#测试  客户端4.50登录分片服务器  存入id值取余0~2的记录,再去三个节点服务器分别查看验证

分片建表案例

创建表数据 延续上面

#4.50
mysql -h192.168.4.51 -uroot -p123456 -P8066
	
	use TESTDB
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

	show tables;   
+------------------+
| Tables in TESTDB |
+------------------+
| company          |
| customer         |
| customer_addr    |
| employee         |
| goods            |
| hotnews          |
| orders           |
| order_items      |
| travelrecord     |
+------------------+
9 rows in set (0.00 sec)

	desc employee
ERROR 1146 (42S02): Table 'db1.employee' doesn't exist   #不存在  重复多次  随机访问db1~3   上面设置了balance=0
	
	#创建employee表   其中字段值要符合分片规则(schema.xml里面的table标签内容)
	create table employee(ID int primary key auto_increment, sharding_id int,
		name char(10), sex enum('boy','girl'));   
	
	desc employee  #查看
+-------------+--------------------+------+-----+---------+----------------+
| Field       | Type               | Null | Key | Default | Extra          |
+-------------+--------------------+------+-----+---------+----------------+
| ID          | int(11)            | NO   | PRI | NULL    | auto_increment |
| sharding_id | int(11)            | YES  |     | NULL    |                |
| name        | char(10)           | YES  |     | NULL    |                |
| sex         | enum('boy','girl') | YES  |     | NULL    |                |
+-------------+--------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
#表有了


#查看下53~55上面是否有
mysql -uroot -p  -e 'desc db1.employee'   #查看对应数据库里面是否有employee表
+-------------+--------------------+------+-----+---------+----------------+
| Field       | Type               | Null | Key | Default | Extra          |
+-------------+--------------------+------+-----+---------+----------------+
| ID          | int(11)            | NO   | PRI | NULL    | auto_increment |
| sharding_id | int(11)            | YES  |     | NULL    |                |
| name        | char(10)           | YES  |     | NULL    |                |
| sex         | enum('boy','girl') | YES  |     | NULL    |                |
+-------------+--------------------+------+-----+---------+----------------+



#4.50插入记录    字段名不能省略  因为不是真实数据库 必须值对应字段名 上面看流程
insert into employee(sharding_id,name,sex) values(10000,'xiaoming',1);
insert into employee(sharding_id,name,sex) values(10010,'lansi',1);
insert into employee(sharding_id,name,sex) values(10020,'liuli',2);
Query OK, 3 rows affected (0.00 sec)

#没有指定9999字段值  所以报错了
insert into employee(sharding_id,name,sex) values(9999,'chunli',2);
ERROR 1064 (HY000): can't find any valid datanode :EMPLOYEE -> SHARDING_ID -> 9999


#分别取三个节点数据库查询  因为sharding_id分片规则指定字段是枚举法
#53
select * from employee;
+----+-------------+----------+------+
| ID | sharding_id | name     | sex  |
+----+-------------+----------+------+
|  1 |       10000 | xiaoming | boy  |
+----+-------------+----------+------+

#54
select * from employee;
+----+-------------+-------+------+
| ID | sharding_id | name  | sex  |
+----+-------------+-------+------+
|  1 |       10010 | lansi | boy  |
+----+-------------+-------+------+

#55
select * from employee;
+----+-------------+-------+------+
| ID | sharding_id | name  | sex  |
+----+-------------+-------+------+
|  1 |       10020 | liuli | girl |
+----+-------------+-------+------+

#枚举分布式存储

mod-long建表

#4.50
mysql -h192.168.4.51 -P8066 -uroot -p123456
use TESTDB;
create table hotnews(id int, title char(30), worker char(10), comment char(100));

#4.53~55查询表结构
desc hotnews
+---------+-----------+------+-----+---------+-------+
| Field   | Type      | Null | Key | Default | Extra |
+---------+-----------+------+-----+---------+-------+
| id      | int(11)   | YES  |     | NULL    |       |
| title   | char(30)  | YES  |     | NULL    |       |
| worker  | char(10)  | YES  |     | NULL    |       |
| comment | char(100) | YES  |     | NULL    |       |
+---------+-----------+------+-----+---------+-------+


#4.50插入数据  字段名不能省略  因为不是真实数据库 必须值对应字段名 上面看流程
insert into hotnews(id,title,worker,comment) values(7,'a','a','aaa');
insert into hotnews(id,title,worker,comment) values(11,'a','a','aaa');
insert into hotnews(id,title,worker,comment) values(9,'a','a','aaa');


#4.53~55验证查询
#4.53
select * from hotnews;
+------+-------+--------+---------+
| id   | title | worker | comment |
+------+-------+--------+---------+
|    9 | a     | a      | aaa     |    # 9 % 3 = 0
+------+-------+--------+---------+

#4.54
select * from hotnews;
+------+-------+--------+---------+
| id   | title | worker | comment |
+------+-------+--------+---------+
|    7 | a     | a      | aaa     |   # 7 % 3 = 1
+------+-------+--------+---------+

#4.55
select * from hotnews;
+------+-------+--------+---------+
| id   | title | worker | comment |
+------+-------+--------+---------+
|   11 | a     | a      | aaa     |  # 11 % 3 = 2
+------+-------+--------+---------+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值