乐趣区

关于数据库:MyCat学习笔记

Mycat 数据库中间件

1、数据库中间件

是一类连贯软件组件和利用的计算机软件,以便于软件各部件之间的沟通。例子:Tomcat,web 中间件。数据库中间件:连贯 java 应用程序和数据库

2、为什么要用 Mycat?

  • Java 与数据库紧耦合
  • 高访问量高并发对数据库的压力
  • 读写申请数据不统一

mysql 单表瓶颈 1000w 数据, 单库瓶颈 5000w 数据

数据库中间件比照:

Mycat 的官网: http://www.mycat.io/

Mycat 能干什么:

  • 读写拆散
  • 数据分片 垂直拆分(分库)、程度拆分(分表)、垂直 + 程度拆分(分库分表)
  • 多数据源整合

原理:

Mycat 的原理中最重要的一个动词是“拦挡”,它拦挡了用户发送过去的 SQL 语句,首先对 SQL 语句做了一些特定的剖析:如分片剖析、路由剖析、读写拆散剖析、缓存剖析等,而后将此 SQL 发 往后端的实在数据库,并将返回的后果做适当的解决,最终再返回给用户

装置启动

1、解压后即可应用 解压缩文件拷贝到 linux 下 /usr/local/ 2、三个配置文件

  • schema.xml:定义逻辑库,表、分片节点等内容
  • rule.xml:定义分片规定
  • server.xml:定义用户以及零碎相干变量,如端口等

3、批改配置文件 server.xml 批改用户信息,与 MySQL 辨别

<!– 用户名 –>
<user name=”root”>
<property name=”password”>123456</property>     <!– 明码 –>
<property name=”schemas”>TESTDB</property> <!– 治理的库 –>
</user>

schemas: 数据库名,这里会和 schema.xml 中的配置关联,多个用逗号离开,例如须要这个用户须要治理两个数据库 db1,db2,则配置 db1,db2

4. 批改配置文件 schema.xml

删除 <schema> 标签间的表信息配置 dataNode="dn1"<dataNode> 标签只留一个,<dataHost>标签只留一个,<writeHost>,<readHost>只留一对

<mycat:schema xmlns:mycat=”http://io.mycat/”>

<!– 逻辑库 –>
<schema name=”TESTDB” checkSQLschema=”false” sqlMaxLimit=”100″  dataNode=”dn1″>
<!– 逻辑表 –>
</schema>

<!– 数据节点 database 填写实在数据库 –>
<dataNode name=”dn1″ dataHost=”host1″ database=”testdb” />

<!– 数据主机 –>
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″  slaveThreshold=”100″>
<!– 心跳检测 –>
<heartbeat>select user()</heartbeat>
<!– 写主机 –>
<writeHost host=”hostM1″ url=”192.168.107.132:3306″ user=”root”
password=”000000″>
<!– 读主机 –>
<readHost host=”hostS2″ url=”192.168.107.108:3306″ user=”hzy” password=”000000″/>
</writeHost>

</dataHost>

</mycat:schema>

5. 验证数据库拜访状况

Mycat 作为数据库中间件要和数据库部署在不同机器上,所以要验证近程拜访状况。

mysql -uhzy -p000000 -h 192.168.107.108 -P 3306
mysql -uroot -p000000 -h 192.168.107.132 -P 3306

如近程拜访报错,请建对应用户

grant all privileges on . to root@’ 短少的 host’ identified by ‘000000’;

6. 启动 mycat

  • 控制台启动:去 mycat/bin 目录下执行 ./mycat console
  • 后盾启动:去 mycat/bin 目录下 ./mycat start

为了能第一工夫看到启动日志,不便定位问题,咱们抉择控制台启动。

7. 登录 mycat

  • 登录后盾治理窗口

此登录形式用于治理保护 Mycat

mysql -umycat -p123456 -P 9066 -h 192.168.140.128

常用命令如下:

show database;
show @@help;

  • 登录数据窗口

此登录形式用于通过 Mycat 查问数据,咱们抉择这种形式拜访 Mycat

mysql -uroot -p123456 -P 8066 -h 192.168.107.132

读写拆散

咱们通过 Mycat 和 MySQL 的 主从复制 配合搭建数据库的 读写拆散,实现 MySQL 的高可用性。咱们将搭建:一主一从、双主双从两种读写拆散模式。

mysql 主从复制原理:

与 redis 不同的是,redis 从机会把主机的数据从头到尾复制, 而 mysql 从机只会从接入点开始复制; 并且会产生屡次 IO 有延时问题

主机配置

批改配置文件:
vim /etc/my.cnf

主服务器惟一 ID

server-id=1

启用二进制日志

log-bin=mysql-bin

设置不要复制的数据库(可设置多个)

binlog-ignore-db=mysql
binlog-ignore-db=information_schema

设置须要复制的数据库

binlog-do-db= 须要复制的主数据库名字

设置 logbin 格局

binlog_format=STATEMENT

binlog 的三种模式:https://blog.csdn.net/vhomes/article/details/8082734

从机配置

vim /etc/my.cnf

从服务器惟一 ID

server-id=2

启用中继日志

relay-log=mysql-relay

  • 重启服务:systemctl restart mysqld
  • 确认防火墙已敞开:systemctl status firewalld
  • 在主机 MySQL 里执行受权命令: GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' IDENTIFIED BY '123123';

如果报错:Your password does not satisfy the current policy requirements, 请执行:

set global validate_password_policy=0;
set global validate_password_length=4;

  • 查看主机状态:
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB Executed_Gtid_Set
mysql-bin.000001 438 testdb mysql,information_schema

1 row in set (0.01 sec)

记录下 File 和 Position 的值, 执行完此步骤后不要再操作主服务器 MySQL,避免主服务器状态值变动

  • 在从机上配置须要复制的主机

复制主机的命令

CHANGE MASTER TO MASTER_HOST=’ 主机的 IP 地址 ’,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin. 具体数字 ’,
MASTER_LOG_POS= 具体值;

启动从服务器复制性能

start slave;

查看从服务器状态

show slave statusG

例子:

CHANGE MASTER TO MASTER_HOST=’192.168.107.132′,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin.000003′,
MASTER_LOG_POS=154;

如果之前配置过主从复制, 须要先重置stop slave;, reset master;

接着启动从服务器复制性能 start slave;

查看从服务器状态 show slave statusG(不要加分号)

这两项尾 Yes 即为胜利

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

如果失败可查看 Error 项

Last_Errno: 0
Last_Error:
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:

主机新建库(my.cnf 中规定的库)、新建表、insert 记录,从机复制

一主一从

<!– 写主机 –>

    <writeHost host="hostM1" url="192.168.107.132:3306" user="root"
               password="000000">

<!– 读主机 –>

    <readHost host="hostS2" url="192.168.107.108:3306" user="hzy" password="000000"/>

启动 mycat

在写主机数据库表 mytbl 中插入带零碎变量数据,造成主从数据不统一 INSERT INTO mytbl VALUES(2,@@hostname);

应用 mycat 查问, 能够看到 mycat 操作的是主机数据

起因是咱们没有指定数据库拜访的 负载策略balance

  • 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″,所有读申请随机的散发到 readhost 执行,writerHost 不累赘读压力

双主双从选 1, 单主单从或多从选 3

批改 schema.xml

<!– 数据主机 –>

<dataHost name="host1" maxCon="1000" minCon="10" balance="3"
          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">

双主双从

一个主机 m1 用于解决所有写申请,它的从机 s1 和另一台主机 m2 还有它的从机 s2 负责所有读请 求。当 m1 主机宕机后,m2 主机负责写申请,m1、m2 互为备机。

Master1 配置

批改配置文件:vim /etc/my.cnf

主服务器惟一 ID

server-id=1

启用二进制日志

log-bin=mysql-bin

设置不要复制的数据库(可设置多个)

binlog-ignore-db=mysql
binlog-ignore-db=information_schema

设置须要复制的数据库

binlog-do-db= 须要复制的主数据库名字

设置 logbin 格局

binlog_format=STATEMENT

在作为从数据库的时候,有写入操作也要更新二进制日志文件

log-slave-updates

示意自增长字段每次递增的量,指字段一次递增多少,其默认值是 1,取值范畴是 1 .. 65535

auto-increment-increment=2

示意自增长字段从哪个数开始,指自增字段的起始值,他的取值范畴是 1 .. 65535

auto-increment-offset=1

Master2 配置

批改配置文件:vim /etc/my.cnf

主服务器惟一 ID

server-id=3

启用二进制日志

log-bin=mysql-bin

设置不要复制的数据库(可设置多个)

binlog-ignore-db=mysql
binlog-ignore-db=information_schema

设置须要复制的数据库

binlog-do-db= 须要复制的主数据库名字

设置 logbin 格局

binlog_format=STATEMENT

在作为从数据库的时候,有写入操作也要更新二进制日志文件

log-slave-updates

示意自增长字段每次递增的量,指自增字段的起始值,其默认值是 1,取值范畴是 1 .. 65535

auto-increment-increment=2

示意自增长字段从哪个数开始,指自增字段的起始值,他的取值范畴是 1 .. 6553

65535 auto-increment-offset=2

留神:auto-increment-offset 不能够是反复的

Slave1 配置

从服务器惟一 ID

server-id=2

启用中继日志

relay-log=mysql-relay

Slave2 配置

从服务器惟一 ID

server-id=4

启用中继日志

relay-log=mysql-relay

  • 双主机、双从机重启 mysql 服务
  • 主机从机都敞开防火墙
  • 在两台主机上建设帐户并受权 slave

在主机 MySQL 里执行受权命令

GRANT REPLICATION SLAVE ON . TO ‘slave’@’%’ IDENTIFIED BY ‘123123’;

  • 查看两台主机的状态show master status;, 记录 binlogid 和接入点
  • 设置两台从机的主机,Slava1 复制 Master1,Slava2 复制 Master2
  • 两台主机互备,Master2 复制 Master1,Master1 复制 Master2

stop slave;
reset master;

复制主机的命令

CHANGE MASTER TO MASTER_HOST=’ 主机的 IP 地址 ’,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin. 具体数字 ’,
MASTER_LOG_POS= 具体值;

启动从服务器复制性能

start slave;

查看从服务器状态

show slave statusG

  • 批改 schema.xml

<dataNode name=”dn1″ dataHost=”host1″ database=”testdb” />
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”1″ 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.140.128:3306" user="root"                                    password="123123">                         
    <!-- can have multi read hosts -->                         
    <readHost host="hostS1" url="192.168.140.127:3306" user="root" password="123123"/>                 
</writeHost>    

<writeHost host="hostM2" url="192.168.140.126:3306" user="root"                                    password="123123">                         
    <!-- can have multi read hosts -->                         
    <readHost host="hostS2" url="192.168.140.125:3306" user="root" password="123123"/>                 
</writeHost>         

</dataHost>

balance=”1″: 全副的 readHost 与 stand by writeHost 参加 select 语句的负载平衡。

writeType=”0″: 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个

writeHost,重新启动后以切换后的为准,切换记录在配置文件中:dnindex.properties。

switchType=”1″: 1 默认值,主动切换。

-1 示意不主动切换

2 基于 MySQL 主从同步的状态决定是否切换。

  • 验证主从复制:Master1 主机新建库、新建表、insert 记录,Master2 和从机复制
  • 验证读写拆散:

在写主机 Master1 数据库表 mytbl 中插入带零碎变量数据,造成主从数据不统一

INSERT INTO mytbl VALUES(3,@@hostname);,

在 Mycat 里查问 mytbl 表, 能够看到查问语句在 Master2(host81)、Slava1(host80)、Slava2(host82)主从三个主机间切换;

进行数据库 Master1 在 Mycat 里插入数据仍然胜利,Master2 主动切换为写主机

垂直拆分——分库

依照业务将表进行分类(或者 Schema)来切分到不同的数据库(主机)之上,这种切能够称之为数据的垂直(纵向)切分

分库的准则:有严密关联关系的表应该在一个库里,互相没有关联关系的表能够分到不同的库里, 因为分库的表不能够关联查问

客户表 rows:20 万

CREATE TABLE customer(

id INT AUTO_INCREMENT, 
NAME VARCHAR(200), 
PRIMARY KEY(id) 

);

订单表 rows:600 万

CREATE TABLE orders(

id INT AUTO_INCREMENT, 
order_type INT, 
customer_id INT, 
amount DECIMAL(10,2),     
PRIMARY KEY(id)

);

订单具体表 rows:600 万

CREATE TABLE orders_detail(

id INT AUTO_INCREMENT,     
detail VARCHAR(2000),     
order_id INT,     
PRIMARY KEY(id) 

);

订单状态字典表 rows:20

CREATE TABLE dict_order_type(

id INT AUTO_INCREMENT,     
order_type VARCHAR(200),     
PRIMARY KEY(id) 

);

客户表分在一个数据库,另外三张都须要关联查问,分在另外一个数据库。

1. 批改 schema 配置文件

<!– 逻辑库 –>

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
    <!-- 配置 customer 表调配到 dn2 -->
    <table name="customer" dataNode="dn2" ></table> 
</schema>

<!-- 数据节点 -->
<dataNode name="dn1" dataHost="host1" database="orders" />
<dataNode name="dn2" dataHost="host2" database="orders" />

<!-- host1 -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    <!-- 心跳检测 -->
    <heartbeat>select user()</heartbeat>
    <!-- 写主机 -->
    <writeHost host="hostM1" url="192.168.107.132:3306" user="root"
               password="000000">
    </writeHost>
    
</dataHost>

<!-- host2 -->
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    <!-- 心跳检测 -->
    <heartbeat>select user()</heartbeat>
    <!-- 写主机 -->
    <writeHost host="hostM1" url="192.168.107.108:3306" user="hzy"
               password="000000">
    </writeHost>
    
</dataHost>

通过 mycat 操作逻辑库默认执行到 dataNode="dn1", 咱们指定了customer 调配到dataNode="dn2"

balance="0"不设置读写拆散

2. 两台机器别离创立新的的数据库

CREATE DATABASE orders;

3. 启动 Mycat

./mycat console

4. 拜访 Mycat 进行分库

mysql -umycat -p123456 -h 192.168.140.128 -P 8066

切换到 TESTDB

创立 4 张表

查看表信息,能够看到胜利分库

程度拆分——分表

依据表中的数据的逻辑关系依照某个字段的某种规定,将同一个表中的数据依照某种条件拆分到多台数据库(主机)下面,这种切分称之为数据的程度(横向)切分

MySQL 单表存储数据条数是有瓶颈的,单表白到 1000 万条数据就达到了瓶颈,会影响查问效率,须要进行程度拆分(分表)进行优化。例如:例子中的 orders、orders_detail 都曾经达到 600 万行数据,须要进行分表优化。

1. 分表字段 , 以 orders 表为例,能够依据不同自字段进行分表

  • id 主键或创立工夫:查问订单重视时效,历史订单被查问的次数少,如此分片会造成一个节点拜访多,一个拜访少,不均匀。
  • customer_id(客户 id): 依据客户 id 去分,两个节点拜访均匀,一个客户的所有订单都在同一个节点

2. 批改 schema 配置文件

<!– 逻辑库 –>

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
    <!-- 配置 customer 表调配到 dn2 -->
    <table name="customer" dataNode="dn2" ></table>
    <table name="orders" dataNode="dn1,dn2"  rule="mod_rule" ></table> 
</schema>

orders表被划分到两个数据节点 dn1,dn2,mod_rule 分片规定名称

3.批改 rule 配置文件

定义 mod_rule 分片规定, 并指定规定实用字段为 customer_id,抉择分片算法 mod-long(对字段求模运算),customer_id 对两个节点求模,依据后果分片

<tableRule name="mod_rule">
        <rule>
            <columns>customer_id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
</tableRule>
<!-- 配置算法 mod-long 参数 count 为 2,两个节点 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- 多少个数据节点 -->
        <property name="count">2</property>
</function>

4. 测试分表

  • 在数据节点 dn2 上建 orders 表
  • 重启 Mycat,让配置失效
  • 拜访 Mycat 实现分片
  • 在 mycat 里向 orders 表插入数据,INSERT 字段不能省略 INSERT INTO

    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(1,101,100,100100);
    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300);
    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000);
    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000);
    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400);
    INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020);

    在 mycat、dn1、dn2 中查看 orders 表数据,分表胜利

Mycat 的分片“join”

Orders 订单表曾经进行分表操作了,和它关联的 orders_detail 订单详情表如何进行 join 查问。

orders_detail 也要进行分片操作。Join 的原理如下图:

ER 表

Mycat 借鉴了 NewSQL 畛域的新秀 Foundation DB 的设计思路,Foundation DB 创新性的提 出了 Table Group 的概念,其将子表的存储地位依赖于主表,并且物理上紧邻寄存,因而彻底解决了 JION 的效率和性能问 题,依据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所 关联的父表记录寄存在同一个数据分片上

批改 schema.xml 配置文件

配置 orders 的子表 orders_detail, 应用外键 order_id 进行分片, 这样与 orders 表的数据分布严密

<childTable name=”orders_detail” primaryKey=”id” joinKey=”order_id” parentKey=”id” />

在 dn2 创立 orders_detail 表 重启 Mycat 拜访 Mycat 向 orders_detail 表插入数据

INSERT INTO orders_detail(id,detail,order_id) values(1,’detail1′,1);
INSERT INTO orders_detail(id,detail,order_id) VALUES(2,’detail1′,2);
INSERT INTO orders_detail(id,detail,order_id) VALUES(3,’detail1′,3);
INSERT INTO orders_detail(id,detail,order_id) VALUES(4,’detail1′,4);
INSERT INTO orders_detail(id,detail,order_id) VALUES(5,’detail1′,5);
INSERT INTO orders_detail(id,detail,order_id) VALUES(6,’detail1′,6);

在 mycat、dn1、dn2 中运行两个表 join 语句

Select o.*,od.detail from orders o
inner join orders_detail od on o.id=od.order_id;

全局表

在分片的状况下,当业务表因为规模而进行分片当前,业务表与这些从属的字典表之间的关联,就成了比拟 辣手的问题,思考到字典表具备以下几个个性:① 变动不频繁 ② 数据量总体变动不大 ③ 数据规模不大,很少有超过数十万条记录

鉴于此,Mycat 定义了一种非凡的表,称之为“全局表”,全局表具备以下个性:

  • 全局表的插入、更新操作会实时在所有节点上执行,放弃各个分片的数据一致性
  • 全局表的查问操作,只从一个节点获取
  • 全局表能够跟任何一个表进行 JOIN 操作

将字典表或者合乎字典表个性的一些表定义为全局表,则从另外一个方面,很好的解决了数据 JOIN 的难题。通过全局表 + 基于 E-R 关系的分片策略,Mycat 能够满足 80% 以上的企业应用开发

批改 schema.xml 配置文件

<childTable name=”orders_detail” primaryKey=”id” joinKey=”order_id” parentKey=”id” />

<!– 定义全局字典表 –>

在 dn2 创立 dict_order_type 表 重启 Mycat 拜访 Mycat 向 dict_order_type 表插入数据

INSERT INTO dict_order_type(id,order_type) VALUES(101,’type1′);
INSERT INTO dict_order_type(id,order_type) VALUES(102,’type2′);

在 Mycat、dn1、dn2 中查问表数据

罕用分片规定
——

### 取模

此规定为对分片字段求摸运算。也是程度分表最罕用规定。

### 分片枚举

通过在配置文件中配置可能的枚举 id,本人配置分片,本规定实用于特定的场景,比方有些业务 须要依照省份或区县来做保留,而全国省份区县固定的,这类业务应用本条规定。

* 批改 schema.xml 配置文件

<!– 分片枚举 –>

* 批改 rule.xml 配置文件

<tableRule name=”sharding_by_intfile”>
<rule>
<columns>areacode</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> <property name=”type”>1</property>
<property name=”defaultNode”>0</property>
</function>

columns:分片字段,algorithm:分片函数

mapFile:标识配置文件名称,type:分片字段类型 0 为 int 型、非 0 为 String

defaultNode:默认节点: 小于 0 示意不设置默认节点,大于等于 0 示意设置默认节点,设置默认节点如果碰到不辨认的枚举值,就让它路由到默认节点,如不设置不辨认就报错

* 批改 partition-hash-int.txt 配置文件

110=0
120=1
#110 走 dn1, 120 走 dn2

* 重启 Mycat

* 拜访 Mycat 创立表

#订单归属区域信息表
CREATE TABLE orders_ware_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
order_id INT comment ‘ 订单编号 ’,
address VARCHAR(200) comment ‘ 地址 ’,
areacode VARCHAR(20) comment ‘ 区域编号 ’,
PRIMARY KEY(id)
);

插入数据

INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (1,1,’ 北京 ’,’110′); INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (2,2,’ 天津 ’,’120′);

### 范畴约定

此分片实用于,提前布局好分片字段某个范畴属于哪个分片。

* 批改 schema.xml 配置文件

* 批改 rule.xml 配置文件

<tableRule name=”auto_sharding_long”>
<rule>
<columns>order_id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>

<function name=”rang-long” class=”io.mycat.route.function.AutoPartitionByLong”>
<property name=”mapFile”>autopartition-long.txt</property> <property name=”defaultNode”>0</property>
</function>

columns:分片字段,algorithm:分片函数 mapFile:标识配置文件名称

defaultNode:默认节点: 小于 0 示意不设置默认节点,大于等于 0 示意设置默认节点,设置默认节点如果碰到不辨认的枚举值,就让它路由到默认节点,如不设置不辨认就 报错

* 批改 autopartition-long.txt 配置文件

0-102=0
103-200=1

* 重启 Mycat

* 拜访 Mycat 创立表

# 领取信息表
CREATE TABLE payment_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
order_id INT comment ‘ 订单编号 ’,
payment_status INT comment ‘ 领取状态 ’,
PRIMARY KEY(id)
);

* 插入数据

INSERT INTO payment_info (id,order_id,payment_status) VALUES (1,101,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (2,102,1);
INSERT INTO payment_info (id,order_id ,payment_status) VALUES (3,103,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (4,104,1);

* 查问 Mycat、dn1、dn2 能够看到数据分片成果

### 日期 (天) 分片

* 批改 schema.xml 配置文件

<!– 日期分片 –>

* 批改 rule.xml 配置文件

<tableRule name=”sharding_by_date”>
<rule>
<columns>login_date</columns>
<algorithm>shardingByDate</algorithm>
</rule>
</tableRule>

<function name=”shardingByDate” class=”io.mycat.route.function.PartitionByDate”>
<property name=”dateFormat”>yyyy-MM-dd</property>
<property name=”sBeginDate”>2019-01-01</property>
<property name=”sEndDate”>2019-01-04</property>
<property name=”sPartionDay”>2</property>
</function>

columns:分片字段,algorithm:分片函数 dateFormat:日期格局 sBeginDate:开始日期

sEndDate:完结日期, 则代表数据达到了这个日期的分片后循环从开始分片插入

sPartionDay:分区天数,即默认从开始日期算起,分隔 2 天一个分区

* 重启 Mycat

* 拜访 Mycat 创立表

* 用户信息表

CREATE TABLE login_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
user_id INT comment ‘ 用户编号 ’,
login_date date comment ‘ 登录日期 ’,
PRIMARY KEY(id)
);

INSERT INTO login_info(id,user_id,login_date) VALUES (1,101,’2019-01-01′);
INSERT INTO login_info(id,user_id,login_date) VALUES (2,102,’2019-01-02′);
INSERT INTO login_info(id,user_id,login_date) VALUES (3,103,’2019-01-03′);
INSERT INTO login_info(id,user_id,login_date) VALUES (4,104,’2019-01-04′);
INSERT INTO login_info(id,user_id,login_date) VALUES (5,103,’2019-01-05′);
INSERT INTO login_info(id,user_id,login_date) VALUES (6,104,’2019-01-06′);

* 查问 Mycat、dn1、dn2 能够看到数据分片成果

全局序列
—-

在实现分库分表的状况下,数据库自增主键已无奈保障自增主键的全局惟一。为此,Mycat 提供 了全局 sequence,并且提供了蕴含本地配置和数据库配置等多种实现形式

1、本地文件 此形式 Mycat 将 sequence 配置到文件中,当应用到 sequence 中的配置后,Mycat 会更新 classpath 中的 sequence_conf.properties 文件中 sequence 以后的值。

* 长处:本地加载,读取速度较快

* 毛病:抗危险能力差,Mycat 所在主机宕机后,无奈读取本地文件。

2、数据库形式 利用数据库一个表 来进行计数累加。然而并不是每次生成序列都读写数据库,这样效率太低。Mycat 会预加载一部分号段到 Mycat 的内存中,这样大部分读写序列都是在内存中实现的。如果内存中的号段用完了 Mycat 会再向数据库要一次。

问:那如果 Mycat 解体了,那内存中的序列岂不是都没了?是的。如果是这样,那么 Mycat 启动后会向数据库申请新的号段,原有号段会弃用。也就是说如果 Mycat 重启,那么损失是以后的号段没用完的号码,然而不会因而呈现主键反复

* 全局序列表

#在 dn1 上创立全局序列表
CREATE TABLE MYCAT_SEQUENCE (
NAME VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 100,
PRIMARY KEY(NAME)
) ENGINE=INNODB;

* 创立全局序列所需函数

DELIMITER $$
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval=”-999999999,null”;
SELECT CONCAT(CAST(current_value AS CHAR),”,”,CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE
WHERE NAME = seq_name;
RETURN retval;
END $$
DELIMITER ;

DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = VALUE
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$ D
ELIMITER ;

DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER ;

* 初始化序列表记录

INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES (‘ORDERS’, 400000, 100);

* 批改 Mycat 配置

批改sequence_db_conf.properties

#sequence stored in datanode
GLOBAL=dn1
COMPANY=dn1
CUSTOMER=dn1
ORDERS=dn1

意思是 ORDERS 这个序列在 dn1 这个节点上,具体 dn1 节点是哪台机子,请参考 schema.xml

* 批改 server.xml

<property name=”sequnceHandlerType”>1</property>

全局序列类型:0- 本地文件,1- 数据库形式,2- 工夫戳形式。此处应该批改成 1。
title: MyCat 学习笔记 # 题目
date: 2019/10/26 16:23:46 # 工夫
categories: # 分类
– 数据库
tags: # 标签
– 数据库中间件
– 分库分表

Mycat 数据库中间件
===========

1、数据库中间件

是一类连贯软件组件和利用的计算机软件,以便于软件各部件之间的沟通。例子:Tomcat,web 中间件。数据库中间件:连贯 java 应用程序和数据库

<!–more–>

2、为什么要用 Mycat?

* Java 与数据库紧耦合

* 高访问量高并发对数据库的压力

* 读写申请数据不统一

mysql 单表瓶颈 1000w 数据, 单库瓶颈 5000w 数据

数据库中间件比照:

Mycat 的官网: http://www.mycat.io/

Mycat 能干什么:

* 读写拆散

* 数据分片 垂直拆分(分库)、程度拆分(分表)、垂直 + 程度拆分(分库分表)

* 多数据源整合 原理:

Mycat 的原理中最重要的一个动词是“拦挡”,它拦挡了用户发送过去的 SQL 语句,首先对 SQL 语句做了一些特定的剖析:如分片剖析、路由剖析、读写拆散剖析、缓存剖析等,而后将此 SQL 发 往后端的实在数据库,并将返回的后果做适当的解决,最终再返回给用户

装置启动
—-

1、解压后即可应用 解压缩文件拷贝到 linux 下 /usr/local/ 2、三个配置文件

* schema.xml:定义逻辑库,表、分片节点等内容

* rule.xml:定义分片规定

* server.xml:定义用户以及零碎相干变量,如端口等

3、批改配置文件 server.xml 批改用户信息,与 MySQL 辨别

<!– 用户名 –>
<user name=”root”>
<property name=”password”>123456</property>     <!– 明码 –>
<property name=”schemas”>TESTDB</property> <!– 治理的库 –>
</user>

schemas: 数据库名,这里会和 schema.xml 中的配置关联,多个用逗号离开,例如须要这个用户须要治理两个数据库 db1,db2,则配置 db1,db2

4. 批改配置文件 schema.xml

删除 <schema> 标签间的表信息配置 dataNode="dn1"<dataNode> 标签只留一个,<dataHost>标签只留一个,<writeHost>,<readHost>只留一对

<mycat:schema xmlns:mycat=”http://io.mycat/”>

<!– 逻辑库 –>
<schema name=”TESTDB” checkSQLschema=”false” sqlMaxLimit=”100″  dataNode=”dn1″>
<!– 逻辑表 –>
</schema>

<!– 数据节点 database 填写实在数据库 –>
<dataNode name=”dn1″ dataHost=”host1″ database=”testdb” />

<!– 数据主机 –>
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″  slaveThreshold=”100″>
<!– 心跳检测 –>
<heartbeat>select user()</heartbeat>
<!– 写主机 –>
<writeHost host=”hostM1″ url=”192.168.107.132:3306″ user=”root”
password=”000000″>
<!– 读主机 –>
<readHost host=”hostS2″ url=”192.168.107.108:3306″ user=”hzy” password=”000000″/>
</writeHost>

</dataHost>

</mycat:schema>

5. 验证数据库拜访状况

Mycat 作为数据库中间件要和数据库部署在不同机器上,所以要验证近程拜访状况。

mysql -uhzy -p000000 -h 192.168.107.108 -P 3306
mysql -uroot -p000000 -h 192.168.107.132 -P 3306

# 如近程拜访报错,请建对应用户
grant all privileges on . to root@’ 短少的 host’ identified by ‘000000’;

6. 启动 mycat

* 控制台启动:去 mycat/bin 目录下执行 ./mycat console

* 后盾启动:去 mycat/bin 目录下 ./mycat start

为了能第一工夫看到启动日志,不便定位问题,咱们抉择控制台启动。

7. 登录 mycat

* 登录后盾治理窗口

此登录形式用于治理保护 Mycat

mysql -umycat -p123456 -P 9066 -h 192.168.140.128

#常用命令如下:
show database;
show @@help;

* 登录数据窗口

此登录形式用于通过 Mycat 查问数据,咱们抉择这种形式拜访 Mycat

mysql -uroot -p123456 -P 8066 -h 192.168.107.132

读写拆散
—-

咱们通过 Mycat 和 MySQL 的 主从复制 配合搭建数据库的 读写拆散,实现 MySQL 的高可用性。咱们将搭建:一主一从、双主双从两种读写拆散模式。

mysql 主从复制原理:

与 redis 不同的是,redis 从机会把主机的数据从头到尾复制, 而 mysql 从机只会从接入点开始复制; 并且会产生屡次 IO 有延时问题

### 主机配置

批改配置文件:
vim /etc/my.cnf
#主服务器惟一 ID
server-id=1
#启用二进制日志
log-bin=mysql-bin
# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
#设置须要复制的数据库
binlog-do-db= 须要复制的主数据库名字
#设置 logbin 格局
binlog_format=STATEMENT

> binlog 的三种模式:https://blog.csdn.net/vhomes/article/details/8082734

### 从机配置

vim /etc/my.cnf
#从服务器惟一 ID
server-id=2
#启用中继日志
relay-log=mysql-relay

* 重启服务:systemctl restart mysqld

* 确认防火墙已敞开:systemctl status firewalld

* 在主机 MySQL 里执行受权命令: GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' IDENTIFIED BY '123123';

如果报错:Your password does not satisfy the current policy requirements, 请执行:

set global validate_password_policy=0;
set global validate_password_length=4;

* 查看主机状态:

show master status;
+——————+———-+————–+————————–+——————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+——————+———-+————–+————————–+——————-+
| mysql-bin.000001 | 438 | testdb | mysql,information_schema | |
+——————+———-+————–+————————–+——————-+
1 row in set (0.01 sec)

记录下 File 和 Position 的值, 执行完此步骤后不要再操作主服务器 MySQL,避免主服务器状态值变动

* 在从机上配置须要复制的主机

# 复制主机的命令
CHANGE MASTER TO MASTER_HOST=’ 主机的 IP 地址 ’,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin. 具体数字 ’,
MASTER_LOG_POS= 具体值;
#启动从服务器复制性能
start slave;
#查看从服务器状态
show slave statusG

例子:

CHANGE MASTER TO MASTER_HOST=’192.168.107.132′,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin.000003′,
MASTER_LOG_POS=154;

如果之前配置过主从复制, 须要先重置stop slave;, reset master;

接着启动从服务器复制性能 start slave;

查看从服务器状态 show slave statusG(不要加分号)

# 这两项尾 Yes 即为胜利
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#如果失败可查看 Error 项
Last_Errno: 0
Last_Error:
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:

主机新建库(my.cnf 中规定的库)、新建表、insert 记录,从机复制

### 一主一从

<!– 写主机 –>
<writeHost host=”hostM1″ url=”192.168.107.132:3306″ user=”root”
password=”000000″>
<!– 读主机 –>
<readHost host=”hostS2″ url=”192.168.107.108:3306″ user=”hzy” password=”000000″/>

启动 mycat

在写主机数据库表 mytbl 中插入带零碎变量数据,造成主从数据不统一 INSERT INTO mytbl VALUES(2,@@hostname);

应用 mycat 查问, 能够看到 mycat 操作的是主机数据

起因是咱们没有指定数据库拜访的 负载策略balance

* 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″,所有读申请随机的散发到 readhost 执行,writerHost 不累赘读压力

双主双从选 1, 单主单从或多从选 3

批改 schema.xml

<!– 数据主机 –>
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”3″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″ slaveThreshold=”100″>

### 双主双从

一个主机 m1 用于解决所有写申请,它的从机 s1 和另一台主机 m2 还有它的从机 s2 负责所有读请 求。当 m1 主机宕机后,m2 主机负责写申请,m1、m2 互为备机。

Master1 配置

批改配置文件:vim /etc/my.cnf
#主服务器惟一 ID
server-id=1
#启用二进制日志
log-bin=mysql-bin
# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
#设置须要复制的数据库
binlog-do-db= 须要复制的主数据库名字
#设置 logbin 格局
binlog_format=STATEMENT
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
#示意自增长字段每次递增的量,指字段一次递增多少,其默认值是 1,取值范畴是 1 .. 65535
auto-increment-increment=2
# 示意自增长字段从哪个数开始,指自增字段的起始值,他的取值范畴是 1 .. 65535
auto-increment-offset=1

Master2 配置

批改配置文件:vim /etc/my.cnf
#主服务器惟一 ID
server-id=3
#启用二进制日志
log-bin=mysql-bin
#设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
#设置须要复制的数据库
binlog-do-db= 须要复制的主数据库名字
#设置 logbin 格局
binlog_format=STATEMENT
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
#示意自增长字段每次递增的量,指自增字段的起始值,其默认值是 1,取值范畴是 1 .. 65535
auto-increment-increment=2
# 示意自增长字段从哪个数开始,指自增字段的起始值,他的取值范畴是 1 .. 6553
65535 auto-increment-offset=2

留神:auto-increment-offset 不能够是反复的

Slave1 配置

# 从服务器惟一 ID
server-id=2
#启用中继日志
relay-log=mysql-relay

Slave2 配置

# 从服务器惟一 ID
server-id=4
#启用中继日志
relay-log=mysql-relay

* 双主机、双从机重启 mysql 服务

* 主机从机都敞开防火墙

* 在两台主机上建设帐户并受权 slave

# 在主机 MySQL 里执行受权命令
GRANT REPLICATION SLAVE ON . TO ‘slave’@’%’ IDENTIFIED BY ‘123123’;

* 查看两台主机的状态show master status;, 记录 binlogid 和接入点

* 设置两台从机的主机,Slava1 复制 Master1,Slava2 复制 Master2

* 两台主机互备,Master2 复制 Master1,Master1 复制 Master2

stop slave;
reset master;
#复制主机的命令
CHANGE MASTER TO MASTER_HOST=’ 主机的 IP 地址 ’,
MASTER_USER=’slave’,
MASTER_PASSWORD=’123123′,
MASTER_LOG_FILE=’mysql-bin. 具体数字 ’,
MASTER_LOG_POS= 具体值;
#启动从服务器复制性能
start slave;
#查看从服务器状态
show slave statusG

* 批改 schema.xml

<dataNode name=”dn1″ dataHost=”host1″ database=”testdb” />
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”1″ 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.140.128:3306″ user=”root” password=”123123″>
<!– can have multi read hosts –>
<readHost host=”hostS1″ url=”192.168.140.127:3306″ user=”root” password=”123123″/>
</writeHost>

<writeHost host=”hostM2″ url=”192.168.140.126:3306″ user=”root” password=”123123″>
<!– can have multi read hosts –>
<readHost host=”hostS2″ url=”192.168.140.125:3306″ user=”root” password=”123123″/>
</writeHost>
</dataHost>
#balance=”1″: 全副的 readHost 与 stand by writeHost 参加 select 语句的负载平衡。
#writeType=”0″: 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个
#writeHost,重新启动后以切换后的为准,切换记录在配置文件中:dnindex.properties。
#switchType=”1″: 1 默认值,主动切换。
# -1 示意不主动切换
# 2 基于 MySQL 主从同步的状态决定是否切换。

* 验证主从复制:Master1 主机新建库、新建表、insert 记录,Master2 和从机复制

* 验证读写拆散:

在写主机 Master1 数据库表 mytbl 中插入带零碎变量数据,造成主从数据不统一

INSERT INTO mytbl VALUES(3,@@hostname);,

在 Mycat 里查问 mytbl 表, 能够看到查问语句在 Master2(host81)、Slava1(host80)、Slava2(host82)主从三个主机间切换;

进行数据库 Master1 在 Mycat 里插入数据仍然胜利,Master2 主动切换为写主机

垂直拆分——分库
——–

依照业务将表进行分类(或者 Schema)来切分到不同的数据库(主机)之上,这种切能够称之为数据的垂直(纵向)切分

分库的准则:有严密关联关系的表应该在一个库里,互相没有关联关系的表能够分到不同的库里, 因为分库的表不能够关联查问

# 客户表 rows:20 万
CREATE TABLE customer(
id INT AUTO_INCREMENT,
NAME VARCHAR(200),
PRIMARY KEY(id)
);
#订单表 rows:600 万
CREATE TABLE orders(
id INT AUTO_INCREMENT,
order_type INT,
customer_id INT,
amount DECIMAL(10,2),
PRIMARY KEY(id)
);
#订单具体表 rows:600 万
CREATE TABLE orders_detail(
id INT AUTO_INCREMENT,
detail VARCHAR(2000),
order_id INT,
PRIMARY KEY(id)
);
#订单状态字典表 rows:20
CREATE TABLE dict_order_type(
id INT AUTO_INCREMENT,
order_type VARCHAR(200),
PRIMARY KEY(id)
);

客户表分在一个数据库,另外三张都须要关联查问,分在另外一个数据库。

1. 批改 schema 配置文件

<!– 逻辑库 –>
<schema name=”TESTDB” checkSQLschema=”false” sqlMaxLimit=”100″ dataNode=”dn1″>
<!– 配置 customer 表调配到 dn2 –>

</schema>

<!– 数据节点 –>
<dataNode name=”dn1″ dataHost=”host1″ database=”orders” />
<dataNode name=”dn2″ dataHost=”host2″ database=”orders” />

<!– host1 –>
<dataHost name=”host1″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″ slaveThreshold=”100″>
<!– 心跳检测 –>
<heartbeat>select user()</heartbeat>
<!– 写主机 –>
<writeHost host=”hostM1″ url=”192.168.107.132:3306″ user=”root”
password=”000000″>
</writeHost>

</dataHost>

<!– host2 –>
<dataHost name=”host2″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″ slaveThreshold=”100″>
<!– 心跳检测 –>
<heartbeat>select user()</heartbeat>
<!– 写主机 –>
<writeHost host=”hostM1″ url=”192.168.107.108:3306″ user=”hzy”
password=”000000″>
</writeHost>

</dataHost>

通过 mycat 操作逻辑库默认执行到 dataNode="dn1", 咱们指定了customer 调配到dataNode="dn2"

balance="0"不设置读写拆散

2. 两台机器别离创立新的的数据库

CREATE DATABASE orders;

3. 启动 Mycat

./mycat console

4. 拜访 Mycat 进行分库

mysql -umycat -p123456 -h 192.168.140.128 -P 8066
#切换到 TESTDB
#创立 4 张表
#查看表信息,能够看到胜利分库

程度拆分——分表
——–

依据表中的数据的逻辑关系依照某个字段的某种规定,将同一个表中的数据依照某种条件拆分到多台数据库(主机)下面,这种切分称之为数据的程度(横向)切分

MySQL 单表存储数据条数是有瓶颈的,单表白到 1000 万条数据就达到了瓶颈,会影响查问效率,须要进行程度拆分(分表)进行优化。例如:例子中的 orders、orders_detail 都曾经达到 600 万行数据,须要进行分表优化。

1. 分表字段 , 以 orders 表为例,能够依据不同自字段进行分表

* id 主键或创立工夫:查问订单重视时效,历史订单被查问的次数少,如此分片会造成一个节点拜访多,一个拜访少,不均匀。

* customer_id(客户 id): 依据客户 id 去分,两个节点拜访均匀,一个客户的所有订单都在同一个节点

2. 批改 schema 配置文件

<!– 逻辑库 –>
<schema name=”TESTDB” checkSQLschema=”false” sqlMaxLimit=”100″ dataNode=”dn1″>
<!– 配置 customer 表调配到 dn2 –>

</schema>

orders表被划分到两个数据节点 dn1,dn2,mod_rule 分片规定名称

3.批改 rule 配置文件

定义 mod_rule 分片规定, 并指定规定实用字段为 customer_id,抉择分片算法 mod-long(对字段求模运算),customer_id 对两个节点求模,依据后果分片

<tableRule name=”mod_rule”>
<rule>
<columns>customer_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<!– 配置算法 mod-long 参数 count 为 2,两个节点 –>
<function name=”mod-long” class=”io.mycat.route.function.PartitionByMod”>
<!– 多少个数据节点 –>
<property name=”count”>2</property>
</function>

4. 测试分表

* 在数据节点 dn2 上建 orders 表

* 重启 Mycat,让配置失效

* 拜访 Mycat 实现分片

* 在 mycat 里向 orders 表插入数据,INSERT 字段不能省略 INSERT INTO

INSERT INTO orders(id,order_type,customer_id,amount) VALUES(1,101,100,100100);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020);

在 mycat、dn1、dn2 中查看 orders 表数据,分表胜利

Mycat 的分片“join”
—————-

Orders 订单表曾经进行分表操作了,和它关联的 orders_detail 订单详情表如何进行 join 查问。

orders_detail 也要进行分片操作。Join 的原理如下图:

### ER 表

Mycat 借鉴了 NewSQL 畛域的新秀 Foundation DB 的设计思路,Foundation DB 创新性的提 出了 Table Group 的概念,其将子表的存储地位依赖于主表,并且物理上紧邻寄存,因而彻底解决了 JION 的效率和性能问 题,依据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所 关联的父表记录寄存在同一个数据分片上

批改 schema.xml 配置文件

配置 orders 的子表 orders_detail, 应用外键 order_id 进行分片, 这样与 orders 表的数据分布严密

<childTable name=”orders_detail” primaryKey=”id” joinKey=”order_id” parentKey=”id” />

在 dn2 创立 orders_detail 表 重启 Mycat 拜访 Mycat 向 orders_detail 表插入数据

INSERT INTO orders_detail(id,detail,order_id) values(1,’detail1′,1);
INSERT INTO orders_detail(id,detail,order_id) VALUES(2,’detail1′,2);
INSERT INTO orders_detail(id,detail,order_id) VALUES(3,’detail1′,3);
INSERT INTO orders_detail(id,detail,order_id) VALUES(4,’detail1′,4);
INSERT INTO orders_detail(id,detail,order_id) VALUES(5,’detail1′,5);
INSERT INTO orders_detail(id,detail,order_id) VALUES(6,’detail1′,6);

在 mycat、dn1、dn2 中运行两个表 join 语句

Select o.*,od.detail from orders o
inner join orders_detail od on o.id=od.order_id;

全局表

在分片的状况下,当业务表因为规模而进行分片当前,业务表与这些从属的字典表之间的关联,就成了比拟 辣手的问题,思考到字典表具备以下几个个性:① 变动不频繁 ② 数据量总体变动不大 ③ 数据规模不大,很少有超过数十万条记录

鉴于此,Mycat 定义了一种非凡的表,称之为“全局表”,全局表具备以下个性:

  • 全局表的插入、更新操作会实时在所有节点上执行,放弃各个分片的数据一致性
  • 全局表的查问操作,只从一个节点获取
  • 全局表能够跟任何一个表进行 JOIN 操作

将字典表或者合乎字典表个性的一些表定义为全局表,则从另外一个方面,很好的解决了数据 JOIN 的难题。通过全局表 + 基于 E-R 关系的分片策略,Mycat 能够满足 80% 以上的企业应用开发

批改 schema.xml 配置文件

<childTable name=”orders_detail” primaryKey=”id” joinKey=”order_id” parentKey=”id” />

<!– 定义全局字典表 –>

在 dn2 创立 dict_order_type 表 重启 Mycat 拜访 Mycat 向 dict_order_type 表插入数据

INSERT INTO dict_order_type(id,order_type) VALUES(101,’type1′);
INSERT INTO dict_order_type(id,order_type) VALUES(102,’type2′);

在 Mycat、dn1、dn2 中查问表数据

罕用分片规定
——

### 取模

此规定为对分片字段求摸运算。也是程度分表最罕用规定。

### 分片枚举

通过在配置文件中配置可能的枚举 id,本人配置分片,本规定实用于特定的场景,比方有些业务 须要依照省份或区县来做保留,而全国省份区县固定的,这类业务应用本条规定。

* 批改 schema.xml 配置文件

<!– 分片枚举 –>

* 批改 rule.xml 配置文件

<tableRule name=”sharding_by_intfile”>
<rule>
<columns>areacode</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> <property name=”type”>1</property>
<property name=”defaultNode”>0</property>
</function>

columns:分片字段,algorithm:分片函数

mapFile:标识配置文件名称,type:分片字段类型 0 为 int 型、非 0 为 String

defaultNode:默认节点: 小于 0 示意不设置默认节点,大于等于 0 示意设置默认节点,设置默认节点如果碰到不辨认的枚举值,就让它路由到默认节点,如不设置不辨认就报错

* 批改 partition-hash-int.txt 配置文件

110=0
120=1
#110 走 dn1, 120 走 dn2

* 重启 Mycat

* 拜访 Mycat 创立表

#订单归属区域信息表
CREATE TABLE orders_ware_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
order_id INT comment ‘ 订单编号 ’,
address VARCHAR(200) comment ‘ 地址 ’,
areacode VARCHAR(20) comment ‘ 区域编号 ’,
PRIMARY KEY(id)
);

插入数据

INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (1,1,’ 北京 ’,’110′); INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (2,2,’ 天津 ’,’120′);

### 范畴约定

此分片实用于,提前布局好分片字段某个范畴属于哪个分片。

* 批改 schema.xml 配置文件

* 批改 rule.xml 配置文件

<tableRule name=”auto_sharding_long”>
<rule>
<columns>order_id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>

<function name=”rang-long” class=”io.mycat.route.function.AutoPartitionByLong”>
<property name=”mapFile”>autopartition-long.txt</property> <property name=”defaultNode”>0</property>
</function>

columns:分片字段,algorithm:分片函数 mapFile:标识配置文件名称

defaultNode:默认节点: 小于 0 示意不设置默认节点,大于等于 0 示意设置默认节点,设置默认节点如果碰到不辨认的枚举值,就让它路由到默认节点,如不设置不辨认就 报错

* 批改 autopartition-long.txt 配置文件

0-102=0
103-200=1

* 重启 Mycat

* 拜访 Mycat 创立表

# 领取信息表
CREATE TABLE payment_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
order_id INT comment ‘ 订单编号 ’,
payment_status INT comment ‘ 领取状态 ’,
PRIMARY KEY(id)
);

* 插入数据

INSERT INTO payment_info (id,order_id,payment_status) VALUES (1,101,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (2,102,1);
INSERT INTO payment_info (id,order_id ,payment_status) VALUES (3,103,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (4,104,1);

* 查问 Mycat、dn1、dn2 能够看到数据分片成果

### 日期 (天) 分片

* 批改 schema.xml 配置文件

<!– 日期分片 –>

* 批改 rule.xml 配置文件

<tableRule name=”sharding_by_date”>
<rule>
<columns>login_date</columns>
<algorithm>shardingByDate</algorithm>
</rule>
</tableRule>

<function name=”shardingByDate” class=”io.mycat.route.function.PartitionByDate”>
<property name=”dateFormat”>yyyy-MM-dd</property>
<property name=”sBeginDate”>2019-01-01</property>
<property name=”sEndDate”>2019-01-04</property>
<property name=”sPartionDay”>2</property>
</function>

columns:分片字段,algorithm:分片函数 dateFormat:日期格局 sBeginDate:开始日期

sEndDate:完结日期, 则代表数据达到了这个日期的分片后循环从开始分片插入

sPartionDay:分区天数,即默认从开始日期算起,分隔 2 天一个分区

* 重启 Mycat

* 拜访 Mycat 创立表

* 用户信息表

CREATE TABLE login_info (
id INT AUTO_INCREMENT comment ‘ 编号 ’,
user_id INT comment ‘ 用户编号 ’,
login_date date comment ‘ 登录日期 ’,
PRIMARY KEY(id)
);

INSERT INTO login_info(id,user_id,login_date) VALUES (1,101,’2019-01-01′);
INSERT INTO login_info(id,user_id,login_date) VALUES (2,102,’2019-01-02′);
INSERT INTO login_info(id,user_id,login_date) VALUES (3,103,’2019-01-03′);
INSERT INTO login_info(id,user_id,login_date) VALUES (4,104,’2019-01-04′);
INSERT INTO login_info(id,user_id,login_date) VALUES (5,103,’2019-01-05′);
INSERT INTO login_info(id,user_id,login_date) VALUES (6,104,’2019-01-06′);

* 查问 Mycat、dn1、dn2 能够看到数据分片成果

全局序列
—-

在实现分库分表的状况下,数据库自增主键已无奈保障自增主键的全局惟一。为此,Mycat 提供 了全局 sequence,并且提供了蕴含本地配置和数据库配置等多种实现形式

1、本地文件 此形式 Mycat 将 sequence 配置到文件中,当应用到 sequence 中的配置后,Mycat 会更新 classpath 中的 sequence_conf.properties 文件中 sequence 以后的值。

* 长处:本地加载,读取速度较快

* 毛病:抗危险能力差,Mycat 所在主机宕机后,无奈读取本地文件。

2、数据库形式 利用数据库一个表 来进行计数累加。然而并不是每次生成序列都读写数据库,这样效率太低。Mycat 会预加载一部分号段到 Mycat 的内存中,这样大部分读写序列都是在内存中实现的。如果内存中的号段用完了 Mycat 会再向数据库要一次。

问:那如果 Mycat 解体了,那内存中的序列岂不是都没了?是的。如果是这样,那么 Mycat 启动后会向数据库申请新的号段,原有号段会弃用。也就是说如果 Mycat 重启,那么损失是以后的号段没用完的号码,然而不会因而呈现主键反复

* 全局序列表

#在 dn1 上创立全局序列表
CREATE TABLE MYCAT_SEQUENCE (
NAME VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 100,
PRIMARY KEY(NAME)
) ENGINE=INNODB;

* 创立全局序列所需函数

DELIMITER $$
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval=”-999999999,null”;
SELECT CONCAT(CAST(current_value AS CHAR),”,”,CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE
WHERE NAME = seq_name;
RETURN retval;
END $$
DELIMITER ;

DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = VALUE
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$ D
ELIMITER ;

DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER ;

* 初始化序列表记录

INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES (‘ORDERS’, 400000, 100);

* 批改 Mycat 配置

批改sequence_db_conf.properties

#sequence stored in datanode
GLOBAL=dn1
COMPANY=dn1
CUSTOMER=dn1
ORDERS=dn1

意思是 ORDERS 这个序列在 dn1 这个节点上,具体 dn1 节点是哪台机子,请参考 schema.xml

* 批改 server.xml

<property name=”sequnceHandlerType”>1</property>

全局序列类型:0- 本地文件,1- 数据库形式,2- 工夫戳形式。此处应该批改成 1。

* 重启 Mycat

* 验证全局序列 登录 Mycat,插入数据,id 应用 MYCATSEQ_ORDERS 全局序列表中的下一个值

insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);

* 重启 Mycat 后,再次插入数据,再查问


* 重启 Mycat

* 验证全局序列 登录 Mycat,插入数据,id 应用 MYCATSEQ_ORDERS 全局序列表中的下一个值

insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);

* 重启 Mycat 后,再次插入数据,再查问

退出移动版