在Web1.0阶段,由于带宽不足,这时的项目大多是内容少,用户量也不多,甚至有一些项目不需要对外开放,对安全性和稳定性的要求是不高的。
单体架构就足以应对。
随之到来的Web2.0阶段,实现了ADSL拨号上网,宽带提速,最高可以达到8M,用户量也就不断增加,一些门户网站也开始活跃,项目就需要考虑安全性和稳定性。
在基于上面的单体架构图中,无法满足Web2.0对项目的需求。
在单体架构的基础上去搭建集群。
在搭建集群之后,可以提升项目的稳定性,并且并发能力增强,还可以避免单点故障。
为了解决上述的问题,需要使用到三门技术。
比如项目包含了三个模块,用户模块,商品模块,订单模块。如果商品模块压力过大,一般最直接有效的方式就是搭建集群。在单体架构的集群上去搭建,效果相对比较差。
随着项目的不断更新,项目中的功能越来越多,最严重可能会导致项目无法启动。
关于单体架构中,完美的体现了低内聚,高耦合,避开了开发的准则。
为了解决上述的各种问题,演进出了垂直架构。
随着项目的不断迭代,新老功能之间需要相互交互,服务器和服务器之间是需要通讯的。
项目一般是分为三层的,Controller,Service,Dao。 导致程序变慢的重灾区,一般是Service和Dao,在搭建集群时,确实针对三层都搭建集群,效果不是很好。
架构从垂直架构演变到了分布式架构。
分布式架构落地的技术,国内常用的方式有两种
海量数据会导致数据库无法存储全部的内容,即便数据库可以存储海量的数据,在查询数据时,数据库的响应时极其缓慢的,在用户高并发的情况下,数据库也时无法承受住的。
为了解决上述的问题,可以基于MyCat实现数据库的分库分表。
虽然已经将每个模块独立的做开发,比如商品模块,压力最大的是商品的查询。
在单独模块中再次拆分项目的方式就可以称之为微服务架构,微服务架构也是分布式架构。
简单的说,MyCAT就是:
一个彻底开源的,面向企业应用开发的“大数据库集群”
支持事务、ACID、可以替代Mysql的加强版数据库
一个可以视为“Mysql”集群的企业级数据库,用来替代昂贵的Oracle集群
一个融合内存缓存技术、Nosql技术、HDFS大数据的新型SQL Server
结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
一个新颖的数据库中间件产品
MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
支持 SQL 92标准
支持Mysql集群,可以作为Proxy使用
支持JDBC连接ORACLE、DB2、SQL Server,将其模拟为MySQL Server使用
支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群
自动故障切换,高可用性
支持读写分离,支持Mysql双主多从,以及一主多从的模式
支持全局表,数据自动分片到多个节点,用于高效表关联查询
支持独有的基于E-R关系的分片策略,实现了高效的表关联查询
多平台支持,部署和实施简单
如图所示:MyCAT使用Mysql的通讯协议模拟成了一个Mysql服务器,并建立了完整的Schema(数据库)、Table (数据表)、User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNode(MySQL Instance)上的真实物理库中,这样一来,所有能使用Mysql的客户端以及编程语言都能将MyCAT当成是Mysql Server来使用,不必开发新的客户端协议。
1)、性能问题
2)、数据库连接过多
3)、E-R分片难处理
4)、可用性问题
5)、成本和伸缩性问题
垂直拆分
将100张表分别放在5台服务器上,也就是每台数据库都只有20张表。
技巧: 将不同服务所对应的表放在不同的数据库中。
水平拆分
一般一个表的数据太慢,首先应该是在条件字段上建立索引,但是当数据特别大的时候,1个亿的数据,索引查询时间也会非常长。此时,当数据量达到一亿时,就需要考虑表的水平拆分。
一张表有4000w条数据,我们可以分别放在5张表中,这样每张表只有800w条数据。
总结:
1、不论是水平或者垂直拆分,都是为了解决数据库的访问效率问题。
2、垂直拆分解决表过多导致的效率慢,比如出现排队阻塞问题。
3、水平拆分解决单表的数据过多,导致的查询效率慢的问题。
MyCAT支持水平分片与垂直分片:
水平分片:一个表格的数据分割到多个节点上,按照行分隔。
垂直分片:一个数据库中多个表格A,B,C,A存储到节点1上,B存储到节点2上,C存储到节点3上。
MyCAT通过定义表的分片规则来实现分片,每个表格可以捆绑一个分片规则,每个分片规则指定一个分片字段并绑定一个函数,来实现动态分片算法。
Schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
Table:表,即物理数据库中存储的某一张表,与传统数据库不同,这里的表格需要声明其所存储的逻辑数据节点DataNode。在此可以指定表的分片规则。
DataNode:MyCAT的逻辑数据节点,是存放table的具体物理节点,也称之为分片节点,通过DataSource来关联到后端某个具体数据库上
DataSource:定义某个物理库的访问地址,用于捆绑到Datanode上
官方下载: http://www.mycat.org.cn/
github下载:https://github.com/MyCATApache/Mycat-Server/releases
1)、下载后解压
2)、在bin目录下启动运行startup_nowrap.bat
3)、登录
执行
mysql -u root -P 8066 -p
输入密码
4)、查询操作
因为是虚拟表,没有关联物理表,心跳失败,查看表结构或查询信息会报错
MyCat安装,需要安装jdk
1)、上传并解压
把MyCat的压缩包上传到linux服务器,并且解压
2)、启动
./opt/work/mycat/bin/mycat start #启动
./opt/work/mycat/bin/mycat stop #停止
./opt/work/mycat/bin/mycat restart #重启
3)、连接
可以使用MySQL自带的客户端进行连接,也可以使用可视化软件进行连接
mycat的默认的账号和密码都是test
客户端连接
mysql -h 10.211.55.12 -u test -p -P 8066
可视化工具连接:
注意:可以使用mysql的客户端直接连接mycat服务。默认服务端口为8066
将指定的一张表分片进行存储,比如存储到三个数据节点上
使用一台服务器模拟分片操作,创建三个数据库分别命名
db_mycat_1
db_mycat_2
db_mycat_3
ip地址:localhost
三个主要配置文件Server.xml、Schema.xml、rule.xml
server.xml几乎保存了所有mycat需要的系统配置信息。最常用的是在此配置用户名、密码及权限。
1)、user标签
<user name="root">
<property name="password">123456property>
<property name="schemas">TESTDBproperty>
<privileges check="false">
privileges>
user>
说明用户名是root,子标签: property,privileges
privileges标签
对用户的 schema以及表进行精细化的DML权限控制。
<privileges check="false"> privileges>
check表示是否开启DML权限检查。默认是关闭。
server.dtd文件中 `` 说明可以有多个schema的配置。
dml顺序说明:
insert,update,select,delete
<schema name="db1" dml="0110" >
<table name="tb01" dml="0000">table>
<table name="tb02" dml="1111">table>
schema>
db1的权限是update,select。
tb01的权限是啥都不能干。
tb02的权限是insert,update,select,delete。
其他表默认是udpate,select。
完整的user标签
<user name="root">
<property name="password">123456property>
<property name="schemas">TESTDBproperty>
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000">table>
<table name="tb02" dml="1111">table>
schema>
privileges>
user>
2)、system标签
基本上不用修改,用默认的设置
<property name="charset">utf8property> 字符集
<property name="processors">1property> 处理线程数量,默认是cpu数量。
<property name="processorBufferChunk">4096property> 每次读取留的数量,默认4096。
<property name="processorBufferPool">409600property> 创建共享buffer需要占用的总空间大小, processorBufferChunk*processors*100。
<property name="processorBufferPoolType">0property>默认为0。0表示 DirectByteBufferPool,1表示ByteBufferArena。
<property name="processorBufferLocalPercent">100property>二级共享buffer是 processorBufferPool的百分比,这里设置的是百分比。
<property name="sequnceHandlerType">100property>全局ID生成方式。(0:为本地文件方式,1:为数 据库方式;2:为时间戳序列方式;3:为ZK生成ID;4:为ZK递增ID生成。
<property name="useCompression">1property>是否开启mysql压缩协议。1为开启,0为关闭,默认关 闭。
<property name="packetHeaderSize">4property> 指定 Mysql 协议中的报文头长度。默认 4。
<property name="maxPacketSize">16Mproperty>指定 Mysql 协议可以携带的数据最大长度。默认 16M。
<property name="idleTimeout">1800000property>指定连接的空闲超时时间。某连接在发起空闲检查 下,发现距离上次使用超过了空闲时间,那么这个连接会被回收,就是被直接的关闭掉。默认 30 分钟,单位毫秒。
<property name="txIsolation">3property>前端连接的初始化事务隔离级别,只在初始化的时候使用,后 续会根据客户端传递过来的属性对后端数据库连接进行同步。 默认为 REPEATED_READ,设置值为数字默认 3。 READ_UNCOMMITTED = 1; READ_COMMITTED = 2; REPEATED_READ = 3; SERIALIZABLE = 4;
<property name="sqlExecuteTimeout">300property>SQL 执行超时的时间,Mycat 会检查连接上最后 一次执行 SQL 的时间,若超过这个时间则会直接关闭这连接。默认时间为 300 秒,单位秒。
<property name="processorCheckPeriod">1000property> 清理 NIOProcessor 上前后端空闲、超时和关闭连接的间隔时间。默认是 1 秒,单 位毫秒。
<property name="dataNodeIdleCheckPeriod">300000property> 对后端连接进行空闲、超时检查的时 间间隔,默认是 300 秒,单位毫秒。
<property name="dataNodeHeartbeatPeriod">10000property>对后端所有读、写库发起心跳的间隔时 间,默认是 10 秒,单位毫秒。
<property name="bindIp">0.0.0.0property>mycat 服务监听的 IP 地址,默认值为 0.0.0.0。
<property name="serverPort">8066property>定义 mycat 的使用端口,默认值为 8066。
<property name="managerPort">9066property>定义 mycat 的管理端口,默认值为 9066。
<property name="fakeMySQLVersion">5.6property>mycat 模拟的 mysql 版本号,默认值为 5.6 版 本,如非特需,不要修改这个值,目前支持设置 5.5,5.6,5.7 版本,其他版本可能会有问题。
<property name="useSqlStat">0property> 是否开启实时统计。1为开启;0为关闭 。
<property name="useGlobleTableCheck">0property>是否开启全局表一致性检测。1为开启;0为关闭
<property name="handleDistributedTransactions">0property>分布式事务开关。0为不过滤分布式 事务;1为过滤分布式事务;2 为不过滤分布式事务,但是记录分布式事务日志。
<property name="maxStringLiteralLength">65535property>默认是65535。 64K 用于sql解析时最 大文本长度 以上举例的属性仅仅是一部分,可以配置的变量很多,具体可以查看SystemConfig这个类的属性内容。 System标签下的属性,一般是上线后,需要根据实际运行的情况,分析后调优的时候进行修改。
3)、Firewall标签
顾名思义,这个就是关于防火墙的设置,也就是在网络层对请求的地址进行限制,主要是从安全角度来保证Mycat不被匿名IP进行访问
<firewall>
<whitehost>
<host host="127.0.0.1" user="mycat"/>
<host host="127.0.0.2" user="mycat"/>
whitehost>
<blacklist check="false"> blacklist>
firewall>
Schema.xml作为MyCat中重要的配置文件之一,管理着MyCat的逻辑库、表、分片规则、DataNode以及DataSource。弄懂这些配置,是正确使用MyCat的前提。这里就一层层对该文件进行解析。
schema 标签用于定义MyCat实例中的逻辑库
Table 标签定义了MyCat中的逻辑表
dataNode 标签定义了MyCat中的数据节点,也就是我们通常说所的数据分片。
dataHost 标签在mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
注意:若是LINUX版本的MYSQL,则需要设置为Mysql大小写不敏感,否则可能会发生表找不到的问题。
在 MySQL的配置文件中my.cnf 位置在etc目录下[mysqld] 中增加一行 lower_case_table_names = 1
datahost标签属性
--name 唯一标示dataHost标签,供上层使用
--maxCon 指定每个读写实例连接池的最大连接。
--minCon 指定每个读写实例连接池的最小连接,初始化连接池的大小
--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":所有读请求随机的分发到writeHst对应的readHost执行,writeHost不负担读压力。(1.4之后 版本有)
--writeType 负载均衡类型。
writeType="0", 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重 新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties
writeType="1",所有写操作都随机的发送到配置的 writeHost。1.5以后版本废弃不推荐。
--switchType -1不自动切换
1 默认值 自动切换
2 基于MySql主从同步的状态决定是否切换心跳语句为 show slave status
3 基于mysql galary cluster 的切换机制(适合集群) 心跳语句为 show status like 'wsrep%'
--dbType 指定后端链接的数据库类型目前支持二进制的mysql协议,还有其他使用jdbc链接的数据库,例如: mongodb,oracle,spark等
--dbDriver 指定连接后段数据库使用的driver,目前可选的值有native和JDBC。使用native的话,因为这个 值执行的是二进制的mysql协议,所以可以使用mysql和maridb,其他类型的则需要使用JDBC驱动来支持。
如果使用JDBC的话需要符合JDBC4标准的驱动jar 放到mycat\lib目录下,并检查驱动jar包中包括如下目录结构 文件 META-INF\services\java.sql.Driver。 在这个文件写上具体的driver类名,例如 com.mysql.jdbc.Driver writeHost readHost指定后端数据库的相关配置给mycat,用于实例化后端连接池。
--tempReadHostAvailable 如果配置了这个属性 writeHost 下面的 readHost 仍旧可用,默认 0 可配置(0、1)。
heartbeat 标签代表Mycat需要对物理库心跳检测的语句,正常情况下生产案例可能配置主从,或者多写 或者单 库,无论哪种情况Mycat都需要维持到数据库的数据源连接,因此需要定时检查后端连接可用性,心跳语句就是来作 为心跳检测。
writeHost 此标签代表 一个逻辑主机(dataHost)对应的后端的物理主机映射,例如例子中写库hostM1 映射到 127.0.0.1:3306。如果后端需要做读写分离或者多写 或者主从则通过配置 多个writeHost 或者readHost即可。
Schema.xml配置
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml里面就定义了我们对表进行拆分所涉及到的规则定义。我们可以灵活的对表使用不同的分片算法,或者对表使用相同的算法但具体的参数不同。 这个文件里面主要有tableRule和function这两个标签。在具体使用过程中可以按照需求添加tableRule和function。
分片规则(rule.xml)
分片规则是非常重要的配置,其决定了数据库切分后的性能好坏
rule.xml配置
默认有这个auto-sharding-long规则
<tableRule name="auto-sharding-long">
<rule>
<columns>idcolumns>
<algorithm>rang-longalgorithm>
rule>
tableRule>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txtproperty>
function>
name
为schema.xml 中table 标签中对应的 rule=“sharding-by-hour” ,也就是配置表的分片规则, columns
是表的切分字段: createTime 创建日期。
algorithm
是规则对应的切分规则:映射到function 的name。
function
配置是分片规则的配置。
name
为切分规则的名称,名字人员取,但是需要与tableRule 中匹配。
class
是切分规则对应的切分类,写死,需要哪种规则则配置哪种,例如本例子是按小时分片: org.opencloudb.route.function.LatestMonthPartion property 标签是切分规则对应的不同属性,不同的切分规则配置不同。
三个数据库分别创建一张表
注意:主键不要自增,因为要分片
CREATE TABLE product (
id INT PRIMARY KEY,
name VARCHAR(20),
price DOUBLE
)
插入数据
INSERT INTO product(id,name,price) value(1,"苹果",10);
INSERT INTO product(id,name,price) value(2,"香蕉",15);
INSERT INTO product(id,name,price) value(5000001,"梨",12);
INSERT INTO product(id,name,price) value(5000002,"水蜜桃",8);
INSERT INTO product(id,name,price) value(10000001,"西瓜",6);
INSERT INTO product(id,name,price) value(10000002,"芒果",9);
由于auto-sharding-long配置的规则:三个数据库db_mycat_1存放id编号1-5000000的数据,db_mycat_1存放id编号5000001-10000000的数据,db_mycat_3存放id编号10000001-15000000的数据。
对虚拟表product执行插入以上数据,会默认分到对应的数据库,当插入数据超过1000会报异常。
MySQL作为世界上使用最为广泛的数据库之一,免费是其原因之一。但不可忽略的是它本身的功能的确很强大。随着技术的发展,在实际的生产环境中,由单台MySQL数据库服务器不能满足实际的需求。此时数据库集群就很好的解决了这个问题了。采用MySQL分布式集群,能够搭建一个高并发、负载均衡的集群服务器(这篇博客暂时不涉及)。在此之前我们必须要保证每台MySQL服务器里的数据同步。数据同步我们可以通过MySQL内部配置就可以轻松完成,主要有主从复制和主主复制。
数据库读写分离对于大型系统或者访问量很高的互联网应用来说,是必不可少的一个重要功能。
对于MySQL来说,标准的读写分离是主从模式,一个写节点Master后面跟着多个读节点,读节点的数量取决于系统的压力,通常是1-3个读节点的配置
Mycat读写分离和自动切换机制,需要mysql的主从复制机制配合。
主从配置需要注意的地方
1、主DB server和从DB server数据库的版本一致
2、主DB server和从DB server数据库数据一致[ 这里就会可以把主的备份在从上还原,也可以直接将主的数据目录拷贝到从的相应数据目录]
3、主DB server开启二进制日志,主DB server和从DB server的server_id都必须唯一
准备工作:
1、两个mysql,分布在不同主机上的两台mysql数据库,都是linux系统,阿里云和vm虚拟主机
2、两个mysql版本一致,都是5.7.26
3、创建数据库db1并创建product表,数据进行拷贝到从机,保持数据的一致性
4、阿里云的mysql为主机,vm虚拟机mysql为从机
1)、修改my.cnf文件
vim /etc/my.cnf
修改的内容为:
在[mysqld]段下添加
#启用的数据库
binlog-do-db=db1
#忽略的数据库
binlog-ignore-db=mysql
#启用二进制日志
log-bin=mysql-bin
#服务器唯一ID,一般取IP最后一段
server-id=1
2)、登录创建数据库、创建用户及赋权
#登录mysql
mysql -u root -p
#创建db1数据库
create database db1 character set utf8 collate utf8_general_ci;
#创建一个用户,%表示任意ip可以使用该用户远程操作,也可以指定ip地址
create user 'abc'@'%' IDENTIFIED BY '123456';
#赋予该用户远程操作db1数据库的完全权限
GRANT ALL ON db1.* TO 'abc'@'%';
service mysql restart
下面的操作都需要连接Mysql的服务器进行设置
#登录mysql
mysql -u root -p
4)、建立帐户并授权slave
#注意:此处不能写db1.*,必须写*.*
GRANT REPLICATION SLAVE ON *.* to 'abc'@'%' identified by '123456';
#刷新权限
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
select user,host from mysql.user;
一般不用root帐号,“%”表示所有客户端都可能连,只要帐号,密码正确,此处可用具体客户端IP代替,如 10.211.55.12,加强安全。
1)、修改配置文件
vim /etc/my.cnf
修改内容如下:
server-id=131 #服务唯一地址
relay-log=slave-relay-bin
relay-log-index=slave-relay-bin.index
修改了配置文件需要重启mysql
service mysql restart
下面的操作都需要连接Mysql的服务器进行设置
#登录mysql
mysql -u root -p
2)、配置从服务器
#使用root用户登录从机后,执行以下sql
change master to master_host='121.196.62.166',master_port=3306,master_user='abc',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=580;
注意语句中间不要断开,master_port为mysql服务器端口号(无引号),master_user为执行同步操作的数据库账户,580无单引号(此处的439就是show master status 中看到的position的值,这里的mysql-bin.000001 就是file对应的值)。
3)、启动从服务器复制功能
start slave;
检查从服务器复制功能状态
show slave status\G;
……………………(省略部分)
Slave_IO_Running: Yes //此状态必须YES
Slave_SQL_Running: Yes //此状态必须YES
……………………(省略部分)
注:Slave_IO及Slave_SQL进程必须正常运行,即YES状态,否则都是错误的状态(如:其中一个NO均属错误)。
Mycat 1.4开始 支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="10000">
<table name="product" dataNode="dn1" rule="auto-sharding-long" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>show slave statusheartbeat>
<writeHost host="hostM1" url="121.196.62.166:3306" user="root"
password="123456">
<readHost host="hostS2" url="172.20.10.9:3306" user="root" password="123456" />
writeHost>
dataHost>
mycat:schema>
规则文件autopartition-long.txt
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
1、设置 balance="1"与writeType="0"
Balance参数设置:
1)balance=“0”, 所有读操作都发送到当前可用的writeHost上。
2)balance=“1”,所有读操作都随机的发送到readHost。
3)balance=“2”,所有读操作都随机的在writeHost、readhost上分发
WriteType参数设置:
1)、writeType=“0”, 所有写操作都发送到可用的writeHost上。
2)、writeType=“1”,所有写操作都随机的发送到readHost。
3)、writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。
“readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据,因此,当它所属的writeHost 宕机了,则它也不会再参与到读写分离中来,即“不工作了”,这是因为此时,它的数据已经“不可靠”了。
基于这个考虑,目前mycat1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下, 从节点还能读取数据,则需要在Mycat里配置为两个writeHost并设置banlance=1。”
2、设置 switchType="2" 与slaveThreshold="100"
switchType 目前有三种选择:
-1:表示不自动切换
1 :默认值,自动切换
2 :基于MySQL主从同步的状态决定是否切换
“Mycat心跳检查语句配置为 show slave status ,dataHost 上定义两个新属性: switchType="2" 与 slaveThreshold="100",此时意味着开启MySQL主从复制状态绑定的读写分离与切换机制。
Mycat心跳机制通过检测 show slave status 中的 "Seconds_Behind_Master", "Slave_IO_Running", "Slave_SQL_Running" 三个字段来确定当前主从同步的状态以及Seconds_Behind_Master主从复制时延。
分片规则配置文件rule.xml位于$MYCAT_HOME/conf目录,它定义了所有拆分表的规则。在使用过程中可以灵活使用不同的分片算法,或者对同一个分片算法使用不同的参数,它让分片过程可配置化,只需要简单的几步就可以让运维人员及数据库管理员轻松将数据拆分到不同的物理库中。
该文件包含两个重要的标签,分别是Function和tableRule。
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txtproperty>
function>
name
:属性指定算法的名称,在该文件中唯一。class
:属性对应具体的分片算法,需要指定算法的具体类。property
:属性根据算法的要求指定。<tableRule name="auto-sharding-long">
<rule>
<columns>idcolumns>
<algorithm>rang-longalgorithm>
rule>
tableRule>
name
:属性指定分片规则的名称,在该文件中唯一。rule
:属性指定分片算法的具体内容,包含 columns 和 algorithm 两个属性。columns
:属性指定对应的表中用于分片的列名。algorithm
:属性对应function中指定的算法的名称。连续分片规则 * 自定义数字范围分片 * 按日期(天)分片 * 按单月小时分片 * 自然月分片
适用于明确知道分片字段的某个范围属于哪个分片,其字段为数字类型。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="auto-sharding-long">
<rule>
<columns>idcolumns>
<algorithm>rang-longalgorithm>
rule>
tableRule>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txtproperty>
function>
mycat:rule>
配置说明:
autopartition-long.txt
# range start-end ,data node index # K=1000,M=10000.
0-2M=0
2M-3M=1
3M-6M=2
注意:schema里的table的dataNode节点个数必须 大于等于 autopartition-long.txt 里的配置个数dataNode节点从0开始
根据时间类型字段,按天分片。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-day" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-day">
<rule>
<columns>create_timecolumns>
<algorithm>part-by-dayalgorithm>
rule>
tableRule>
<function name="part-by-day"
class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-ddproperty>
<property name="sBeginDate">2017-10-01property>
<property name="sPartionDay">10property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段。algorithm
:为分片函数。dateFormat
:为日期格式。sBeginDate
:为开始日期。sEndDate
:为结束日期,如果配置了这个属性,则代表数据达到了这个日期的分片后会重复从开始分片插入。sPartionDay
:为分区天数,默认从开始日期算起,每隔10天一个分区。注意 当配置的dataNode节点数为3,而2017-10-31为2017-10-01后的第四个10天中的第一天,因此需要至少4个dataNode,节点不够就报错。
单月内按照小时拆分,最小粒度是小时,一天最多可以有24个分片,最少1个分片,下个月从头开始循环,每个月末需要手工清理数据。
字段为字符串类型, yyyymmddHH 10位。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-hour" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-hour">
<rule>
<columns>sharding_colcolumns>
<algorithm>sharding-by-houralgorithm>
rule>
tableRule>
<function name="sharding-by-hour"
class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">3property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段,字符串类型( yyyymmddHH ),格式需要符合Java标准。
algorithm
:为分片函数。
splitOneDay
:为一天切分的分片数。
注意:分片数必须跟dataNode节点数一致最大分24个分片分片字段的值必须是字符串,如:2017103112.(即为2017年10月31日12点)
使用场景为按月份列分区,每个自然月一个分片,查询条件时使用between and。 字段为时间类型。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-month" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-month">
<rule>
<columns>create_timecolumns>
<algorithm>sharding-by-monthalgorithm>
rule>
tableRule>
<function name="sharding-by-month"
class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-ddproperty>
<property name="sBeginDate">2017-10-01property>
<property name="sEndDate">2017-12-30property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段,字符串类型,与 dateFormat 格式一致。
algorithm
:为分片函数。
dateFormat
:为日期字符串格式。
sBeginDate
:为开始日期。
sEndDate
:为结束日期
注意:schema里的table的dataNode节点数必须:大于rule的开始时间按照分片数计算到现在的个数 * 按照自然月计算(无论是28、30、31天都是一个月的) 分片节点个数可以后增加,但是必须符合第一点说明。
离散分片规则:枚举分片、程序指定分区的分片、十进制求模分片、字符串hash解析分片、一致性哈希分片
通过在配置文件中配置可能的枚举id,指定数据分布到不同的物理节点上,本规则适用于按照省份或区县来拆分数据类业务。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-intfile" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-intfile">
<rule>
<columns>agecolumns>
<algorithm>hash-intalgorithm>
rule>
tableRule>
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txtproperty>
<property name="type">0property>
<property name="defaultNode">0property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段
algorithm
:为分片函数。
partition-hash-int.txt
# 枚举项=节点标识,枚举项可以是数字和字符(非汉字)
11=1
12=2
注意:schema里的table的dataNode节点个数必须:大于等于 partition-hash-int.txt里的配置个数
在程序运行阶段,由程序自主决定路由到哪个分片。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-substring" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-substring">
<rule>
<columns>agecolumns>
<algorithm>sharding-by-substringalgorithm>
rule>
tableRule>
<function name="sharding-by-substring"
class="io.mycat.route.function.PartitionDirectBySubString">
<property name="startIndex">0property>
<property name="size">2property>
<property name="partitionCount">3property>
<property name="defaultPartition">0property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段。
algorithm
:为分片函数。
startIndex
:为字符串开始截取位,从0开始。
size
:为截取的位数。
partitionCount
:为分片个数
defaultPartition
:为默认节点
注意:直接根据字符子串(必须是数字)计算分区号(由应用传递参数,指定分区号)。
例如user_id=05-10000 ,其中 user_id 是从 startIndex=0 开始的,截取长度为两位数字,即05,05就是获取的分区,默认分配到 defaultPartition 。
对分片字段十进制取模运算,其数据分布最均匀。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-substring" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-substring">
<rule>
<columns>agecolumns>
<algorithm>sharding-by-substringalgorithm>
rule>
tableRule>
<function name="sharding-by-substring"
class="io.mycat.route.function.PartitionDirectBySubString">
<property name="startIndex">0property>
<property name="size">2property>
<property name="partitionCount">3property>
<property name="defaultPartition">0property>
function>
mycat:rule>
配置说明:
columns 标识将要分片的表字段。
algorithm 为分片函数。
startIndex 为字符串开始截取位,从0开始。
size 为截取的位数。
partitionCount 为分片个数
defaultPartition 为默认节点
注意:对分片字段十进制取模运算, dataNode=id%count 数据分布最均匀。 扩容需要重新计算分片,数据迁移繁琐。尽量的提前计算出来增量,创建足够多的分片数。但是也不宜太多,给运维造成负担。平衡点自己掌控。
此规则是截取字符串中的int数值的hash分片
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-stringhash" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-stringhash">
<rule>
<columns>ord_nocolumns>
<algorithm>sharding-by-stringhashalgorithm>
rule>
tableRule>
<function name="sharding-by-stringhash"
class="io.mycat.route.function.PartitionByString">
<property name="partitionLength">512property>
<property name="partitionCount">2property>
<property name="hashSlice">-6:0property>
function>
mycat:rule>
配置说明:
columns
:标识将要分片的表字段。
algorithm
:为分片函数。
partitionLength
:为字符串hash的求模基数。
partitionCount
:为分区数。其中partitionLength*partitionCount=1024 hashSlice
:为预算位,即根据子字符串中的int值进行hash运算。 0 代表 str.length(), -1 代表str.length()-1,大于0只代表数字自身 可以理解为substring(start,end),start为0则只表示0 例1:值“45abc”,hash预算位0:2 ,取其中45进行计算 例2:值“aaaabbb2345”,hash预算位-4:0 ,取其中2345进行计算
注意: 分片数量必须小于等于dataNode数
一致性hash算法有效解决了分布式数据的扩容问题。因为此规则优点在于扩容时迁移数据量比较少,前提是分片节点比较多,虚拟节点分配多些。虚拟节点分配的少就会造成数据分布不够均匀。但如果实际分片数据比较少,迁移量也会比较多。
schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="product" dataNode="dn$1-3" rule="sharding-by-murmurhash" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db_mycat_1" />
<dataNode name="dn2" dataHost="localhost1" database="db_mycat_2" />
<dataNode name="dn3" dataHost="localhost1" database="db_mycat_3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
writeHost>
dataHost>
mycat:schema>
rule.xml
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-murmurhash">
<rule>
<columns>idcolumns>
<algorithm>sharding-by-murmurhashalgorithm>
rule>
tableRule>
<function name="sharding-by-murmurhash"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0property>
<property name="count">2property>
<property name="virtualBucketTimes">160property>
function>
mycat:rule>
注意 : 分片数量必须小于等于dataNode数
mycat注意事项:
1、在mycat进行查询的时候,不可以用* 进行查询,必须添加字段名进行查询 2、Mycat 不支持这种语法。DELETE d from hotspot d
3、表结构同步到mycat要做的修改
1)、第一种是原来的表自增主键,现在如果编程跨库的表了。则要换成全局序列主键。原始表的自增主键要去掉
ALTER TABLE `hotspot`
ALTER `id` DROP DEFAULT;
ALTER TABLE `hotspot`
CHANGE COLUMN `id` `id` INT(11) NOT NULL COMMENT '临时表id 与主id无关' FIRST;
2)、mycat不支持联合主键:所以这个表改成自增主键。原来的联合主键变成:唯一约束
ALTER TABLE `m_base_term`
ADD COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT FIRST,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`),
ADD UNIQUE INDEX `ecode_termid` (`ecode`, `termid`);
4、Mycat有一些不支持、或者支持不好的函数
IFNULL 如下图的sql。Mycat不会进行结果合并。而是返回三个结果。
SELECT
IFNULL(max(kid),0)
as max
FROM access_record_inout_temp2
所以要改成下面这种格式。
SELECT
MAX(t.max) as max
FROM
(
SELECT
IFNULL(max(id),0)
as max
FROM m_rec_consume_copy
)t