mysql主从实例docker实现
目录
准备写一篇关于sharding-proxy实现分片与读写分离介绍,需要准备主从同步,顺手记录下mysql主从实例的实现配置。
主从库优点
- 利用主从数据库来实现读写分离,减轻数据库压力
- 当主服务器出现问题时,还能作为备用数据库使用
主从同步逻辑
[图片来源:博客园]
-
master主服务器将对数据的操作记录到binlog,MySQL将事务串行的写入binlog;
-
slave从服务器将binlog复制到relaylog。首先,slave开始一个工作线程——I/O线程。
- slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接;
- 开始binlog dump process;
- 如果binlog dump process已经跟上master,它会睡眠并等待master产生新的事件。
- I/O线程将这些事件写入relaylog;
- SQL slave thread从relaylog读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致
主从同步复制有以下几种方式:
- 同步复制,master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。
- 异步复制,master只需要完成自己的数据库操作即可,至于slaves是否收到二进制日志,是否完成操作,不用关心。MYSQL的默认设置。
- 半同步复制,master只保证slaves中的一个操作成功,就返回,其他slave不管。这个功能,是由google为MYSQL引入的。
主从mysql实例容器
系统:ubuntu 16.04
# 下载mysql镜像
sudo docker pull mysql:5.7.25
# 启动mysql容器 实例02主机3310端口->容器3306
sudo docker run --name=mysql02 -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.25
# 启动mysql容器 实例03主机3311端口->容器3306
sudo docker run --name=mysql03 -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.25
确认
jm@ubuntu:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3b4fb3e6c2dc mysql:5.7.25 "docker-entrypoint.s…" 18 seconds ago Up 17 seconds 33060/tcp, 0.0.0.0:3311->3306/tcp mysql03
3f710a0f51de mysql:5.7.25 "docker-entrypoint.s…" 8 minutes ago Up 3 minutes 33060/tcp, 0.0.0.0:3310->3306/tcp mysql02
这里我们以mysql02实例作为master服务器,mysql03作为slave服务器。
master主服务器配置
进入mysql02容器
sudo docker exec -it mysql02 /bin/bash
编辑vim /etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]节点下增加sever-id、log-bin、log-bin-index配置:(以/etc/my.cnf文件实际情况找到相应节点)
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
#log-error = /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address = 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
server-id=1
log-bin=master-bin
log-bin-index=master-bin.index
如果没有vim工具,可以尝试安装,或通过docker挂载配置目录的方式从宿主机修改配置后同步到容器中,这里我们直接安装了vim,其实我们建议-v挂载的方式,然而不想重新启动容器了,在容器中安装vim:
# 容器使用的是debian,使用apt-get体系
apt-get update
apt-get install vim
退出容器(exit),重启mysql02容器:
sudo docker restart mysql02
查看master主服务器状态:
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 154 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
准备一个用户用于从slave服务器连接master服务器,并授予同步数据的权限:
mysql> create user syncer;
Query OK, 0 rows affected (0.01 sec)
mysql> grant replication slave on *.* to 'syncer'@'%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.01 sec)
注:% 通配符,表示支持任何客户端ip访问,但生产环境,建议是指定slave群ip段,比如192.168.8.%等
slave从服务器配置
进入mysql03容器(作为slave服务器)
sudo docker exec -it mysql03 /bin/bash
编辑/etc/mysql/mysql.conf.d/mysqld.cnf,指定server-id、relay-log、relay-log-index:
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
#log-error = /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address = 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
server-id=2
relay-log=salve-relay-bin
relay-log-index=slave-relay-bin.index
退出容器(exit),重启mysql03容器:
sudo docker restart mysql03
在slave服务器中指定同步的master服务器:
mysql> change master to master_host="192.168.8.130",master_port=3310,master_user="syncer",master_password="123456",master_log_file="master-bin.000001",master_log_pos=154;
Query OK, 0 rows affected, 1 warning (0.01 sec)
备注:
- master_host对应主服务器的IP地址。
- master_port对应主服务器的端口。
- master_log_file对应show master status显示的File列:master-bin.000001。
- master_log_pos对应show master status显示的Position列:154。
开启slave数据同步:
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
备注:stop slave可以用来停止数据同步
查看slave信息:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.8.130
Master_User: syncer
Master_Port: 3310
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 8971
Relay_Log_File: salve-relay-bin.000004
Relay_Log_Pos: 4343
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 8971
Relay_Log_Space: 7887
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 3c49d64e-df94-11eb-be45-0242ac110004
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
Slave_IO_Running 和 Slave_SQL_Running 都为yes,则表示同步成功。
测试
# mysql02 - master
CREATE DATABASE test;
USE test;
CREATE TABLE `t_user` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
INSERT INTO t_user(`name`) VALUES("小鱼"),("香香")
INSERT INTO t_user(`name`) VALUES("tsing"),("9ong")
# mysql03 - slave
mysql> select * from t_user;
+----+--------+
| id | name |
+----+--------+
| 1 | 小鱼 |
| 2 | 香香 |
| 3 | tsing |
| 4 | 9ong |
+----+--------+
主从常见问题
读写分离的问题
-
读写分离的基本结构
- 客户端直连,由客户端做负载均衡
- 中间proxy架构
-
过期读解决方案
- 强制走主库方案(客户端查询请求分类连接)
- sleep 方案(主库更新后,读从库之前先 sleep 一下)
- 判断主备无延迟方案
- 配合 semi-sync 方案(引入半同步复制)
- 等主库位点方案
- 等 GTID 方案
其实,在实际应用中,这几个方案是可以混合使用的。比如,先在客户端对请求做分类,区分哪些请求可以接受过期读,而哪些请求完全不能接受过期读;然后,对于不能接受过期读的语句,再使用等 GTID 或等位点的方案。但话说回来,过期读在本质上是由一写多读导致的。在实际应用中,可能会有别的不需要等待就可以水平扩展的数据库方案,但这往往是用牺牲写性能换来的,也就是需要在读性能和写性能中取权衡。
sharding-proxy实现读写分离
详见:sharding-proxy部署及php验证分片与读写分离