MyCat分片&读写分离

MyCat简介

MyCat来自阿里曾经开源知名产品–Cobar。Cobar核心功能和优势是MySQL数据库分片,此产品曾经广为流传,据说最早的发起者对 Mysql 很精通,后来从阿里跳槽了,阿里随后开源的 Cobar,并维持到 2013 年年初。

Cobar 的思路和实现路径的确不错。基于 Java 开发的,实现了 MySQL 公开的二进制传输协议,巧妙地将自己伪装成一个 MySQL Server,目前市面上绝大多数 MySQL 客户端工具和应用都能兼容。比自己实现一个新的数据库协议要明智的多,因为生态环境在哪里摆着。

MyCat 是基于 cobar 演变而来,对 Cobar 的代码进行了彻底的重构,使用 NIO 重构了网络模块,并且优化了 Buffer 内核,增强了聚合,Join 等基本特性,同时兼容绝大多数数据库成为通用的数据库中间件。

简单的说,MyCat就是:一个新颖的数据库中间件产品支持mysql集群,或者mariadb cluster,提供高可用性数据分片集群。你可以像使用mysql一样使用MyCat。对于开发人员来说根本感觉不到MyCat的存在。

在这里插入图片描述

MyCat支持的数据库:
在这里插入图片描述

MyCat下载和安装

配置java环境(略)

上传MyCat安装包

解压缩MyCat

tar xvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz  -C /usr/local

输入:

hostname

如果主机名显示为:

bogon

就需要修改主机名称ip地址对应配置文件

vi /etc/hosts

增加主机名和ip对应关系

127.0.0.1   bogon

启动Mycat

./mycat start

检查mycat启动状态

ps -ef | grep mycat

查看mycat的对应端口是否监听

netstat -antp | grep 8066
//如果命令没找到执行 yum install net-tools -y

防火墙释放8066端口

firewall-cmd --add-port=8066/tcp --permanent
firewall-cmd --reload

MySQL下载和安装

JDK:1.8版本以上

MySQL:推荐5.5版本以上

将MySQL的服务端和客户端安装包以及所需类库包(RPM)上传到服务器

mysql-community-client-5.7.20-1.el7.x86_64.rpm
mysql-community-common-5.7.20-1.el7.x86_64.rpm
mysql-community-libs-5.7.20-1.el7.x86_64.rpm
mysql-community-server-5.7.20-1.el7.x86_64.rpm

查询服务器确认是否安装过mysql和开源社区版的mariadb

rpm -qa | grep mysql
rpm -qa | grep mariadb

如果查找到,就需要卸载:

rpm -e --nodeps mariadb-libs-5.5.56-2.el7.x86_64

开始安装,安装顺序很重要

rpm -ivh mysql-community-common-5.7.20-1.el7.x86_64.rpm

rpm -ivh mysql-community-libs-5.7.20-1.el7.x86_64.rpm

rpm -ivh mysql-community-client-5.7.20-1.el7.x86_64.rpm

安装server包之前,需要安装MySQL所需依赖包

yum install perl net-tools -y

不然会报错:

 error: Failed dependencies:
        /usr/bin/perl is needed by mysql-community-server-5.7.20-1.el7.x86_64
        net-tools is needed by mysql-community-server-5.7.20-1.el7.x86_64
        perl(Getopt::Long) is needed by mysql-community-server-5.7.20-1.el7.x86_64
        perl(strict) is needed by mysql-community-server-5.7.20-1.el7.x86_64

最后安装server包 :

rpm -ivh mysql-community-server-5.7.20-1.el7.x86_64.rpm

如果出现:

warning: mysql-community-server-5.7.20-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY

重新输入:

rpm -ivh mysql-community-server-5.7.20-1.el7.x86_64.rpm --force –nodeps

原因:这是由于yum安装了旧版本的GPG keys造成的

初始化数据库,执行后会在/var/log/mysqld.log生成随机密码

mysqld --initialize

如果出现:

mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory

输入:

yum install -y libaio

安装后再初始化就OK了

查看密码:

cat /var/log/mysqld.log

找到root账号的临时密码:(@localhost:后边的就是临时密码)

A temporary password is generated for root@localhost: rjMAqWFj9>rZ

查看数据存储目录权限

ll /var/lib/mysql

修改mysql数据存储目录所属权限

chown mysql:mysql /var/lib/mysql -R

启动数据库

systemctl start mysqld    //启动mysql数据库命令

systemctl status  mysqld  //查看mysql数据库启动状态

systemctl stop  mysqld    //停止mysql数据库

systemctl restart  mysqld  //重启mysql数据库

使用mysql命令行客户端登录mysql数据库

mysql -uroot -p  -h 127.0.0.1 -P 3306
//-u登录账户 -p登录密码 -h数据库主机地址 -P数据端口号(默认端口3306可以不用输入)

首次登录必须重置root密码

set password=password('123456');

开启root账号远程使用权限

use mysql;
select user,host from user; //发现root账号限制只能本机登陆
update user set host = '%' where user = 'root'; //修改root账号允许远程登录
flush privileges; //刷新权限

开放linux防火墙对应MySQL数据库端口

firewall-cmd --zone=public --add-port=3306/tcp --permanent 
firewall-cmd --reload 
firewall-cmd --list-all

安装完成之后克隆出4台服务器

MyCat分片

什么是分片

简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。

数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

  1. 一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切分可以称之为数据的垂直(纵向)切分,可以达到降低单台数据库服务器负载压力。
  2. 另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。比如单表如果数据超过500w条,性能会急剧下降,可以分为多个表放到多个数据库主机,每个表数据结构相同。
MyCat分片策略:

在这里插入图片描述

分片相关的概念
逻辑库(schema)

前面一节讲了数据库中间件,通常对实际应用来说,并不需要知道中间件的存在,业务开发人员只需要知道数据库的概念,所以数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。

逻辑表(table):

分片表:是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。
总而言之就是需要进行分片的表。

非分片表:一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。

分片节点(dataNode):

数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。

节点主机(dataHost):

数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。

分片规则(rule):

前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。

MyCat分片配置
配置schema.xml

schema.xml作为MyCat中重要的配置文件之一,管理着MyCat的逻辑库、逻辑表以及对应的分片规则、DataNode以及DataSource。弄懂这些配置,是正确使用MyCat的前提。这里就一层层对该文件进行解析。

schema 标签用于定义MyCat实例中的逻辑库

Table 标签定义了中的逻辑表用于指定分片规则,auto-sharding-long的分片规则是按ID值的范围进行分片 1-5000000 为第1片 5000001-10000000 为第2片…

dataNode 标签定义了MyCat中的数据节点,也就是我们通常说所的数据分片。

dataHost标签在mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。

在服务器上创建3个数据库,分别是db1,db2.db3

修改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="demo1" primaryKey="ID" type="global" dataNode="dn1,dn2"/>
		<table name="demo2" rule="auto-sharding-long" dataNode="dn1,dn2,dn3"/>
 	</schema>
	
	<dataNode name="dn1" dataHost="host1" database="db1"/>
	<dataNode name="dn2" dataHost="host2" database="db2"/>
	<dataNode name="dn3" dataHost="host1" database="db3"/>
	
	<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.188.135:3306" user="root"
				   password="123456" >
		</writeHost>
	</dataHost>
	
	<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.188.136:3306" user="root"
				   password="123456" />
		
	</dataHost>
	
	
</mycat:schema>

解释:schema为逻辑库,table有demo1为全局表,分片节点对应dn1和dn2。demo2位分片表,分片规则按照auto-sharding-long,对应分片节点为dn1,dn2,dn3分别对应db1,db2,db3数据库。db1数据库和db3数据库对应节点主机为host1,上文安装配置mysql的一台机器(192.168.188.135),db2数据库对应节点主机为host2(192.168.188.136).

rule.xml为规则配置文件,当我们需要将数据平均分在几个分区中,需要使用一致性hash规则

<function name="murmur"
		class="org.opencloudb.route.function.PartitionByMurmurHash">
		<property name="seed">0</property><!-- 默认是0 -->
		<property name="count">3</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
		<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
		<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
		<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 
			用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
	</function>

demo2分片表所用规则auto-sharding-long可以在该文件中找到:

<tableRule name="auto-sharding-long">
		<rule>
             //规则指定的列是id ,如果我们的表主键不是id ,而是demo2_id,可以修改为demo2_id
			<columns>id</columns>
			<algorithm>rang-long</algorithm>
		</rule>
</tableRule>

tableRule 是定义具体某个表或某一类表的分片规则名称,再次搜索rang-long定义:

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

Function用于定义算法 mapFile 用于定义算法需要的数据,我们打开autopartition-long.txt

# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2

由此可见该分片规则按照ID值从0开始每500万分成一片

重启MyCat

关闭MyCat

./mycat stop

清空日志

cd ../logs/
rm -rf *

重启

cd ../bin/
./mycat start

查看日志

cat wrapper.log
配置server.xml

server.xml几乎保存了所有mycat需要的系统配置信息。最常用的是在此配置用户名、密码及权限。在system中添加UTF-8字符集设置,否则存储中文会出现问号

<property name="charset">utf8</property>

默认有两个用户,我们使用root用户

<user name="root">
		<property name="password">123456</property>
		<property name="schemas">TESTDB</property>
		
		<!-- 表级 DML 权限设置 -->
		<!-- 		
		<privileges check="false">
			<schema name="TESTDB" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
		</privileges>		
		 -->
	</user>

	<user name="user">
		<property name="password">user</property>
		<property name="schemas">TESTDB</property>
		<property name="readOnly">true</property>
	</user>
MyCat分片测试

windows命令行连接MyCat:

mysql -u root -p -h 192.168.188.134 -P 8066

查看数据库:

show databases;

存在TESTDB逻辑库

查看数据表:

show tables;

存在demo1,demo2两个表

查看表结构:

desc demo1;

发现提示出错,表不存在.

创建demo1表:

CREATE TABLE demo1 (
  id BIGINT(20) PRIMARY KEY,
  msg VARCHAR(100) NOT NULL 
) ENGINE=INNODB DEFAULT CHARSET=utf8 

结果:

此时我们发现135主机db1数据库和136主机db2数据库demo1表已经自动创建好了,神奇!

我们插入值发现db1和db2数据会都会自动插入!

我们再建demo2表:

CREATE TABLE demo2 (
  id BIGINT(20) PRIMARY KEY,
  msg VARCHAR(100) NOT NULL 
) ENGINE=INNODB DEFAULT CHARSET=utf8 

结果:

观察数据库发现db1,db2,db3数据库demo2表都已经建好,如果插入数据会根据id值范围分布到db1,db2,db3中(注意如果插入数据超过1500M需要在autopartition-long.txt再配置一个节点,必须新增一个数据库对应此节点,重启mycat再连接测试)!!!

MyCat读写分离

数据库读写分离对于大型系统或者访问量很高的互联网应用来说,是必不可少的一个重要功能。对于MySQL来说,标准的读写分离是主从模式,一个写节点Master后面跟着多个读节点,读节点的数量取决于系统的压力.

在这里插入图片描述

在这里插入图片描述

Mycat读写分离和自动切换机制,需要mysql的主从复制机制配合。

MySql主从复制

主从配置注意:

  1. 主DB server和从DB server数据库的版本一致
  2. 主DB server和从DB server数据库数据名称一致
  3. 主DB server开启二进制日志,主DB server和从DB server的server_id都必须唯一
Mysql主服务器配置(主库)

修改/etc/my.cnf文件:

在[mysqld]段下添加:

#多个库写多行
binlog-do-db=db1  
binlog-do-db=db3
#要忽略的数据库
binlog-ignore-db=mysql 
#启用二进制日志
log-bin=mysql-bin
#服务器唯一ID,一般取IP最后一段
server-id=135

重启mysql服务:

systemctl restart mysqld

进入mysql:

mysql -uroot -p

建立帐户并授权slave:

mysql>GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';

刷新权限:

flush privileges;

查看主库日志记录状态:

show master status;

记录 :

File:日志文件名称 mysql-bin.000001
Position:日志编号 431
Mysql从服务器配置(从库)

修改读库的配置文件:

vi /etc/my.cnf

在[mysqld]段下添加:

server-id=137

重启MySQL数据库:

systemctl restart mysqld

在从数据库执行命令挂载主数据库:

sql>  change master to master_host='192.168.188.135',master_port=3306,master_user='backup',master_password='123456';

注意:如果mysql数据库版本低于 5.7 需要增加2个参数:

sql> change master to master_host='192.168.188.135',master_port=3306,master_user='backup',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=431;

启动从服务器复制功能:

sql> start slave;

查看从服务器状态:

 sql> show slave status \G;
……………………(省略部分)
Slave_IO_Running: Yes //此状态必须YES如果为NO,出现此错误:
Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
因为是mysql是克隆的系统所以mysql的uuid是一样的,所以需要修改。删除/var/lib/mysql/auto.cnf文件,执行rm-rf /var/lib/mysql/auto.cnf,重新启动mysql服务,执行systemctl restart mysqld。

Slave_SQL_Running: Yes //此状态必须YES如果为NO需要执行
1、停掉从服务器
mysql> stop slave;

2、跳过sql执行错误:注意执行一次跳过一个错误,一直到跳过全部错误
mysql> set global sql_slave_skip_counter=1;

3、启动从服务器(重新挂载)
mysql> start slave;

注:Slave_IO及Slave_SQL进程必须正常运行,即YES状态,否则都是错误的状态(如:其中一个NO均属错误)
……………………(省略部分)

此时操作主数据库,写入数据,从库自动更新!

MyCat配置

Mycat 1.6 支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠,配置如下:

修改文件位置:/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="demo1" primaryKey="ID" type="global" dataNode="dn1"/>
		<table name="demo2" rule="auto-sharding-long" dataNode="dn1,dn2,dn3,dn4"/>
		<table name="demo3" rule="sharding-by-murmur" dataNode="dn1,dn2,dn3,dn4"/>
 	</schema>
	
	<dataNode name="dn1" dataHost="host1" database="db1"/>
	<dataNode name="dn2" dataHost="host2" database="db2"/>
	<dataNode name="dn3" dataHost="host1" database="db3"/>
	<dataNode name="dn4" dataHost="host2" database="db4"/>
	
	<dataHost name="host1" 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.188.135:3306" user="root"
				   password="123456" >
			<readHost host="hostR1" url="192.168.188.137:3306" user="root" 
				   password="123456"/>
		</writeHost>
	</dataHost>
	
	<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.188.136:3306" user="root"
				   password="123456" />
		
	</dataHost>
	
	
</mycat:schema>

Schema标签:name指明schema逻辑数据库的名称,checkSQLschema是否去除sql语句中的数据库名称,如果sql查询语句没有limit语句,sqlMaxLimit为查询语句加上limit。

dataNode标签:定义节点,指定数据虚拟服务器,数据库等属性

dataHost标签:定义具体的数据库实例,读写分离配置,心跳包语句。maxCon属性指定每个读写实例连接池的最大连接。minCon属性指定每个读写实例连接池的最小连接。

balance属性,目前的取值有 4 种:

​ balance=“0”, 不开启读写分离机制,所有读写操作都发送到当前可用的writeHost 上。

​ balance=“1”,所有读操作都随机的发送到readHost

​ balance=“2”,所有读操作都随机的在 writeHost、 readhost 上分发。

​ balance=“3”, 所有读请求随机分发到 wiriterHost 对应的 readhost 执行

writeType属性,负载均衡类型,目前的取值有3种:

​ writeType=”0”, 所有写操作都发送到可用的writeHost上。

​ writeType=”1”,所有写操作都随机的发送到readHost。

writeType=”2”,所有写操作都随机的在writeHost、readhost分上发。

switchType 属性:

​ -1 表示不自动切换

​ 1 默认值,自动切换

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

writeHost,readHost,heartBeat标签,定义真实服务器的读写Host,heartBeat为心跳包语句。以上定义了一主一从的读写分离机制,writeHost下可以有多个readHost。

由于修改了分片节点,所以使用分片规则需要重新配置,修改rule.xml

<function name="murmur"
		class="io.mycat.route.function.PartitionByMurmurHash">
		<property name="seed">0</property><!-- 默认是0 -->
		<property name="count">4</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
		<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
		<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
		<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 
			用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
	</function>

修改autopartition-long.txt

# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
1500M-2000M=3
测试读写分离

进入bin目录启动mycat (确保配置的读写分离Host已经配置了主从数据同步),启动mycat

cd /usr/local/mycat/logs/
rm -rf *
cd /usr/local/mycat/bin
./mycat start
cd ../logs/
cat wrapper.log

windows命令行连接MyCat:

mysql -u root -p -h 192.168.188.134 -P 8066

查看数据库:

show databases;

存在TESTDB逻辑库

use TESTDB;

查看数据表:

show tables;

查看demo1表结构:

desc demo1;

插入数据:

insert into demo1 (id,msg)values(123,’body1’);

查看主库从库数据都已经插入!!!

从主机停掉主从复制:

stop slave;

再次插入数据:

insert into demo1 (id,msg)values(124,’body2’);

查询demo1所有数据:

select * from demo1;

如果查询不到最后一条数据,说明读写分离成功!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值