mysql分布式写入_MySQL-读写分离与分布式架构

MySQL读写分离概述

读写分离原理

基本原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作性操作导致的变更同步到集群中的从数据库=b。

读写分离原理图:

069cc58a1edb75e472c30c7d273d2ed1.png

数据内部交换过程:

1059d8d937f005be7526c9f8ae91051e.png

为什么要读写分离

面对越来越大的访问压力,单台的服务器的性能成为瓶颈需要分担负载

主从只负责各自的读和写,极大程度的缓解 X 锁和 S 锁争用

从库可配置 myisam 引擎,提升查询性能以及节约系统开销

增加冗余,提高可用性

实现读写分离的方式

一般有两种方式实现

应用程序层实现,网站的程序实现

实现程序层实现指的是在应用程序内部及连接器中实现读写分离

42c7952a8e108f161553bad2be007fbb.png

程序层实现优点:

应用程序内部实现读写分离,安装即可以使用

减少一定部署难度

访问压力在一定级别以下,性能很好

程序层实现缺点:

架构一但调整,代码要跟着变

难以实现高级应用,如自动分库,分表

无法适用大型应用场景

中间件实现

中间件层实现是指在外部中间件程序实现读写分离

中间件优点:

架构设计更灵活

可以在程序上实现一些高级控制,如:透明化水平拆分,failover,监控

可以依靠技术手段提高MySQL性能

对业务代码的影响小,同时也安全

中间件缺点:

需要一定的开发运维团队的支持

Atlas中间件

Atlas介绍

360团队基于mysql proxy把lua用C改写。原有版本是支持分表, 目前已经放出了分库分表版本。在网上看到一些朋友经常说在高并 发下会经常挂掉,如果大家要使用需要提前做好测试。

Atlas架构图

f266229d67f8427b92d37b0d0002e599.png

Atlas安装

环境准备:

主机

IP地址

数据节点

vip地址

db01

10.0.0.51

master

10.0.0.55

db02

10.0.0.52

slave-1

db03

10.0.0.53

slave-2

#在线下载,可能会会比较慢或者失败wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm

#直接在MHA-2019-6.28.zip里面有

[root@db01~]# rpm -ivh Atlas-2.2.1.el6.x86_64.rpm

Preparing... ################################# [100%]

Updating/installing...1:Atlas-2.2.1-1 ################################# [100%]

配置文件

cd /usr/local/mysql-proxy/confmvtest.cnf test.cnf.bakcat > test.cnf <

[mysql-proxy]

admin-username =user

admin-password = pwdproxy-backend-addresses = 10.0.0.55:3306proxy-read-only-backend-addresses = 10.0.0.52:3306,10.0.0.53:3306pwds= repl:3yb5jEku5h4=,mha:O2jBXONX098=daemon= truekeepalive= trueevent-threads = 8log-level =message

log-path = /usr/local/mysql-proxy/log

sql-log=ON

proxy-address = 0.0.0.0:33060admin-address = 0.0.0.0:2345charset=utf8

EOF

proxy-backend-addresses = 10.0.0.55:3306 #填写vip ip地址,谁有vip地址就去写数据

proxy-read-only-backend-addresses = 10.0.0.52:3306,10.0.0.53:3306 #读数据的数据库

启动atlas

# /usr/local/mysql-proxy/bin/mysql-proxyd test start

OK: MySQL-Proxy of test is started

#ps -ef |grepproxy

root10236 1 0 12:59 ? 00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf

root10237 10236 0 12:59 ? 00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf

root10253 9305 0 13:00 pts/1 00:00:00 grep --color=auto proxy

测试读写分离功能

注:master节点在db01上,我们在db03上连接db01进行测试

[root@db03 ~]# mysql -umha -pmha -h10.0.0.51 -P33060

读操作测试:

mysql> select@@server_id;+-------------+

| @@server_id |

+-------------+

| 53 |

+-------------+

1 row in set (0.00sec)

mysql> select@@server_id;+-------------+

| @@server_id |

+-------------+

| 52 |

+-------------+

1 row in set (0.00 sec)

注:可以看到我们的读操作分别在db2和db3上进行了操作

写操作测试:

mysql> begin;select@@server_id;commit;

Query OK,0 rows affected (0.00sec)+-------------+

| @@server_id |

+-------------+

| 51 |

+-------------+

1 row in set (0.00sec)

Query OK,0 rows affected (0.00sec)

mysql> begin;select@@server_id;commit;

Query OK,0 rows affected (0.00sec)+-------------+

| @@server_id |

+-------------+

| 51 |

+-------------+

1 row in set (0.00sec)

Query OK,0 rows affected (0.00 sec)

注:所有的写操作都在db1上进行

Atlas的管理

1. 连接查看管理帮助

#登录管理

[root@db01~]# mysql -uuser -ppwd -h10.0.0.51 -P2345

mysql> select *from help;+----------------------------+---------------------------------------------------------+

| command | description |

+----------------------------+---------------------------------------------------------+

| SELECT * FROM help | shows this help |

| SELECT * FROM backends | lists the backends and their state |

| SET OFFLINE $backend_id | offline backend server, $backend_id is backend_ndx's id |

| SET ONLINE $backend_id | online backend server, ... |

| ADD MASTER $backend | example: "add master 127.0.0.1:3306", ... |

| ADD SLAVE $backend | example: "add slave 127.0.0.1:3306", ... |

| REMOVE BACKEND $backend_id | example: "remove backend 1", ... |

| SELECT * FROM clients | lists the clients |

| ADD CLIENT $client | example: "add client 192.168.1.2", ... |

| REMOVE CLIENT $client | example: "remove client 192.168.1.2", ... |

| SELECT * FROM pwds | lists the pwds |

| ADD PWD $pwd | example: "add pwd user:raw_password", ... |

| ADD ENPWD $pwd | example: "add enpwd user:encrypted_password", ... |

| REMOVE PWD $pwd | example: "remove pwd user", ... |

| SAVE CONFIG | save the backends to config file |

| SELECT VERSION | display the version of Atlas |

+----------------------------+---------------------------------------------------------+

16 rows in set (0.01 sec)

2. 查看数据库节点状态

mysql> select *from backends;+-------------+----------------+-------+------+

| backend_ndx | address | state | type |

+-------------+----------------+-------+------+

| 1 | 10.0.0.55:3306 | up | rw |

| 2 | 10.0.0.52:3306 | up | ro |

| 3 | 10.0.0.53:3306 | up | ro |

+-------------+----------------+-------+------+

3 rows in set (0.00 sec)

rw:支持读写

ro:支持只读

3. 上线和下线节点

set offline $backend_id --下线例子:set offline 2;

set online $backend_id--上线例子:set online 2;

4. 添加删除节点

ADD MASTER $backend --添加主节点例子:add master 10.0.0.54:3306;

ADD slave $backend--添加从节点例子:add slave 10.0.0.54:3306;

REMOVE BACKEND $backend_id--删除节点

5. 用户管理

select * from pwds --查看用户

ADD PWD $pwd --添加一个用户,使用的是明文

ADD ENPWD $pwd --添加一个用户,使用密文

REMOVE PWD $pwd --删除用户

6. 永久生效

mysql> save config;

企业用户管理案例

1. 数据库主节点

grant all on *.* to china@'10.0.0.%' identified by '123';

2. Atlas中添加数据库用户

#明文

ADD PWD china:123;

#密文/usr/local/mysql-proxy/bin/encrypt 123[root@db01~]# /usr/local/mysql-proxy/bin/encrypt 1233yb5jEku5h4=ADD ENPWD china:3yb5jEku5h4=

配置永久生效

save config;

MySQL分布式架构

基础环境准备

架构表格

主机

实例

端口

数据目录

db01

mysql3307

3307

/data/3307/data

db02

mysql3308

3308

/data/3308/data

mysql3309

3309

/data/3309/data

mysql3310

3310

/data/3310/data

架构图:

8ca340026889447944d717d0e525ddb5.png

环境准备

数据库版本:MySQL 5.7.28

两台虚拟机:db01、db02

每台创建四个MySQL实例:3307、3308、3309、3310

删除历史环境

pkill mysqldrm -rf /data/33{07..10}mv /etc/my.cnf /etc/my.cnf.bak

3. 创建相关目录初始化数据

mkdir /data/33{07..10}/data -p

mysqld--initialize-insecure --user=mysql --datadir=/data/3307/data --basedir=/app/database/mysql

mysqld--initialize-insecure --user=mysql --datadir=/data/3308/data --basedir=/app/database/mysql

mysqld--initialize-insecure --user=mysql --datadir=/data/3309/data --basedir=/app/database/mysql

mysqld--initialize-insecure --user=mysql --datadir=/data/3310/data --basedir=/app/database/mysql

4.准备配置文件和脚本

db01配置文件和启动脚本

#db01配置文件cat >/data/3307/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3307/data

socket=/data/3307/mysql.sock

port=3307log-error=/data/3307/mysql.log

log_bin=/data/3307/mysql-bin

binlog_format=row

skip-name-resolve

server-id=7gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3308/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3308/data

port=3308socket=/data/3308/mysql.sock

log-error=/data/3308/mysql.log

log_bin=/data/3308/mysql-bin

binlog_format=row

skip-name-resolve

server-id=8gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3309/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3309/data

socket=/data/3309/mysql.sock

port=3309log-error=/data/3309/mysql.log

log_bin=/data/3309/mysql-bin

binlog_format=row

skip-name-resolve

server-id=9gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3310/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3310/data

socket=/data/3310/mysql.sock

port=3310log-error=/data/3310/mysql.log

log_bin=/data/3310/mysql-bin

binlog_format=row

skip-name-resolve

server-id=10gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOF

#db01启动文件cat >/etc/systemd/system/mysqld3307.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3308.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3309.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3310.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf

LimitNOFILE= 5000EOF

db02配置文件和启动文件

#配置文件cat >/data/3307/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3307/data

socket=/data/3307/mysql.sock

port=3307log-error=/data/3307/mysql.log

log_bin=/data/3307/mysql-bin

binlog_format=row

skip-name-resolve

server-id=17gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3308/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3308/data

port=3308socket=/data/3308/mysql.sock

log-error=/data/3308/mysql.log

log_bin=/data/3308/mysql-bin

binlog_format=row

skip-name-resolve

server-id=18gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3309/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3309/data

socket=/data/3309/mysql.sock

port=3309log-error=/data/3309/mysql.log

log_bin=/data/3309/mysql-bin

binlog_format=row

skip-name-resolve

server-id=19gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOFcat >/data/3310/my.cnf<

[mysqld]

basedir=/app/database/mysql

datadir=/data/3310/data

socket=/data/3310/mysql.sock

port=3310log-error=/data/3310/mysql.log

log_bin=/data/3310/mysql-bin

binlog_format=row

skip-name-resolve

server-id=20gtid-mode=on

enforce-gtid-consistency=truelog-slave-updates=1EOF

#启动文件cat >/etc/systemd/system/mysqld3307.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3308.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3309.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf

LimitNOFILE= 5000EOFcat >/etc/systemd/system/mysqld3310.service<

[Unit]

Description=MySQL Server

Documentation=man:mysqld(8)

Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html

After=network.target

After=syslog.target

[Install]

WantedBy=multi-user.target

[Service]

User=mysql

Group=mysql

ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf

LimitNOFILE= 5000EOF

5. 修改权限,启动多实例

chown -R mysql.mysql /data/*systemctl start mysqld3307

systemctl start mysqld3308

systemctl start mysqld3309

systemctl start mysqld3310

netstat -lntup

mysql -S /data/3307/mysql.sock -e "show variables like 'server_id'"

mysql -S /data/3308/mysql.sock -e "show variables like 'server_id'"

mysql -S /data/3309/mysql.sock -e "show variables like 'server_id'"

mysql -S /data/3310/mysql.sock -e "show variables like 'server_id'"

6. 节点主从规划

箭头指向谁是主库

shard1

10.0.0.51:3307 10.0.0.52:3307

10.0.0.51:3309 ------> 10.0.0.51:3307

10.0.0.52:3309 ------> 10.0.0.52:3307

shard2

10.0.0.52:3308 10.0.0.51:3308

10.0.0.52:3310 -----> 10.0.0.52:3308

10.0.0.51:3310 -----> 10.0.0.51:3308

7.开始配置

##shard1

10.0.0.51:3307 10.0.0.52:3307

db02

mysql -S /data/3307/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"mysql-S /data/3307/mysql.sock -e "grant all on *.* to root@'10.0.0.%' identified by '123' with grant option;"

db01

mysql -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3307/mysql.sock -e "start slave;"mysql-S /data/3307/mysql.sock -e "show slave status\G"

db02

mysql -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3307/mysql.sock -e "start slave;"mysql-S /data/3307/mysql.sock -e "show slave status\G"

10.0.0.51:3309 ------> 10.0.0.51:3307

db01

mysql -S /data/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3309/mysql.sock -e "start slave;"mysql-S /data/3309/mysql.sock -e "show slave status\G"

10.0.0.52:3309 ------> 10.0.0.52:3307

db02

mysql -S /data/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3309/mysql.sock -e "start slave;"mysql-S /data/3309/mysql.sock -e "show slave status\G"

##shard2

10.0.0.52:3308 10.0.0.51:3308

db01

mysql -S /data/3308/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"mysql-S /data/3308/mysql.sock -e "grant all on *.* to root@'10.0.0.%' identified by '123' with grant option;"

db02

mysql -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3308/mysql.sock -e "start slave;"mysql-S /data/3308/mysql.sock -e "show slave status\G"

db01

mysql -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3308/mysql.sock -e "start slave;"mysql-S /data/3308/mysql.sock -e "show slave status\G"

10.0.0.52:3310 -----> 10.0.0.52:3308

db02

mysql -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3310/mysql.sock -e "start slave;"mysql-S /data/3310/mysql.sock -e "show slave status\G"

10.0.0.51:3310 -----> 10.0.0.51:3308

db01

mysql -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"mysql-S /data/3310/mysql.sock -e "start slave;"mysql-S /data/3310/mysql.sock -e "show slave status\G"

8. 检查主从状态

mysql -S /data/3307/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3308/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3309/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3310/mysql.sock -e "show slave status\G"|grep "Running:"

注:(没问题不要做这部!!!!) 如果中间出现错误,在每个节点进行执行以下命令

mysql -S /data/3307/mysql.sock -e "stop slave; reset slave all;"mysql-S /data/3308/mysql.sock -e "stop slave; reset slave all;"mysql-S /data/3309/mysql.sock -e "stop slave; reset slave all;"mysql-S /data/3310/mysql.sock -e "stop slave; reset slave all;"

分布式架构演变

b2f3fcb437192ebb1c3e882e554f06d7.png

Mycat中间件安装

Mycat介绍

Mycat是目前最流行的基于Java语言编写的数据库中间件,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分库分表。配合数据库的主从模式还可以实现读写分离。

Mycat是基于阿里开源的Cobar产品研发,Cobar的稳定性、可靠性、优秀的bib架构和性能以及众多成熟的使用案例使得Mycat变得非常强大。

Mycat发展到目前版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Orale、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在Mycat里,都是一个传统的数据库表,支持标准的SQL语句,这样一来,对前端业务系统来说,可以大幅度降低开发难度,提升开发速度。

Mycat架构图:

02a3d344a2be7ee6566d101be533987f.png

Mycat应用

上传解压软件

mkdir /data/mycat/cd/data/mycatwget http://dl.mycat.io/1.6.7.1/Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz

tar xf Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz

#添加

export PATH=/data/mycat/bin:$PATH

#生效

source/etc/profile

配置Java环境

解压到/usr/local,创建软连接

mkdir /app/

tar xf jdk-8u221-linux-x64.tar.gz -C /app/

ln -s /app/jdk1.8.0_221/ /app/jdk

全局环境变量

export JAVA_HOME=/app/jdk

export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH

export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jarq

./etc/profile

测试版本

[root@db01 /app]# java -version

java version"1.8.0_221"Java(TM) SE Runtime Environment (build1.8.0_221-b11)

Java HotSpot(TM)64-Bit Server VM (build 25.221-b11, mixed mode)

注:实验环境直接yum install java -y

启动测试

[root@db01 mycat]# mycat start

Starting Mycat-server...

[root@db01 mycat]# mysql-uroot -p123456 -h 127.0.0.1 -P8066

软件结构

bin:程序目录

mycat程序,启动和关闭mycat中间件

conf:配置相关目录

schema.xml主配置文件

rule.xml分片配置

server.xmlmycat服务相关配置

logs:日志相关目录

wrapper.log

mycat.log

schema.xml配置文件结构

[root@db01 conf]# cd /data/mycat/conf/

mvschema.xml schema.xml.bak

vim schema.xml

# 逻辑库:

# DN数据节点(逻辑分片):数据节点(逻辑分片):作用:

垂直和水平查分。

# DH 数据主机

作用: 高可用和读写分离

select user()

#写的节点#读的节点

schema.xml文件逻辑结构

c71d95257ba17582e88737dcaee1a2d9.png

测试环境准备

注:测试word.sql数据库

配置文件

vim /data/mycat/conf/schema.xml<?xml version="1.0"?>

select user()

db01:

mysql -S /data/3307/mysql.sock

grant all on*.* to root@'10.0.0.%' identified by '123';

source/root/world.sql

mysql-S /data/3308/mysql.sock

grant all on*.* to root@'10.0.0.%' identified by '123';

source/root/world.sql

重启mycat

# mycat restart

Stopping Mycat-server...

Stopped Mycat-server.

Starting Mycat-server...

读写分离测试

连接mycat服务

[root@db01 ~]# mysql -uroot -p123456 -h 10.0.0.51 -P8066

# 测试读

mysql> select@@server_id;+-------------+

| @@server_id |

+-------------+

| 9 |

+-------------+

1 row in set (0.05sec)

# 测试写

mysql> begin ; select@@server_id;commit;+-------------+

| @@server_id |

+-------------+

| 7 |

+-------------+

1 row in set (0.00 sec)

配置读写分离及高可用

[root@db01 conf]# mvschema.xml schema.xml.rw

[root@db01 conf]# vim schema.xml<?xml version="1.0"?>

select user()

[root@db01 conf]# mycat restart

Stopping Mycat-server...

Stopped Mycat-server.

Starting Mycat-server...

真正的 writehost:负责写操作的writehost

standby writehost:和readhost一样,只提供读服务

当写节点宕机后,后面跟的readhost也不提供服务,这时候standby的writehost就提供写服务,后面跟的readhost提供读服务

测试

mysql -uroot -p123456 -h 127.0.0.1 -P 8066show variables like'server_id';

读写分离测试

mysql -uroot -p -h 127.0.0.1 -P8066

show variables like'server_id';

show variables like'server_id';

show variables like'server_id';

begin;

show variables like'server_id';

参数介绍

有两个参数需要注意,balance和switchType。

其中,balance指的负载均衡类型,目前的取值有4种:

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":所有读请求随机的分发到writeHost对应的readhost执行,writeHost不负担读压力

switchType指的是切换模式,目前的取值也有4种:

switchType="-1":表示不自动切换

switchType="1":默认值,表示自动切换

switchType="2":基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status;

switchType="3":基于 MySQL galary cluster 的切换机制(适合集群),心跳语句为 show status like 'wsrep%'。

datahost其他配置

maxCon="1000":最大的并发连接数

minCon="10":mycat在启动之后,会在后端节点上自动连接线程

tempReadHostAvailable="1":这个一主一从(1个writehost,1个readhost时),可以开启这个参数,如果2个writehost,2个readhost时select user()监测心跳

Mycat分库分表

环境恢复

重启所有节点

systemctl restart mysqld3307

systemctl restart mysqld3308

systemctl restart mysqld3309

sysetmctl restart mysqld3310

查看主从状态

mysql -S /data/3307/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3308/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3309/mysql.sock -e "show slave status\G"|grep "Running:"mysql-S /data/3310/mysql.sock -e "show slave status\G"|grep "Running:"

Mycat分布式架构--垂直分表

分片

垂直分片:将不同的表切分到不同的数据库中

水平切片:将同一种表按照某个条件切分到不同的数据库中

分表架构图:

d2118052b6e721aa520786eff8da55c2.png

cd /data/mycat/confmvschema.xml schema.xml.ha

vim schema.xml<?xml version="1.0"?>

select user()

select user()

创建测试库和表

mysql -S /data/3307/mysql.sock -e "create database taobao charset utf8;"mysql-S /data/3308/mysql.sock -e "create database taobao charset utf8;"mysql-S /data/3307/mysql.sock -e "use taobao;create table user(id int,name varchar(20))";

mysql-S /data/3308/mysql.sock -e "use taobao;create table order_t(id int,name varchar(20))"

重启mycat

mycat restart

读操作测试

mysql -uroot -p123456 -h10.0.0.51 -P8066

mysql>use TESTDB;

mysql>show tables;+------------------+

| Tables_in_taobao |

+------------------+

| order_t |

| user |

+------------------+

2 rows in set (0.00sec)

[root@db01/data/mycat/conf]# mysql -S /data/3307/mysql.sock -e "show tables from taobao"

+------------------+

| Tables_in_taobao |

+------------------+

| user |

+------------------+[root@db01/data/mycat/conf]# mysql -S /data/3308/mysql.sock -e "show tables from taobao"

+------------------+

| Tables_in_taobao |

+------------------+

| order_t |

+------------------+

Mycat分布式架构--水平拆分

垂直分片:将不同的表切分到不同的数据库中

水平切片:将同一种表按照某个条件切分到不同的数据库中

水平拆分架构图:

acace8f19fad73325f5f1b710cbcd4b4.png

水平分库分表重要概念

水平拆分:

水平拆分也有两种:水平分表和水平分库分表。

水平分表:

水平分表和垂直分表区别在于垂直分表针对列,将不常用的列拆分到辅助表。而水平分表针对的是表,在同一个数据库中创建多张一样的表,比如我们在order数据库中创建三张订单表order1、order2、order3,然后插入订单时将id对3取余,根据不同的值存入不同的订单表,但是由于水平分表是将数据表存放在同一个数据库,水平分表可以降低单标的数据量,有助于提高查询效率。如果业务量很大一样会受到服务器lo的瓶颈,所以我们经常使用的还是水平分库分表。

水平分开库分表:

水平分库实际上就是在多台不同的机器分别创建数据库和数据表,比如订单表我们可以在两个有主从复制和MHA的集群里分别创建order数据库和order数据表,然后根据一定的逻辑将不同的数据存放在不同机器的数据库中。一般来说水平拆分主要有以下几种拆分规则:

范围拆分:比如订单表通过id拆分,id在1到500w在集群db01内的order数据库,id在501-1000w在集群db02内的order数据库,依次类推

地理拆分:将订单表按照不同地区将表中的数据拆分到不同数据库的order数据库中存储。比如可以安装省份来进行拆分。

取模拆分:取模就是刚才在水平分表讲到的比如有三个订单表,可以将id对3取余,但是区别在于水平分库分表是将同样的数据库和数据表存放在不同机器,所以可以说有效缓解单机瓶颈问题。

时间拆分:根据时间来拆分表中的数据,可以将表中创建时间超过一年的数据拆分到其他数据库的order数据库存储,原表中只保留被查询概率较高的数据而这部分数据往往都是近期才创建的,所以可以通过时间拆分实现冷热数据分离。

范围分片

比如说t3表

行数非常多,2000w(1-1000w:sh1 1000w-2000w:sh2)

访问非常频繁,用户访问较离散

62ff081b7fa35da82b50f396f4311306.png

修改schema.xml文件,定制分片策略

cp schema.xml schema.xml.1vim schema.xml

---对t3表进行定制分片策略

rule.xml文件配置切分规则

vim rule.xml

id

rang-long

autopartition-long.txt

autopartition-long.txt 定制范围-range

# range start-end,data node index

# k=1000,M=10000.0-10=0

10-20=1#0,1是分片的编号

创建测试表

mysql -S /data/3307/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3308/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"

测试

# 重启mycat

mycat restart

mysql-uroot -p123456 -h 127.0.0.1 -P 8066insert into t3(id,name) values(1,'a');

insert into t3(id,name) values(2,'b');

insert into t3(id,name) values(3,'c');

insert into t3(id,name) values(4,'d');

insert into t3(id,name) values(11,'aa');

insert into t3(id,name) values(12,'bb');

insert into t3(id,name) values(13,'cc');

insert into t3(id,name) values(14,'dd');

[root@db01 conf]# mysql-S /data/3308/mysql.sock -e "select * from taobao.t3"

+----+------+

| id | name |

+----+------+

| 11 | aa |

| 12 | bb |

| 13 | cc |

| 14 | dd |

+----+------+[root@db01 conf]# mysql-S /data/3307/mysql.sock -e "select * from taobao.t3"

+----+------+

| id | name |

+----+------+

| 1 | a |

| 2 | b |

| 3 | c |

| 4 | d |

+----+------+

取模(取余数)分片

取余分片方式:分片键(一个列)与节点数量进行取余,得到余数,将数据写入对应节点

复制配置文件

#修改配置文件

vim schema.xml

#查看和定义分片使用

vim rule.xml2 #这里我们有几个节点就写几,这里我们是2个多实例节点

准备测试环境

#创建t4测试表

mysql-S /data/3307/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3308/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"#重启mycat

mycat restart

#测试

mysql-root -p123456 -h10.0.0.051 -P8066

use TESTDB

insert into t4(id,name) values(1,'a');

insert into t4(id,name) values(2,'b');

insert into t4(id,name) values(3,'c');

insert into t4(id,name) values(4,'d');

insert into t4(id,name) values(6,'x'),(8,'y'),(10,'z');

#分别登录后端节点查询数据

mysql-S /data/3308/mysql.sock -e "select * from taobao.t4"

+----+------+

| id | name |

+----+------+

| 1 | a |

| 3 | c |

+----+------+mysql-S /data/3307/mysql.sock -e "select * from taobao.t4"

+----+------+

| id | name |

+----+------+

| 2 | b |

| 4 | d |

| 6 | x |

| 8 | y |

| 10 | z |

+----+------+

枚举分片

所谓的枚举分片,就是通过在配置文件中配置可能的枚举id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,具体使用场景可根据自己具体的业务场景确定。

表格规划

t5 表idname telnum1 bj 1212

2 sh 22222

3 bj 3333

4 sh 44444

5 bj 5555#使用的函数

sharding-by-intfile

schema.xml配置文件

rule.xml分片配置文件

vim rule.xml

name

hash-int

partition-hash-int.txt

1###type这一列,打开中英文的支持1###这里行是添加的其他数据默认加入sh=1里面

注:根据name这个列条件分片name

partition-hash-int.txt配置

bj=0

sh=1DEFAULT_NODE=1#上面这个参数是其他数据往sh=1这个表里走

注:columns标识将要分片的表字段,algorithm分片函数, 其中分片函数配置中,mapFile标识配置文件名称

准备测试环境

mysql -S /data/3307/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3308/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"

重启mycat,查看结构

#重启

mycat restart

#连接加入表数据

mysql-uroot -p123456 -h10.0.0.51 -P8066

use TESTDB

insert into t5(id,name) values(1,'bj');

insert into t5(id,name) values(2,'sh');

insert into t5(id,name) values(3,'bj');

insert into t5(id,name) values(4,'sh');

insert into t5(id,name) values(5,'tj');

#查看结果

mysql-S /data/3308/mysql.sock -e "select * from taobao.t5"

+----+------+

| id | name |

+----+------+

| 2 | sh |

| 4 | sh |

| 5 | tj |

+----+------+mysql-S /data/3307/mysql.sock -e "select * from taobao.t5"

+----+------+

| id | name |

+----+------+

| 1 | bj |

| 3 | bj |

+----+------+

mycat全局表

a b c d .....jointselectt1.name ,t.x from t1jointselectt2.name ,t.x from t2jointselectt3.name ,t.x from t3join t

注:所有表都要去joint这张表,我们要把这张表变成全局表

应用场景:

如果你的业务中有些数据类似于数据字典,比如配置文件的配置,常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分,要在所有的分片上保存一份数据即可,Mycat 在Join操作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join,避免跨库Join,在进行数据插入操作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。

编辑配置文件schema.xml

vim schema.xml

后端数据准备

mysql -S /data/3307/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3308/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"

重启mycat

mycat restart

测试

mysql -uroot -p123456 -h10.0.0.51 -P8066

use TESTDB

insert into t_area(id,name) values(1,'a');

insert into t_area(id,name) values(2,'b');

insert into t_area(id,name) values(3,'c');

insert into t_area(id,name) values(4,'d');

#查看表

mysql-S /data/3308/mysql.sock -e "select * from taobao.t_area"

+----+------+

| id | name |

+----+------+

| 1 | a |

| 2 | b |

| 3 | c |

| 4 | d |

+----+------+mysql-S /data/3307/mysql.sock -e "select * from taobao.t_area"

+----+------+

| id | name |

+----+------+

| 1 | a |

| 2 | b |

| 3 | c |

| 4 | d |

+----+------+

E-R分片

join是关系数据库最常用的一个特性,然而在分布式环境中,跨分片的join最复杂,最难解决

比如:

mycat逻辑库word,两张表格t1,t2.做了分库策略,t1放到了datanode1,t2放到了datanode2,如果我t1 join t2检索数据,

怎么办?

这就是E-R关系策略要解决的问题。

mycat借鉴了table group的概念,将子表的存储位置依赖于子表,并且在物理上紧邻存放,解决了join的效率和性能问题。E-R关系的数据库分片策略,根据这一思路,将子表的记录和所关联的父表存档在同一个数据分片上。

ajoinb

on a.xx=b.yy

为了防止跨分片join,可以使用E-R模式

### a表结构idname1a2b3c4d

### b表结构idaddr aid1001 bj 1

1002 sh 2

1003 tj 3

1004 wh 4### 两表之间join关联select * from a join b on a.id = b.aid where a.name=d

例子:a表和b表做E-R分片,并进行join

1. 修改配置文件

vim schema.xml

注:a是主,b是负

2. 修改rule.xml mod-log分片策略:

vim rule.xml

id

mod-long_china

2

注:tableRule里的name是我们自定义的,在文件下方的函数也要进行创建,可以参考旁边的mod-log

3. 创建测试表

mysql -S /data/3307/mysql.sock -e "use taobao;create table a (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3307/mysql.sock -e "use taobao;create table b (id int not null primary key auto_increment,addr varchar(20) not null ,aid int );"mysql-S /data/3308/mysql.sock -e "use taobao;create table a (id int not null primary key auto_increment,name varchar(20) not null);"mysql-S /data/3308/mysql.sock -e "use taobao;create table b (id int not null primary key auto_increment,addr varchar(20) not null ,aid int );"

4. 重启mycat测试

mycat restart

mysql-uroot -p123456 -h10.0.0.51 -P8066

use TESTDB

insert into a(id,name) values(1,'a');

insert into a(id,name) values(2,'b');

insert into a(id,name) values(3,'c');

insert into a(id,name) values(4,'d');

insert into a(id,name) values(5,'e');

insert into b(id,addr,aid) values(1001,'bj',1);

insert into b(id,addr,aid) values(1002,'sj',3);

insert into b(id,addr,aid) values(1003,'sd',4);

insert into b(id,addr,aid) values(1004,'we',2);

insert into b(id,addr,aid) values(1005,'er',5);

5. 后端数据节点数据分布

mysql -S /data/3307/mysql.sock -e "select * from taobao.a"mysql-S /data/3307/mysql.sock -e "select * from taobao.b"mysql-S /data/3308/mysql.sock -e "select * from taobao.a"mysql-S /data/3308/mysql.sock -e "select * from taobao.b"

server.xml解读

管理逻辑库 默认是TESTDB

1. 逻辑库名

schema.xmlserver.xml

123456

oldboy,oldguo

oldboy

user

oldboy

true

oldboy

2. 添加一个逻辑库

schema.xml

server.xmloldboy,oldguo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值