Mycat是数据库中间件。
使用场景:
- 高可用性与Mysql读写分离
- 业务数据分级存储
- 大表水平拆分,集群并行计算
- 数据库连接池
- 整合多个数据源整合
安装
下载地址:http://dl.mycat.org.cn
安装Mycat之前,需要安装Mysql、JDK,安装Mycat稳定版是1.6.7.1。
下载好的安装包文件 (Mycat-xxx-linux.tar.gz),上传Linux服务器上,一般安装在/usr/local下,进行解压
tar -zxvf Mycat-xxx-linux.tar.gz
安装成功,进入mycat目录,能看到
- bin:命令文件
- catlet:空的,扩展
- conf:配置文件(server.xml,schema.xml,rule.xml等)
- lib:依赖的jar包
核心概念
分片
我们将存放同一个数据库中数据分散到多个数据库中,达到单台设备负载效果。当数据库量超过800万,需要做分片处理。
数据库切分:
- 垂直拆分:如果因为表多导致数据多,使用垂直切分,根据业务切分成不同的库;
- 横向拆分:如果因为单张表的数据量太大,使用水平切分。分库分表的顺序应该是先垂直分,后水平分。
垂直拆分:
- 垂直分表:大表拆小表,一般是表中的字段较多,将不常用的,数据较大,长度较长字段的拆分到“扩展表。
- 垂直分库:针对系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。 切分后,放在多个服务器上。在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈。
水平拆分:
- 水平分表:针对数据量大的单张表,按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。
- 水平分库分表:将单表的数据切分到多个服务器上,每个服务器具有相应的库与表,只是表中数据集合不同。 切分规则:1. 从0到10000一个表,10001到20000一个表;2. HASH取模; 3. 地理区域。
逻辑库
Mycat是数据库中间件,可以被看做一个/多个数据库集群构成的逻辑库。然后下面的逻辑表,读写数据的表就是逻辑表。
ER表
表的记录与所有关联的父表记录存放同一个数据分片中,保证数据关联查询不会垮库操作。
全局表
类似于数据字典表,把这些冗余数据定义为全局表。
分片节点
数据切分,一个大表被分到不同的分片数据库上,每个表分片所在数据库就是分片节点。
分片主机
同一机器上存在多个分片数据库,这个分片节点所在的机器是节点主机。
常用命令
启动Mycat:
bin/mycat start
bin/mycat stop
bin/mycat status
查看Mycat:
连接命令:连接端口号:8066
mysql -h (IP地址) -P 8066 -u root -p
连接管理命令:连接端口号:9066
mysql -h (IP地址) -P 9066 -u root -p
配置server.xml
常用系统配置
- charset 值 utf8 字符集
- useSqlStat 值 0 1 开启实时统计 0 关闭
- sqlExecuteTimeout 值 1000 SQL语句超时时间
- processors 值1,2… 指定线程数量
- txIsolation 值1,2,3,4 事务的隔离级别
- serverPort 值8066 使用端口号
- mangerPort 值9066 管理端口号
user 标签定义登录Mycat用户和权限:
<user name="mycat用户名2">
<property name="password">密码</property>
<property name="schemas">逻辑库名</property>
<property name="readOnly">true(是否只读)</property>
<property name="benchmark">1000(连接数,0代表不限制)</property>
<property name="usingDecrypt">1(是否加密,1加密)</property>
<!--权限设置-->
<privileges check="true">
<schema name="逻辑库名" dml="0000">
<table name="逻辑表" dml="0000"></table>
<table name="逻辑表" dml="0000-代表增改查删的权限,1代表有,0没有"></table>
</schema>
</privileges>
</user>
# 注意
# 设置了密码加密,需要在/lib目录下执行
java -cp Mycat-server-xxx.release.jar io.maycatutil.DecryptUtil 0:root:密码
# 然后得到加密的密码,然后在配置文件密码改成加密后的密码
firewall标签定义防火墙:
<firewall>
<!--白名单-->
<whitehost>
<host user="root" host="IP地址"></host>
</<whitehost>
<!--黑名单 这个用户有哪些SQl的权限-->
<blacklist check="true">
<property name="selelctAllow">true</property>
<property name="deleteAllow">false</property>
</<blacklist>
</firewall>
配置schema.xml
配置逻辑库、逻辑表、分片、分片节点。
- schema 逻辑库,可以有多个
- table 逻辑表,它属性:rult:分片规则名 type:类型(全局表、普通表)
- dataNode 定义数据节点,不能重复
- dataHost 具体的数据库实例,节点主机
- database 定义分片所属的数据库
dataHost 标签节点主机:
- name 节点名称
- maxCon 最大连接数
- minCon 最小连接数
- balance 负载均衡类型 0,1,2,3
- writeType 写操作分发方式 0:读写操作都是第一台writeHost 1:随机发送writeHost 上
- switchType 数据库切换测试 -1.1,2,3
writeHost 、readHost标签读写主机:
- host 实例主机标识
- url 数据库连接地址
- weight 权重
- usingDecrypt 密码加密 0否1是
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="逻辑库名" checkSQLschema="false" sqlMaxLimit="100">
<!-- name:这张表进行分库,使用数据节点 -->
<table name="逻辑表" dataNode="数据节点d1,数据节点d2,数据节点d3" rule="分片规则"></table>
</schema>
<!-- dataNode:数据结点 dataHost:主机名 database:分库的名字的数据库名字 -->
<dataNode name="数据节点d1" dataHost="host1" database="数据库1" />
<dataNode name="数据节点d2" dataHost="host2" database="数据库1" />
<dataNode name="数据节点d3" dataHost="host3" database="数据库1" />
<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="地址1:3306" user="root" password="123123"></writeHost> </dataHost>
...
</mycat:schema>
配置rule.xml
定义拆分表的规则
tableRule 标签:
- name 分片名称
- rule 分片具体算法
- columns 分片列名
- algoorithm 算法方法名
function 标签:
- name 算法名称
- class 具体类
<tableRule name="mod_rule">
<rule>
<columns>customer_id</columns>
<algorithm>mod-long</algorithm>
</rule>
...
</tableRule>
<!--函数算法,这个算法是根据选中的字段进行取模的规则进行拆分-->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod" >
<property name="count">2</property>
</function>
配置sequence.xml
原有的主键自增不满足集群中主键唯一约束,mycat提供全局序列,保证全局唯一。
- 本地文件方式
- 数据库方式
- 本地时间戳
- 其他方式
- 自增长主键
分片
架构演变:单机数据库-由于越来越多的请求,我们将数据库进行读写分离,主机负责写,从机负责读,从库可以水平扩展,所以更多的读请求不成问题。当数据量增大后,写请求越来越多,就需要用到分库分表,对写操作进行切分。
单库太大:单个数据库处理能力有限;解决方法:切分成更多更小的库
单表太大:CRUD都成问题;索引膨胀,查询超时;解决方法:切分成多个数据集更小的表。
分库分表的方式方法:
分为 垂直切分 和 水平切分,如果因为表多导致数据多,使用垂直切分,根据业务切分成不同的库;如果因为单张表的数据量太大,使用水平切分。分库分表的顺序应该是先垂直分,后水平分。
垂直拆分
演示:当一个数据库数据量很大,对这些表进行分片处理,把一个数据库拆分多个数据库,分为用户库、订单库、信息表…
步骤1:
准备3个数据库实例,分别创建属于自己的库(用户库、订单库…)
配置server.xml (配置用户、字符集、逻辑库名)
<user name="mycat用户名">
<property name="password">密码</property>
<property name="schemas">逻辑库名</property>
</user>
步骤2:
配置schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="逻辑库名" checkSQLschema="false" sqlMaxLimit="100">
<table name="用户表1" dataNode="d1" primaryKey="主键ID"></table>
<table name="用户表2" dataNode="d1" primaryKey="主键ID"></table>
<table name="用户表3" dataNode="d1" primaryKey="主键ID"></table>
<table name="字典表1" dataNode="dn1,dn2" type="global" ></table>
<table name="订单表1" dataNode="d2" primaryKey="主键ID"></table>
<table name="订单表2" dataNode="d2" primaryKey="主键ID"></table>
<table name="订单表3" dataNode="d2" primaryKey="主键ID"></table>
</schema>
<dataNode name="d1" dataHost="host1" database="用户库" />
<dataNode name="d2" dataHost="host2" database="订单表" />
<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="地址1:3306" user="root" password="123123"></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="地址2:3306" user="root" password="123123"></writeHost> </dataHost>
</mycat:schema>
步骤3:
在不同的数据库创建数据,如果有字典表,把字典表分别在不同的数据库进行创建,避免垮库查询
备份命令:mysqldump -uroot -pitcast 库名 表名 > 文件名
把备份出的字典表数据,分别在其他数据库里创建,并配置schema.xml,增加全局表(global)
字典表和关联子表配置
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="customer" dataNode="dn2" ></table>
<table name="orders" dataNode="dn1,dn2" rule="mod_rule">
<!-- childTable:关联子表 primaryKey:子表主键 joinKey:关联字段 parentKey:父表的关联字段-->
<childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
<!--例如字典表,需要在host1 host2 主键都创建,type:定义global 全局表 -->
<table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table>
</schema>
<dataNode name="dn1" dataHost="host1" database="数据库1" />
<dataNode name="dn2" dataHost="host2" database="数据库2" />
启动Mycat,配置完成。
水平拆分
将同一个表中数据按某种规则拆分到多台数据库主机上。
演示:当一个张表数据量很大,对这些表进行分片处理,拆分3台数据库主机上。
步骤1:
准备3个数据库实例,分别创建属于自己的库(用户库)
配置server.xml (配置用户、字符集、逻辑库名)
步骤2:
配置schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="逻辑库名" checkSQLschema="false" sqlMaxLimit="100">
<table name="用户表1" dataNode="d1,d2,d3" primaryKey="主键ID" rule="mod_rule(取模分片)">
</table>
</schema>
<dataNode name="d1" dataHost="host1" database="用户库" />
<dataNode name="d2" dataHost="host2" database="用户库" />
<dataNode name="d3" dataHost="host3" database="用户库" />
<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="地址1:3306" user="root" password="123123"></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="地址2:3306" user="root" password="123123"></writeHost> </dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" >
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="地址3:3306" user="root" password="123123"></writeHost> </dataHost>
</mycat:schema>
步骤3:
配置rule.xml
<tableRule name=“mod_rule“>
<rule>
<columns>customer_id</columns>
<algorithm>mod-long</algorithm>
</rule>
...
</tableRule>
<!--函数算法,这个算法是根据选中的字段进行取模的规则进行拆分-->
<function name=“mod-long” class=“io.mycat.route.function.PartitionByMod” >
<property name="count">3</property>
</function>
步骤4:
启动Mycat,在Mycat下创建表结构,然后其他数据库也就创建表结构数据。
进行测试,我们创建一些数据,然后根据分片规则,在对应的数据库创建对应的数据。
分片规则:
-
mod-long 取模分片
-
auto-sharding-long 范围分片
# 配置 autopartition-long.txt文件 # M=10000 k=1000 0-500M=0 500M-1000M=1 1000M-1500M=2
-
sharding-by-intfile 枚举分片 本规则适合省份、状态拆分数据
<tableRule name=“sharding-by-intfile“> <rule> <columns>status</columns> <algorithm>hash-int</algorithm> </rule> </tableRule> <function name=“hash-int” class=“io.mycat.route.function.ParitionByFileMap” > <property name="mapFile">partition-hash-int.txt</property> <property name="type">0</property> <property name="defaultNode">0 (默认的节点)</property> </function> # partition-hash-int.txt 1=0 2=1 3=2 # 根据状态status字段进行拆分,值1为第一个数据库,值2为第二个数据库,值3为第三个数据库
-
auto-sharding-rang-mod 范围分片(先进行范围分片,计算分组,再进行组内求模)
<tableRule name=“auto-sharding-rang-mod“> <rule> <columns>id</columns> <algorithm>rang-mod</algorithm> </rule> </tableRule> <function name=“rang-mod” class=“io.mycat.route.function.PartitionByRangeMod” > <property name="mapFile">autopartition-range-mod.txt</property> <property name="defaultNode">0 (默认的节点)</property> </function> # autopartition-range-mod.txt 0-500M=1 500M1-200M=2 # M=10000 2是2个节点
-
sharding-by-long-hash 固定分片hash算法
-
sharding-by-prefixpattern 字符串hash求模范围算法
-
sharding-by-murmur 一致性hash算法
# 有效解决分布式数据的拓容问题,均匀的分散到数据库节点上 <tableRule name=“sharding-by-murmur“> <rule> <columns>id</columns> <algorithm>murmur</algorithm> </rule> </tableRule> <function name=“murmur” class=“io.mycat.route.function.PartitionByMurmurHash” > <property name="seed">0</property> <property name="count">3(要分片的数据库节点)</property> <property name="virtualBucketTimes">160</property> </function>
-
sharding-by-date 日期分片算法
-
sharding-by-month 自然月分片算法
全局序列:
一旦分库,在不同机器上部署mysql,新增数据,表的主键肯能出现相等状况,为了避免这个设置全局序列。
- 本地文件:不推荐,一旦mycat挂了,本地文件也访问不到。
- 数据库方式:利用数据库一个表 来进行计数累加。mycat会预加载一部分号段到mycat的内存中,这样大部分读写序列都是在内存中完成的。如果内存中的号段用完了 mycat会再向数据库要一次。
- 时间戳方式:默认的,但是时间戳格式长,性能不好。
- 自主生成:根据业务逻辑组合,需要改Java代码。
设置数据库方式:
# 1.创建表
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;
# 2.创建3个函数
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 $$
DELIMITER;
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;
# 3 插入序列的表,初始化MYCAT_SEQUENCE数据
字段1:全局序列名字,字段2:多少号开始,字段3:一次性给多少
SELECT * FROM MYCAT_SEQUENCE
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000,100);
# 4 更改mycat配置:
修改这个文件:sequence_db_conf.properties
把要改的表,如order表改成 = dn1 结点
# 5 更改server.xml文件:
把下面的类型改成1 的类型是数据库方式,更改完进行重启
...
<property name="sequnceHandlerType">1</property>
# 6 执行新增操作 增加要用的序列
insert into `orders`(id,amount,customer_id,order_type) values(
next value for MYCATSEQ_ORDERS
,1000,101,102);
性能监控
Mycat-web
帮助我们统计任务和配置管理任务。可以统计SQL并分析慢SQL和高频SQL,为优化SQL提供依据。
安装 Mycat-web
步骤1:
安装Mycat-web之前,需要安装JDK,zookeeper,官方地址:http://zookeeper.apache.org
安装zookeeper:下载好的安装包文件 (zookeepe-xxx.tar.gz),上传Linux服务器上,一般安装在/usr/local下,进行解压
tar -zxvf zookeeper-xxx.tar.gz
解压完,在当前目录(/usr/loca/zookeeper)创建data目录,切换到conf目录下,修改配置文件 zoo_sample.cfg 重命名为 zoo.cfg,修改完进行编辑这个文件
dataDir=/usr/loca/zookeeper/data
启动zookeeper
bin/zkServer.sh start
步骤2:
安装Mycat-web ,下载地址:http://dl.mycat.org.cn
选择mycat-web目录下文件进行下载,下载好的安装包文件,上传Linux服务器上,一般安装在/usr/local下,进行解压
tar -zxvf Mycat-web-xxx-linux.tar.gz
解压完,在当前目录(/usr/loca/mycat-web),如果多个,启动程序:
sh start.sh
启动程序,访问http://ip地址:8082/mycat,通过这个网址进行监控Mycat。
步骤3:
配置Mycat,打开网址,菜单栏 - mycat服务管理 - 新增 (新增要监控的Mycat)注意:管理端口9066 服务端口8066
读写分离
复制的基本原理
主从复制是用来建立一个和主数据库完全一样的数据库环境,称为从数据库,主数据库只有一个。而其它服务器充当从服务器。此时主服务器会将更新信息写入到一个特定的二进制文件中。并会维护文件的一个索引用来跟踪日志循环。这个日志可以记录并发送到从服务器的更新中去。
主从复制配置
步骤1:主机配置
找到Mysql配置文件,[mysqld] 下修改下面内容
...
[mysqld]
server-id = 1 # 主服务器唯一ID
log-bin=自己本地的路径/data/mysqlbin # 启用二进制日志,日志的存放地址
log-err=自己本地的路径/data/mysqlerr # 启用二进制日志,错误日志存放地址
# basedir="D:/devSoft/MySQLServer5.5/" # 根目录 (可选填写)
# 设置logbin格式 有3种 默认 STATEMENT(函数支持不好) ROW(行模式大量修改效率不行) MIXED (综合)
binlog_format=STATEMENT # 二进制日志格式
read-only=0 # 主机,1 只读 0 读写
binlog-ignore-db=mysql # 设置不要复制的数据库
binlog-do-db=需要复制的主数据库名字 # 设置需要复制的数据库
步骤2:从机配置
修改my.cnf配置文件
[mysqld]
server-id = 2 # 从服务器唯一ID
log-bin=自己本地的路径/data/mysqlbin # 启用二进制日志,日志的存放地址
relay-log=mysql-relay # 开启中继日志
步骤3:重启服务、关闭防火墙
更改配置文件后,重启Mysql服务
关闭防火墙 systemctl stop firewalld
步骤4:创建用户并授权给从机
主机创建用户:
GRANT REPLICATION SLAVE ON *.* TO '用户名'@'从机器数据库IP 或者 % 所有' IDENTIFIED BY '密码';
flush privileges;
查询主机的状态:
show master status;
# 执行上面命令,得到 File(binlog日志) Position(接入点) Binlog_Do_DB(要复制的数据库) Binlog_IgnoreDB()
从机操作:
在从机Mysql命令行上执行。
主机用户,是刚才在主机创建的用户和密码;
binlog日志名字在主机状态里查看,进行赋值;
CHANGE MASTER TO MASTER_HOST='主机IP',MASTER_USER='主机用户',MASTER_PASSWORD='主机密码',
MASTER_LOG_FILE='binlog日志名字',MASTER_LOG_POS=具体的接入点值;
如果操作失败,需要重新配置,执行下面2个命令
stop slave; # 停止同步操作
reset master; # 重置主从配置
然后执行下面命令,开启同步
start slave;
步骤5:检查是否成功
show slave status\G; # 检查状态
# 如果结果下面的字段为Yes 代表配置成功
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
检查Mycat的主从复制是否正常
一主一从配置
首先配置数据库的主从复制
步骤1 更改server.xml文件:
设置mycat的用户名和密码,schemas部分设置mycat的逻辑库名。
<user name="mycat用户名">
<property name="password">密码</property>
<property name="schemas">TESTDB</property>
</user>
步骤2 更改schema.xml 文件:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="逻辑库名" checkSQLschema="false" sqlMaxLimit="100">
<table name="表1" dataNode="dn1" primaryKey="主键ID"></table>
</schema>
<dataNode name="dn1" dataHost="host1" database="数据库名" />
<!-- dataHost:主机名 balance: 负载均衡类型 0 不开启 1 双主双从 2 随机分发 3 主写从读 -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" >
<heartbeat>select user()</heartbeat>
<!-- 配置写主机 host:写主机名字,url:主机的地址 user:主机的用户名 password:主机密码 -->
<writeHost host="hostm1" url="192.168.67.1:3306" user="root" password="123123">
<!-- 配置从机 读库(从库)的配置 -->
<readHost host="hosts1" url="192.168.67.131:3306" user="root" password="123123">
</readHost>
</writeHost>
</dataHost>
</mycat:schema>
步骤3 验证数据库访问情况:
mysql -u root -p 密码 -h 远程访问的Id地址 -P 3306端口号
步骤5 配置Mycat日志:
在/usr/local/mycat/conf配置,修改log4j2.xml
<asyncRoot level="debug" includeLocation="true">...<asyncRoot>
日志修改为debug模式
步骤6 启动Mycat
# 方式1 - 控制台启动 :去mycat/bin 目录下 执行 mycat console
[root@... bin]# ./mycat console
# 方式2 - 后台启动 :去mycat/bin 目录下 mycat start
[root@... bin]# ./mycat start
如果启动失败,报错域名解析失败
解决:修改 /etc/hosts ,在 127.0.0.1 后面增加你的机器名,修改后,重启服务 service network restart
启动成功,登录MyCat:
# 后台管理的窗口:
mysql -uroot -p 密码 -h 192.168.67.131 -P 9066
# 数据窗口窗口:
mysql -uroot -p 密码 -h 地址 -P 8066
# 登录后,查询库
show databases;
配置完成,进行演示,
在/usr/local/mycat/log查看日志信息,方便看走的哪个数据库
tail -f mycat.log # 查看日志
双主双从配置
首先配置数据库的主从复制,4个数据库,2主机,2从机
步骤1:主机配置
找到Mysql配置文件,[mysqld] 下修改下面内容
[mysqld]
server-id = 1 # 主服务器唯一ID
log-bin=自己本地的路径/data/mysqlbin # 启用二进制日志,日志的存放地址
binlog_format=STATEMENT # 二进制日志格式
binlog-ignore-db=mysql # 设置不要复制的数据库
binlog-do-db=需要复制的主数据库名字1 # 设置需要复制的数据库
binlog-do-db=需要复制的主数据库名字2 # 设置需要复制的数据库
binlog-do-db=需要复制的主数据库名字3 # 设置需要复制的数据库
log-slave-updates # 在作为从数据库的时候,有写入操作也要更新二进制日志文件
另一个主机也这样配置,注意server-id 不能重复
步骤2:从机配置
修改my.cnf配置文件
...
[mysqld]
server-id = 2 # 从服务器唯一ID
relay-log=mysql-relay # 开启中继日志
另一个从机也这样配置,注意server-id 不能重复
步骤3:重启服务、关闭防火墙
更改配置文件后,重启Mysql服务
关闭防火墙 systemctl stop firewalld
步骤4:创建用户并授权给从机
在2个主机上创建用户:
GRANT REPLICATION SLAVE ON *.* TO '用户名'@'从机器数据库IP 或者 % 所有' IDENTIFIED BY '密码';
flush privileges;
查询主机的状态:
show master status;
# 执行上面命令,得到 File(binlog日志) Position(接入点) Binlog_Do_DB(要复制的数据库) Binlog_IgnoreDB()
在从机上配置需要复制的主机
从机1复制主机1,从机2复制主机2,
从机1执行:
CHANGE MASTER TO MASTER_HOST='主机1IP',MASTER_USER='主机用户',MASTER_PASSWORD='主机密码',
MASTER_LOG_FILE='binlog日志名字',MASTER_LOG_POS=具体的接入点值;
从机2执行:
CHANGE MASTER TO MASTER_HOST='主机2IP',MASTER_USER='主机用户',MASTER_PASSWORD='主机密码',
MASTER_LOG_FILE='binlog日志名字',MASTER_LOG_POS=具体的接入点值;
如果操作失败,需要重新配置,执行下面2个命令
stop slave; # 停止同步操作
reset master; # 重置主从配置
然后两个从机执行下面命令,开启同步
start slave;
步骤5:两个主机互相复制
主机1执行
CHANGE MASTER TO MASTER_HOST='主机2IP',MASTER_USER='主机用户',MASTER_PASSWORD='主机密码',
MASTER_LOG_FILE='binlog日志名字',MASTER_LOG_POS=具体的接入点值;
主机2执行
CHANGE MASTER TO MASTER_HOST='主机1IP',MASTER_USER='主机用户',MASTER_PASSWORD='主机密码',
MASTER_LOG_FILE='binlog日志名字',MASTER_LOG_POS=具体的接入点值;
然后分别执行:
start slave;
步骤6:检查是否成功
show slave status\G; # 检查状态
# 如果结果下面的字段为Yes 代表配置成功
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
检查Mycat的主从复制是否正常,主机1创建数据,从机1。主机2 都有复制成功。
步骤7:配置读写分离
通过Mycat配置读写分离,更改server.xml文件:
设置mycat的用户名和密码,schemas部分设置mycat的逻辑库名。
步骤8 更改schema.xml 文件:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="逻辑库名" checkSQLschema="false" sqlMaxLimit="100">
<table name="表1" dataNode="dn1" primaryKey="主键ID"></table>
</schema>
<dataNode name="dn1" dataHost="host1" database="数据库名" />
<!-- dataHost:主机名 balance: 负载均衡类型 0 不开启 1 双主双从 2 随机分发 3 主写从读 -->
<!-- writeType 0写操作在第一主机,如果挂掉,会连接第二主机 1随机发送主机上 -->
<!-- writeType -1不自动切换 1自动切换 2基于心跳状态决定-->
<dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" >
<heartbeat>select user()</heartbeat>
<!-- 配置写主机 host:写主机名字,url:主机的地址 user:主机的用户名 password:主机密码 -->
<writeHost host="hostm1" url="主机1:3306" user="root" password="123123">
<readHost host="hosts1" url="从机1:3306" user="root" password="123123">
</readHost>
</writeHost>
<writeHost host="hostm2" url="主机2:3306" user="root" password="123123">
<readHost host="hosts2" url="从机2:3306" user="root" password="123123">
</readHost>
</writeHost>
</dataHost>
</mycat:schema>
步骤3 验证数据库访问情况:
mysql -u root -p 密码 -h 远程访问的Id地址 -P 3306端口号
步骤5 配置Mycat日志:
在/usr/local/mycat/conf配置,修改log4j2.xml
<asyncRoot level="debug" includeLocation="true">...<asyncRoot>
日志修改为debug模式
步骤6 启动Mycat
# 方式1 - 控制台启动 :去mycat/bin 目录下 执行 mycat console
[root@... bin]# ./mycat console
# 方式2 - 后台启动 :去mycat/bin 目录下 mycat start
[root@... bin]# ./mycat start
启动成功,登录MyCat,配置完成,进行演示。
集群搭建
搭建高可用集群,2台HAProxy 可实现Mycat多节点的集群高可用和负载均衡,而HAProxy 的高可用,由Keepalived来实现。Keepalived负责为该台服务器抢占vip(虚拟IP),抢到后对该主机访问。
搭建高可用集群:
上图,我们要安装的集群架构,mysql 2台、Mycat 2台、HAProxy 2台
步骤1:安装mysql、Mycat
安装并配置数据库的主从配置,配置Mycat的读写分离。安装与上面读写分离步骤一致。
步骤2:安装HAProxy
HAProxy
下载地址:https://src.fedoraproject.org/repo/pkgs/haproxy
下载好的安装包文件 (haproxy-xxx.tar.gz),上传Linux服务器上,一般安装在/usr/local/src下,进行解压
tar -zxvf haproxy-1.5.16.tar.gz
解压完成后,查看内核版本,进行编译
cd /usr/local/src/haproxyc # 切换目录
uname -r # 查看内核版本 (得到 2.6.43-431.e16.x86_64)
# HAProxy是C语言开发,需要编译,进行编译命令
make TARGET=linux2643 PREFIX=/usr/local/haproxy ARCH=x86_64
# TARGET=linux内核版本,uname -r命令前几位就是内核版本
# PREFIX haproxyc安装路径
# ARCH 系统位数
编译后,进行安装
make install PREFIX=/usr/local/haproxy
安装成功后,创建目录 (haproxy数据存放的目录)
mkdir -p /usr/data/haproxy/
创建HAProxy配置文件
vim /usr/local/haproxy/haproxy.conf
配置文件:
global
log 127.0.0.1 local0
maxconn 4096
chroot /usr/local/haproxy
pidfile /usr/data/haproxy/haproxy.pid
uid 99
gid 99
daemon
node mysql-haproxy-01
description mysql-haproxy-01
defaults
log global
mode tcp
option abortonclose
option redispatch
retries 3
maxconn 2000
timeout connect 50000ms
timeout client 50000ms
timeout server 50000ms
listen proxy_status
bind 0.0.0.0:48066
mode tcp
balance roundrobin
server mycat_1 mycat1地址:8066 check
server mycat_2 mycat2地址:8066 check
frontend admin_stats
bind 0.0.0.0:8888
mode http
stats enable
option httplog
maxconn 10
stats refresh 30s
stats uri /admin
stats auth admin:123123
stats hide-version
stats admin if TRUE
内容解析:
#global 配置中的参数为进程级别的参数,通常与其运行的操作系统有关
global
#定义全局的syslog服务器, 最多可定义2个; local0 是日志设备, 对应于/etc/rsyslog.conf中的配置 , 默认收集info级别日志
log 127.0.0.1 local0
#log 127.0.0.1 local1 notice
#log loghost local0 info
#设定每个haproxy进程所接受的最大并发连接数 ;
maxconn 4096
#修改HAproxy工作目录至指定的目录并在放弃权限之前执行chroot操作, 可以提升haproxy的安全级别
chroot /usr/local/haproxy
#进程ID保存文件
pidfile /usr/data/haproxy/haproxy.pid
#指定用户ID
uid 99
#指定组ID
gid 99
#设置HAproxy以守护进程方式运行
daemon
#debug
#quiet
node mysql-haproxy-01 ## 定义当前节点的名称,用于 HA 场景中多 haproxy 进程共享同一个 IP 地址时
description mysql-haproxy-01 ## 当前实例的描述信息
#defaults:用于为所有其他配置段提供默认参数,这默认配置参数可由下一个"defaults"所重新设定
defaults
#继承global中的log定义
log global
#所使用的处理模式(tcp:四层 , http:七层, health:状态检查,只返回OK)
### tcp: 实例运行于纯 tcp 模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对 7 层报文做任何类型的检查,此为默认模式
### http:实例运行于 http 模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与 RFC 模式兼容的请求都会被拒绝
### health:实例运行于 health 模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息 ,此模式将用于相应外部组件的监控状态检测请求
mode tcp
#当服务器负载很高的时候,自动结束掉当前队列处理时间比较长的连接
option abortonclose
#当使用了cookie时,haproxy将会将请求的后端服务器的serverID插入到cookie中,以保证会话的session持久性,而此时,后端服务器宕机,但是客户端的cookie不会刷新,设置此参数,将会将客户请求强制定向到另外一个后端server上,以保证服务的正常。
option redispatch
retries 3
# 前端的最大并发连接数(默认为 2000)
maxconn 2000
# 连接超时(默认是毫秒,单位可以设置 us,ms,s,m,h,d)
timeout connect 5000
# 客户端超时时间
timeout client 50000
# 服务器超时时间
timeout server 50000
#listen: 用于定义通过关联“前端”和“后端”一个完整的代理,通常只对 TCP 流量有用
listen proxy_status
bind 0.0.0.0:48066 # 绑定端口
mode tcp
balance roundrobin # 定义负载均衡算法,可用于"defaults"、"listen"和"backend"中,默认为轮询
#格式: server <name> <address> [:[port]] [param*]
# weight : 权重,默认为 1,最大值为 256,0 表示不参与负载均衡
# backup : 设定为备用服务器,仅在负载均衡场景中的其他 server 均不可以启用此 server
# check : 启动对此 server 执行监控状态检查,其可以借助于额外的其他参数完成更精细的设定
# inter : 设定监控状态检查的时间间隔,单位为毫秒,默认为 2000,也可以使用 fastinter 和 downinter 来根据服务器端专题优化此事件延迟
# rise : 设置 server 从离线状态转换至正常状态需要检查的次数(不设置的情况下,默认值为 2)
# fall : 设置 server 从正常状态转换至离线状态需要检查的次数(不设置的情况下,默认值为 3)
# cookie : 为指定 server 设定 cookie 值,此处指定的值将会在请求入站时被检查,第一次为此值挑选的 server 将会被后续的请求所选中,其目的在于实现持久连接的功能
# maxconn: 指定此服务器接受的最大并发连接数,如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待其他连接被释放
server mycat_1 192.168.192.157:8066 check inter 10s
server mycat_2 192.168.192.158:8066 check inter 10s
# 用来匹配接收客户所请求的域名,uri等,并针对不同的匹配,做不同的请求处理
# HAProxy 的状态信息统计页面
frontend admin_stats
bind 0.0.0.0:8888
mode http
stats enable
option httplog
maxconn 10
stats refresh 30s
stats uri /admin
stats auth admin:123123
stats hide-version
stats admin if TRUE
启动HAProxy
/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.conf
查看进程
ps -ef|grep haproxy
访问地址:http://IP地址:8888/admin (监控地址)
通过haproxy访问Mycat
mysql -h ip地址 -P 48066 -u mycat用户名 -p 密码;
步骤3:安装Keepalived
Keepalived
下载地址:https://www.keepalived.org/download.html
下载好的安装包文件 (Keepalived-xxx.tar.gz),上传Linux服务器上,一般安装在/usr/local/src下,进行解压
tar -zxvf keepalived-1.4.5.tar.gz
解压完成后,安装依赖插件
yum install -y gcc openssl-devel popt-devel
进入解压后的目录,进行配置,进行编译
cd /usr/local/src/keepalived-1.4.5
./configure --prefix=/usr/local/keepalived
完成后进行安装
make && make install
运行前配置
cp /usr/local/src/keepalived-1.4.5/keepalived/etc/init.d/keepalived /etc/init.d/
mkdir /etc/keepalived
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
cp /usr/local/src/keepalived-1.4.5/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
修改配置文件 /etc/keepalived/keepalived.conf
Master:
global_defs {
notification_email {
javadct@163.com
}
notification_email_from keepalived@showjoy.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id haproxy01
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script chk_haproxy {
script "/etc/keepalived/haproxy_check.sh"
interval 2
weight 2
}
vrrp_instance VI_1 {
#主机配MASTER,备机配BACKUP
state MASTER
#所在机器网卡
interface eth1
virtual_router_id 51
#数值越大优先级越高
priority 120
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
## 将 track_script 块加入 instance 配置块
track_script {
chk_haproxy ## 检查 HAProxy 服务是否存活
}
virtual_ipaddress {
#虚拟IP
192.168.192.200
}
}
BackUP:
global_defs {
notification_email {
javadct@163.com
}
notification_email_from keepalived@showjoy.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
#标识本节点
router_id haproxy02
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
}
# keepalived 会定时执行脚本并对脚本执行的结果进行分析,动态调整 vrrp_instance 的优先级
vrrp_script chk_haproxy {
# 检测 haproxy 状态的脚本路径
script "/etc/keepalived/haproxy_check.sh"
#检测时间间隔
interval 2
#如果条件成立,权重+2
weight 2
}
vrrp_instance VI_1 {
#主机配MASTER,备机配BACKUP
state BACKUP
#所在机器网卡
interface eth1
virtual_router_id 51
#数值越大优先级越高
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
## 将 track_script 块加入 instance 配置块
track_script {
chk_haproxy ## 检查 HAProxy 服务是否存活
}
virtual_ipaddress {
#虚拟IP
192.168.192.200
}
}
编写检测haproxy的shell脚本 haproxy_check.sh
在/etc/keepalived/目录,创建haproxy_check.sh脚本文件
#!/bin/bash
A=`ps -C haproxy --no-header | wc -l`
if [ $A -eq 0 ];then
/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.conf
echo "haproxy restart ..." &> /dev/null
sleep 1
if [ `ps -C haproxy --no-header | wc -l` -eq 0 ];then
/etc/init.d/keepalived stop
echo "stop keepalived" &> /dev/null
fi
fi
启动测试
service keepalived start
登录验证
# 访问的是Vip (虚拟ip)
mysql -uMycat用户名 -p密码 -h 192.168.192.200 -P 48066