目录

准备写一篇关于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   |
+----+--------+


主从常见问题

线上MYSQL同步报错故障处理方法总结

mysql从库同步失败_MySQL 主从同步错误解决

读写分离的问题

  • 读写分离的基本结构

    • 客户端直连,由客户端做负载均衡
    • 中间proxy架构
  • 过期读解决方案

    • 强制走主库方案(客户端查询请求分类连接)
    • sleep 方案(主库更新后,读从库之前先 sleep 一下)
    • 判断主备无延迟方案
    • 配合 semi-sync 方案(引入半同步复制)
    • 等主库位点方案
    • 等 GTID 方案

其实,在实际应用中,这几个方案是可以混合使用的。比如,先在客户端对请求做分类,区分哪些请求可以接受过期读,而哪些请求完全不能接受过期读;然后,对于不能接受过期读的语句,再使用等 GTID 或等位点的方案。但话说回来,过期读在本质上是由一写多读导致的。在实际应用中,可能会有别的不需要等待就可以水平扩展的数据库方案,但这往往是用牺牲写性能换来的,也就是需要在读性能和写性能中取权衡。

sharding-proxy实现读写分离

详见:sharding-proxy部署及php验证分片与读写分离


tsingchan@9ong.com