MySQL-读写分离与分布式架构

MySQL读写分离概述

读写分离原理

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

  • 读写分离原理图:

  • 数据内部交换过程:

为什么要读写分离

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

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

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

  3. 增加冗余,提高可用性

实现读写分离的方式

一般有两种方式实现

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

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

程序层实现优点:

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

  2. 减少一定部署难度

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

程序层实现缺点:

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

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

  3. 无法适用大型应用场景

中间件实现

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

中间件优点:

  1. 架构设计更灵活

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

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

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

中间件缺点:

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

Atlas中间件

Atlas介绍

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

  • Atlas架构图

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  

官方地址:https://github.com/Qihoo360/Atlas/releases

软件包链接:https://pan.baidu.com/s/15Cr3RgonQANLJ9aT_pFoRw 提取码:p6s

#在线下载,可能会会比较慢或者失败
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/conf
mv test.cnf test.cnf.bak
cat > test.cnf <<EOF
[mysql-proxy]
admin-username = user
admin-password = pwd
proxy-backend-addresses = 10.0.0.55:3306
proxy-read-only-backend-addresses = 10.0.0.52:3306,10.0.0.53:3306
pwds = repl:3yb5jEku5h4=,mha:O2jBXONX098=
daemon = true
keepalive = true
event-threads = 8
log-level = message
log-path = /usr/local/mysql-proxy/log
sql-log=ON
proxy-address = 0.0.0.0:33060
admin-address = 0.0.0.0:2345
charset=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 |grep proxy
root      10236      1  0 12:59 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf
root      10237  10236  0 12:59 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf
root      10253   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.00 sec)

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.00 sec)

+-------------+
| @@server_id |
+-------------+
|          51 |
+-------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> begin;select @@server_id;commit;
Query OK, 0 rows affected (0.00 sec)

+-------------+
| @@server_id |
+-------------+
|          51 |
+-------------+
1 row in set (0.00 sec)

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 123
3yb5jEku5h4=

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
  • 架构图:

  1. 环境准备

    •   数据库版本:MySQL 5.7.28

    •   两台虚拟机:db01、db02

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

  1. 删除历史环境

pkill mysqld
rm -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<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
log-error=/data/3307/mysql.log
log_bin=/data/3307/mysql-bin
binlog_format=row
skip-name-resolve
server-id=7
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

cat >/data/3308/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3308/data
port=3308
socket=/data/3308/mysql.sock
log-error=/data/3308/mysql.log
log_bin=/data/3308/mysql-bin
binlog_format=row
skip-name-resolve
server-id=8
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

cat >/data/3309/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3309/data
socket=/data/3309/mysql.sock
port=3309
log-error=/data/3309/mysql.log
log_bin=/data/3309/mysql-bin
binlog_format=row
skip-name-resolve
server-id=9
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

cat >/data/3310/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3310/data
socket=/data/3310/mysql.sock
port=3310
log-error=/data/3310/mysql.log
log_bin=/data/3310/mysql-bin
binlog_format=row
skip-name-resolve
server-id=10
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

#db01启动文件
cat >/etc/systemd/system/mysqld3307.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3308.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3309.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3310.service<<EOF
[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 = 5000
EOF
  • db02配置文件和启动文件
#配置文件
cat >/data/3307/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
log-error=/data/3307/mysql.log
log_bin=/data/3307/mysql-bin
binlog_format=row
skip-name-resolve
server-id=17
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF
cat >/data/3308/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3308/data
port=3308
socket=/data/3308/mysql.sock
log-error=/data/3308/mysql.log
log_bin=/data/3308/mysql-bin
binlog_format=row
skip-name-resolve
server-id=18
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF
cat >/data/3309/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3309/data
socket=/data/3309/mysql.sock
port=3309
log-error=/data/3309/mysql.log
log_bin=/data/3309/mysql-bin
binlog_format=row
skip-name-resolve
server-id=19
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

cat >/data/3310/my.cnf<<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3310/data
socket=/data/3310/mysql.sock
port=3310
log-error=/data/3310/mysql.log
log_bin=/data/3310/mysql-bin
binlog_format=row
skip-name-resolve
server-id=20
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

#启动文件
cat >/etc/systemd/system/mysqld3307.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3308.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3309.service<<EOF
[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 = 5000
EOF

cat >/etc/systemd/system/mysqld3310.service<<EOF
[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 = 5000
EOF

  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;"

分布式架构演变

猜你喜欢

转载自www.cnblogs.com/Mercury-linux/p/12468506.html
今日推荐