1. 前言
大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够。到了数据业务层、数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器来处理如此多的数据库连接操作,数据库必然会崩溃,特别是数据丢失的话,后果更是不堪设想。这时候,我们会考虑如何减少数据库的连接,下面就进入我们今天的主题。
利用主从数据库来实现读写分离,从而分担主数据库的压力。在多个服务器上部署mysql,将其中一台认为主数据库,而其他为从数据库,实现主从同步。其中主数据库负责主动写的操作,而从数据库则只负责主动读的操作(slave从数据库仍然会被动的进行写操作,为了保持数据一致性),这样就可以很大程度上的避免数据丢失的问题,同时也可减少数据库的连接,减轻主数据库的负载。
在Mysql-A的数据库事件(例如修改数据库的sql操作语句),都会存储到日志系统A中,在相应的端口(默认3306)通过网络发送给Mysql-B。Mysql-B收到后,写入本地日志系统B,然后一条条的将数据库事件在数据库Mysql-B中完成。
日志系统A,是MYSQL的日志类型中的二进制日志,也就是专门用来保存修改数据库表的所有动作,即bin log,注意MYSQL会在执行语句之后,释放锁之前,写入二进制日志,确保事务安全。
日志系统B,不是二进制日志,由于它是从MYSQL-A的二进制日志复制过来的,并不是自己的数据库变化产生的,有点接力的感觉,称为中继日志,即relay log。
通过上面的机制,可以保证Mysql-A和Mysql-B的数据库数据一致,但是时间上肯定有延迟,即Mysql-B的数据是滞后的。因此,会出现这样的问题,Mysql-A的数据库操作是可以并发的执行的,但是Mysql-B只能从relay log中一条一条的读取执行。若Mysql-A的写操作很频繁,Mysql-B很可能就跟不上了。
主从同步复制有以下几种方式:
(1)同步复制,master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。
(2)异步复制,master只需要完成自己的数据库操作即可,至于slaves是否收到二进制日志,是否完成操作,不用关心。MYSQL的默认设置。
(3)半同步复制,master只保证slaves中的一个操作成功,就返回,其他slave不管。这个功能,是由google为MYSQL引入的。
本文使用Docker安装,适用于对Docker有了解人群
2. 安装步骤
2.1 安装master
# 查询镜像
docker search mysql
# 执行结果
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 14304 [OK]
mariadb MariaDB Server is a high performing open sou… 5463 [OK]
phpmyadmin phpMyAdmin - A web interface for MySQL and M… 833 [OK]
percona Percona Server is a fork of the MySQL relati… 617 [OK]
bitnami/mysql Bitnami MySQL Docker Image 91 [OK]
databack/mysql-backup Back up mysql databases to... anywhere! 88
ubuntu/mysql MySQL open source fast, stable, multi-thread… 51
linuxserver/mysql-workbench 50
linuxserver/mysql A Mysql container, brought to you by LinuxSe… 38
circleci/mysql MySQL is a widely used, open-source relation… 29
google/mysql MySQL server for Google Compute Engine 23 [OK]
rapidfort/mysql RapidFort optimized, hardened image for MySQL 23
rapidfort/mysql8-ib RapidFort optimized, hardened image for MySQ… 9
rapidfort/mysql-official RapidFort optimized, hardened image for MySQ… 7
bitnami/mysqld-exporter 5
drupalci/mysql-5.5 https://www.drupal.org/project/drupalci 3 [OK]
newrelic/mysql-plugin New Relic Plugin for monitoring MySQL databa… 1 [OK]
vitess/mysqlctld vitess/mysqlctld 1 [OK]
hashicorp/mysql-portworx-demo 0
docksal/mysql MySQL service images for Docksal - https://d… 0
mirantis/mysql 0
bitnamicharts/mysql 0
eclipse/mysql Mysql 5.7, curl, rsync 0 [OK]
cimg/mysql 0
drupalci/mysql-5.7 https://www.drupal.org/project/drupalci 0
# 下载镜像
docker pull mysql:5.7
# 创建挂载目录
pwd -> /usr/local/docker/mysql/test/master
# 因为我云服务器安装过了主从 这是再次安装 所以路径比较长 XDM可以自行调整
cd /usr/local/docker/mysql/test/master
mkdir logs conf data
# 启动临时容器
docker run -it -d --name=mysql_tmp -p 13306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 复制容器中配置文件
cd conf
# 两个文件夹一定要加 否则启动报错
mkdir conf.d mysql.conf.d
docker cp mysql_tmp:/etc/my.cnf /usr/local/docker/mysql/test/master/conf/
# 修改配置文件
vim my.cnf
[mysql]
default-character-set=utf8
[mysqld]
#标识唯一id(必须),一般使用ip最后位
server-id=1
#开启二进制日志
log_bin=master-bin
log_bin_index=master-bin.index
default-storage-engine=INNODB
character_set_server=utf8
#不同步的数据库,可设置多个
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=mysql
#设置存储模式
binlog_format=MIXED
#日志清理时间
expire_logs_days=7
#日志大小
max_binlog_size=200m
#缓存大小
binlog_cache_size=5m
#最大缓存大小
max_binlog_cache_size=512m
#备注:
#server-id 服务器唯一标识。
#log_bin 启动MySQL二进制日志,即数据同步语句,从数据库会一条一条的执行这些语句。
#binlog_do_db 指定记录二进制日志的数据库,即需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可。
#binlog_ignore_db 指定不记录二进制日志的数据库,即不需要复制的数据库名,如果有多个数据库,重复设置这个选项即可。
#其中需要注意的是,binlog_do_db和binlog_ignore_db为互斥选项,一般只需要一个即可。
# 停止并删除临时容器
docker stop mysql_tmp
docker rm mysql_tmp
# 启动容器
docker run -it -d --restart=always --name=mysql_master
-v /usr/local/docker/mysql/test/master/conf:/etc/mysql
-v /usr/local/docker/mysql/test/master/logs:/var/log/mysql
-v /usr/local/docker/mysql/test/master/data:/var/lib/mysql
-p 13306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
# 查看容器日志 判断是否启动成功 或排查失败原因
docker logs -f mysql_master
# 启动成功后进入容器
docker exec -it mysql_master /bin/bash
# 进入mysql命令行界面
mysql -uroot -proot
# 创建从数据库的masterbackup用户和权限
mysql> grant replication slave on *.* to masterbackup@'127.0.0.1' identified by 'root';
#备注
#127.0.0.%通配符,表示0-255的IP都可访问主服务器,正式环境请配置指定从服务器IP
#若将 127.0.0.% 改为 %,则任何ip均可作为其从数据库来访问主服务器
#退出然后重启容器
mysql> exit;
exit
docker restart mysql_master
2.2 安装slaver
cd /usr/local/docker/mysql/test/slaver/
mkdir logs conf data
cd conf/
cp -f -r ../../master/conf/* ./
vim my.cnf
[mysql]
default-character-set=utf8
[mysqld]
server-id=2
default-storage-engine=INNODB
character_set_server=utf8
relay-log=slave-relay-bin
relay-log-index=slave-relay-bin.index
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=mysql
# 启动slaver
docker run -it -d --restart=always --name=mysql_slaver
-v /usr/local/docker/mysql/test/slaver/conf:/etc/mysql
-v /usr/local/docker/mysql/test/slaver/logs:/var/log/mysql
-v /usr/local/docker/mysql/test/slaver/data:/var/lib/mysql
-p 13307:3306 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
# 进入容器
docker exec -it mysql_slaver /bin/bash
mysql -uroot -proot
# 连接主库 因为在一台机器 所以可以使用127.0.0.1 一般来说主从不会在一台机器上 所以需要使用外网IP
# 在执行之前需要获取主库当前的master_log_file及master_log_pos 通过主库 mysql 命令行执行 show master status 获取;
#mysql> show master status;
#+-------------------+----------+--------------+---------------------------------------------+-------------------+
#| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
#+-------------------+----------+--------------+---------------------------------------------+-------------------+
#| master-bin.000003 | 453 | | information_schema,performance_schema,mysql | |
#+-------------------+----------+--------------+---------------------------------------------+-------------------+
#1 row in set (0.00 sec)
mysql> change master to master_host='127.0.0.1',master_port=13306,master_user='masterbackup',master_password='root',master_log_file='master-bin.000003',master_log_pos=453;
mysql> start slave;
# mysql> stop slave; 停止同步命令(如有需要)
mysql> show slave status\G;
# Slave_IO_Running和Slave_SQL_Running都为yes,则表示同步成功
# 如果Slave_IO_Running一直连接中 停止同步后把主服务和从服务设置的IP重新设置为外网地址
# - 主服务设置 grant replication slave on *.* to masterbackup@'127.0.0.1' identified by 'root';
# - 从服务设置 change master to master_host='127.0.0.1',master_port=13306,master_user='masterbackup',master_password='root',master_log_file='master-bin.000003',master_log_pos=453;
# 设置从服务时切记要和主服务master_log_file及master_log_pos一致