Mysql集群及读写分离

一、集群搭建之主从复制

(一)主从复制原理

  这里需要了解两个文件,bin log和relay log(中继日志)文件。

  bin log:bin log记录所有的数据更改操作,可用于本机数据恢复和主从数据同步,其刷入磁盘方式有三种:每秒一次将数据刷新入磁盘;每次事务提交将数据刷新入磁盘;每一秒一次 + 每次事务提交   都会将数据刷入磁盘。

  relay log:中继日志会进行回访,从而使从数据库达到与主数据库主从同步的目的。

  主从复制的原理就是:

    主服务器会将binlog写入本地,从数据库定时请求增量binlog,然后主节点将binlog同步到从节点;

    从节点单独的线程将binlog 复制到从节点的 relaylog中

    从节点定时重放relaylog

  上面说到,主服务器会将数据变更刷入磁盘,那么刷新类型有三种模式。

  binlog的三种模式:

模式 说明 优点 缺点
statement level 每一条修改数据的sql都会被记录到master节点的bin-log中,slave在复制的时候,会将该sql重新执行一遍 其只需要关心在master节点上执行的sql及语句执行的上下文信息,不需要记录每一行数据的变化,减少了bin-log的数据量,节约io,提高性能, 由于该种模式记录的是执行sql,为了能让sql在slave上也能正常的执行,其需要记录sql执行的上下文信息,但是由于mysql发展很快,在执行一些特定函数的时候,已经发现不少会造成主从复制问题的情况,例如sleep()函数就不能正常复制    
row level 日志中会记录成每一条数据被修改的形式,slave直接将数据进行修改 不需要记录修改数据的上下文信息,仅仅记录了被修改成什么样子,因此不存在无法被正确的主从复制的情况 由于需要记录每一条数据变更的数据,因此bin-log的日志量会很大,会增加io
mixed 就是上面两种情况的结合体,在该种模式下,会根据sql语句的具体内容来选择使用statement level还是选择row level    

  查看binlog日志模式

mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

  调整binlog日志模式

mysql> set binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'binlog_format';
+---------------+-----------+
| Variable_name | Value     |
+---------------+-----------+
| binlog_format | STATEMENT |
+---------------+-----------+
1 row in set (0.00 sec)

  查看bin log和relay log日志

   首先查看binlog是否开启

mysql> show variables like 'log%';
+----------------------------------------+---------------------+
| Variable_name                          | Value               |
+----------------------------------------+---------------------+
| log_bin                                | OFF                 |
| log_bin_basename                       |                     |
| log_bin_index                          |                     |
| log_bin_trust_function_creators        | OFF                 |
| log_bin_use_v1_row_events              | OFF                 |
| log_builtin_as_identified_by_password  | OFF                 |
| log_error                              | /var/log/mysqld.log |
| log_error_verbosity                    | 3                   |
| log_output                             | FILE                |
| log_queries_not_using_indexes          | OFF                 |
| log_slave_updates                      | OFF                 |
| log_slow_admin_statements              | OFF                 |
| log_slow_slave_statements              | OFF                 |
| log_statements_unsafe_for_binlog       | ON                  |
| log_syslog                             | OFF                 |
| log_syslog_facility                    | daemon              |
| log_syslog_include_pid                 | ON                  |
| log_syslog_tag                         |                     |
| log_throttle_queries_not_using_indexes | 0                   |
| log_timestamps                         | UTC                 |
| log_warnings                           | 2                   |
+----------------------------------------+---------------------+

  可以看到binlog是关闭的(log_bin的值为OFF),需要开启,只需要在/etc/my.cnf文件中增加以下内容,然后重启mysql服务即可。

log-bin=mysql-bin
server-id=1
binlog_format=ROW

  如果在/etc/my.cnf中没有设置binlog的位置,则默认在/var/lib/mysql文件夹中,会生成mysql-bin.0000*的文件,由于该文件是个二进制文件,没办法直接查看,这里可以使用mysql自带的mysqlbinlog工具进行解码,将该二进制文件转为可阅读的sql语句。

mysqlbinlog --base64-output=decode-rows -v -v mysql-bin.000001 > binlog

  

   可以发现已经多了一个binlog文件, 然后,可以使用vim直接查看

(二)基于binlog主从复制

  1、主从服务器都先关闭防火墙:

#关闭防火墙
systemctl stop firewalld
#设置开机不启动
systemctl disable firewalld.service

  2、主服务器配置

  (1)然后需要保证主服务器binlog是开启状态,如果未开启,需要修改my.cnf配置文件进行开启,同时,主从的service-id不能一致

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid


# MySQL设置大小写不敏感:默认:区分表名的大小写,不区分列名的大小写 # 0:大小写敏感 1>:大小写不敏感
lower_case_table_names=1
# 默认字符集
character-set-server=utf8

log-bin=mysql-bin
server-id=104

  (2)修改my.cnf配置文件需要重启服务。

  (3)给从服务器授权备份权限

  进入mysql后,可以使用如下命令进行授权操作  grant replication slave on *.* to '从服务器用户名'@'从服务器IP' identified by '从服务器密码';     其中  *.*  表示授权所有库的所有表。

grant replication slave on *.* to 'root'@'192.168.1.106' identified by 'root';

  如果在执行语句过程中,提示密码策略不符合要求,可以先对密码策略做修改,修改密码策略详见 https://www.cnblogs.com/liconglong/p/14437439.html 中 第二点(安装)中第5点(修改初始密码)

  上述命令样例中,可以将从服务器的ip替换为%,表示不限制ip,只要用户名密码正确,就可以备份。

grant replication slave on *.* to 'root'@'%' identified by 'root';

  (4)刷新权限

flush privileges;

  (5)查看主服务器状态

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      884 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

  3、从服务器配置

  (1)修改从服务器配置

  修改从服务的配置文件my.cnf,设置service-id,要与主服务器区别开

  (2)删除错误的UUID

rm -f /var/lib/mysql/auto.cnf

  (3)重启服务器

  (4)登录到mysql中,对从服务器进行配置

  需要配置从服务器的host、user、password等内容;

  其中主服务器的binlog文件名称,是在查看主服务器状态时的File的值;

  master_log_pos则是对应主服务器的positions;

  MASTER_AUTO_POSITION大小写敏感,必须为大写。

change master to
master_host='192.168.1.104',
master_port=3306,
master_user='root',
master_password='root',
master_log_file='mysql-bin.000001',
master_log_pos=884,
MASTER_AUTO_POSITION=0;

  (5)启动从服务器

mysql> start slave;

  (6)查看从服务状态

mysql> show slave status G;
*************************** 1. row ***************************.............
                  Master_Host: 192.168.1.104
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 884
               Relay_Log_File: bogon-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..............

  其中Slave_IO_Running和Slave_SQL_Running必须为YES,否则的话就是没有配置成功。

  (7)测试

  最后就是测试了,在主服务器上创建库、表即增删改数据,都会同步到从数据库上。

(三)主从同步延迟的原因及解决办法

  1、原因

  主从同步时,主服务器会把更新语句写入binlog,从服务器的IO线程(5.6.3之前的IO只有一个线程,5.6.3之后开始使用多线程,因此在5.6.3之后速度变快)会去读主服务器的binlog并且写入从服务器的relaylog,然后从服务器的sql线程会一个一个的执行relaylog中的sql,进行数据恢复。

  但是,主从复制的集群,只有主服务器对外提供服务,从服务器只作为备份使用,同时主服务器可能有多个客户端同时进行并发操作,但是从服务器读取binlog的线程只有一个,当某个sql执行时间较长,或者由于某个sql要进行锁表,就会导致主服务器的sql大量积压,从而未被同步到从服务器中,这也就是所谓的主从同步延迟。

  2、解决方案

  对于该种延迟的解决方法,并没有很确切的解决方案,但是我们可以提供一些环节措施。

  (1)调整binlog参数

  由于主服务器对安全性要求比较高,所以会设置一些参数,例如设置同步存储binlog、每次提交时更新binlog等(sync_binlog=1、innodb_flush_log_at_trx_commit=1),而从服务器不需要那么高的数据安全,完全可以异步更新binlog(sync_binlog=0)或者关闭binlog。innodb_flushlog、innodb_flush_log_at_trx_commit也可以设置为0来提高sql的执行效率(这个能很大程度的提高效率);另外一个就是可以使用比主库更好的硬件设备来作为从库。

  (2)从库只作为数据备份

  由于从库还有可能提供数据查询功能(读写分离),这样从库除了要获取主库的binlog之外,还要对外提供查询,可以将从库只作为数据备份库,不提供查询,从而降低从库的负载,从而提高效率。

  (3)增加从服务器。

  3、判断主从同步延迟

  查看从服务器的状态(show slave status G;),在输出结果中查看Seconds_Behind_Master的值,如果为0,表明主从复制状态正常,如果为NULL,说明主从同步发生了延迟或故障。

二、集群搭建之读写分离

  主从复制只会保证主服务器对外提供服务,而从服务器不对外提供服务,只作为数据备份使用。

  读写分离,主服务器提供读写服务,从数据库提供读服务。

  其实也可以两个数据库互为主从,那么两个服务器就会同时对外提供读写服务。

  数据库读写分离可以使用Mysql-proxy或Mysql-Mouter实现

  上面已经使用192.168.1.104和192.168.1.106做了主从复制,在该基础上继续做读写分离

(一)Mysql-Proxy

  1、下载&解压

  在一台新的服务器上下载Mysql-Proxy并解压

 wget https://cdn.mysql.com/archives/mysql-proxy/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz
tar -zxvf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz
mv mysql-proxy-0.8.5-linux-el6-x86-64bit mysql-proxy

  2、配置Mysql-Proxy配置文件

  创建mysql-proxy.cnf

vi mysql-proxy.cnf

  内容

[mysql-proxy]
user=root
admin-username=root
admin-password=root
proxy-address=0.0.0.0:3306
proxy-backend-addresses=192.168.1.104:3306
proxy-read-only-backend-addresses=192.168.1.106:3306
proxy-lua-script=./share/doc/mysql-proxy/rw-splitting.lua
log-file=./mysql-proxy.log
log-level=debug
keepalive=true
daemon=true

  其中proxy-address为可以设置监控的ip和端口,proxy-backend-addresses为主服务器地址(提供读写服务),proxy-read-only-backend-addresses为从服务地址(提供写服务)

  修改配置文件权限

chmod 660 mysql-proxy.cnf

  修改rw-splitting.lua脚本,位置在mysql-proxy/share/doc/mysql-proxy下,将最小连接和最大连接都改为1,方便模拟测试。

if not proxy.global.config.rwsplit then
        proxy.global.config.rwsplit = {
                min_idle_connections = 1,#默认超过4个连接数时,才开始读写分离,改为1 测试需要
                max_idle_connections = 1,#默认8,改为1测试需要
                is_debug = false
        }
end

  3、启动

./bin/mysql-proxy --defaults-file=mysql-proxy.cnf > mysql-proxy.out 2>&1 &

  说明:Mysql-proxy虽然可以实现读写分离,但是Mysql官方并没有推出稳定版本,因此不推荐在生产中使用,在生产中使用推荐Mysql-Mouter。

(二)Mysql-Mouter

   Mysql Router2.0是初始版本,目前已经废弃,2.1版本为支持Mysql InnoDB Cluster而引入,从2.1.5版本之后,就废弃了2.1.x的版本代号,转而使用8.0.x版本号,与mysql版本一致。

  1、下载&解压

wget https://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-8.0.23-linux-glibc2.12-x86_64.tar.xz
tar -xvJf mysql-router-8.0.23-linux-glibc2.12-x86_64.tar.xz
mv mysql-router-8.0.23-linux-glibc2.12-x86_64 mysql-router

  2、配置mysqlrouter.cnf文件

vi mysqlrouter.cnf

  内容

[logger]
level = INFO

[routing:secondary]
bind_address = localhost
bind_port = 7001
destinations = 192.168.1.104:3306,192.168.1.106:3306
routing_strategy = round-robin

[routing:primary]
bind_address = localhost
bind_port = 7002
destinations = 192.168.1.134:3306,192.168.1.106:3306
routing_strategy = first-available

  配置文件中配置了两个两个路由策略,一个是开放7001端口,通过循环的使用配置的ip,一个通过7002端口,只使用第一个ip

  3、启动mysqlrouter

./bin/mysqlrouter -c mysqlrouter.conf &

  4、测试

  修改主从服务器的hostname,以便可以区分连的是哪一台数据库,修改后重启服务器。

vi /etc/hostname

  使用7001端口可以发现,是轮询使用。

[root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-106  |
+------------+
[root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-104  |
+------------+
[root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-106  |
+------------+
[root@bogon mysql-router]# mysql -uroot -proot -P7001 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-104  |
+------------+

  使用7002端口,可以发现,只使用了主服务器

[root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-106  |
+------------+
[root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-106  |
+------------+
[root@bogon mysql-router]# mysql -uroot -proot -P7002 --protocol=tcp -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mysql-106  |
+------------+

  根据以上可以看到,主要是使用了routing_strategy来配置了轮询方案,对于轮询方案,有以下四种

  round-robin:轮询,以实现负载均衡

  roud-robin-with-fallback:用于InnoDB Cluster,每个新的连接都循环连接到下一个可用的SECONDARY服务器,如果SECONDARY服务器不可用,则以循环方式使用PRIMIARY服务器

  first-available:使用第一个可用的服务器

  next-valiable:使用第一个可用的服务器。与first-avaliable不同的是,如果一个服务器被标记为不可用,那么该服务器江湖被丢弃,并且永远不会再次用作目标。但是router重启,被丢弃的服务器将可再次使用。

三、基于主从复制的高可用方案

  这种方案主要是双节点主从 + keepalived/heartbeat方案,一般来说,中小型规模的时候,采用这种架构是最省事的。两个节点可以采用简单的一主一从模式,或者双主模式,并且放置于同一个VLAN中,在master节点发生故障后,利用keepalived/heartbeat的高可用机制实现快速切换到slave节点。

  这里主要说明一点,把两个节点的auto_increment_increment(自增起始值)和auto_increment_offset(自增步长)设成不同值。其目的是为了避免master节点意外宕机时,可能会有部分binlog未能及时复制到slave上被应用,从而会导致slave新写入数据的自增值和原先master上冲突了,因此一开始就使其错开;当然了,如果有合适的容错机制能解决主从自增ID冲突的话,也可以不这么做。

------------------------------------------------------------------
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~
原文地址:https://www.cnblogs.com/liconglong/p/14448456.html