一、Mysql复制简介

     随着业务规模的增加当单台mysql服务器承载的访问压力过大时的可以通过mysql内置的复制功能向外扩展;mysql的复制功能是实现mysql大规模高性能应用的基本工具


1、复制的作用

数据分布

   能跨越互联网完成数据复制

负载均衡

   均衡读操作,适用于读密集型的应用

备份

   备份从服务器,不影响主服务器的应用

高可用和故障切换

   mysql主从 + keepalived 实现mysql的高可用

mysql升级测试


2、复制的原理

     对mysql的复制是通过二进制日志实现的,当主节点mysql服务器发生任何有可能引起数据变化的操作,产生二进制日志信息时,从节点从主节点复制二进制日志文件中的增加的条目并执行。

复制是单向的,从服务器应该只读(否则数据一定会不一致)。


SLAVE:从服务器

  IO thread:

      向主服务器请求二进制日志中的事件,如果没有新的事件,将进入睡眠状态,有新事件时,主服务器会通知给从服务器

  SQL thread:

     从中继日志读取事件并在本地执行

MASTER:

  binlog dump(倾倒线程,二进制转储线程):将IO thread请求的事件发送给对方


3、MySQL复制时默认为异步工作模式

async会带来以下几个问题:

 1)从服务器落后于主服务器

 2)主从数据不一致   # 无法避免


4、复制如何开始

 1)都从0开始 

 2)主服务器已运行了一段时间,并且存在不小的数据集 # 不演示  

      在主节点做一个完全备份,并记录二进制日志文件及位置(方便做增量备份),然后在从服务器恢复,并在启动复制时从记录的二进制日志文件和位置开始复制


二、主从复制的配置

1、环境

Node2:CentOS 6.5 x86_64  mariadb 10.1.20

Node5:CentOS 6.5 x86_64  mariadb 10.1.21

注意:

   双方的myslq版本要一致,如果不一致,主的要低于从的

   双方的时间要同步


2、配置过程

master:

 1)启用二进制日志;

 2)设置一个在当前集群中惟一的server-id;

 3)创建一个有复制权限的(REPLICATION SLAVE, REPLICATION CLIENT)账号;

MariaDB [(none)]> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'node5' identified by "123";

从服务器连接进来后:

MariaDB [(none)]> show processlist\G
*************************** 1. row ***************************
      Id: 9
    User: root
    Host: localhost
      db: NULL
 Command: Query
    Time: 0
   State: init
    Info: show processlist
Progress: 0.000
*************************** 2. row ***************************
      Id: 10
    User: repluser
    Host: Node5:54078
      db: NULL
 Command: Binlog Dump
    Time: 201
   State: Master has sent all binlog to slave; waiting for binlog to be updated
    Info: NULL
Progress: 0.000
2 rows in set (0.00 sec)

MariaDB [(none)]>


slave:

 1)启用中继日志,可以把二进制日志取消

# vim /etc/my.cnf

### 在mysqld段添加
relay-log = /data/mydata/relay-bin

 2)设置一个在当前集群中惟一的server-id;

 3)使用有复制权限的用户账号连接至主服务器,并启动复制线程;


连接主服务器命令:

  CHANGE MASTER TO option [,option]...

option:

   MASTER_BIND = 'interface_name'

 | MASTER_HOST = 'host_name'       主服务器地址:主机名或地址,都需要用引号

 | MASTER_USER = 'user_name'       以那个用户的身份复制

 | MASTER_PASSWORD = 'password'     密码

 | MASTER_PORT = port_num         端口

 | MASTER_CONNECT_RETRY = interval      连接重试的间隔时长

 | MASTER_HEARTBEAT_PERIOD = interval    探测主服务器心跳的间隔时长

 | MASTER_LOG_FILE = 'master_log_name'   从主服务器的哪个日志文件开始复制

 | MASTER_LOG_POS = master_log_pos      从主服务器的哪个位置点开始复制

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST="192.168.10.2",master_user="repluser",MASTER_PASSWORD="123";
MariaDB [(none)]> SHOW MASTER STATUS;
Empty set (0.00 sec)

MariaDB [(none)]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.10.2
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No        # 没运行
            Slave_SQL_Running: No        # 没运行
              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: 0
              Relay_Log_Space: 249
              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: NULL
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: 0
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: No
                  Gtid_IO_Pos: 
      Replicate_Do_Domain_Ids: 
  Replicate_Ignore_Domain_Ids: 
                Parallel_Mode: conservative
1 row in set (0.00 sec)

MariaDB [(none)]> SHOW PROCESSLIST;
+----+------+-----------+------+---------+------+-------+------------------+----------+
| Id | User | Host      | db   | Command | Time | State | Info             | Progress |
+----+------+-----------+------+---------+------+-------+------------------+----------+
|  5 | root | localhost | NULL | Query   |    0 | init  | SHOW PROCESSLIST |    0.000 |
+----+------+-----------+------+---------+------+-------+------------------+----------+
1 row in set (0.00 sec)


启动复制线程命令:

   START SLAVE [thread_types];


   START SLAVE [SQL_THREAD] UNTIL

        MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos;

                               # 复制到哪个位置点截止停止复制

   START SLAVE [SQL_THREAD] UNTIL

        RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos

                                 # 复制到哪个位置点截止停止在本地执行?

thread_types:  

   [thread_type [, thread_type] ... ]

thread_type: IO_THREAD | SQL_THREAD    # 不指定则默认2个线程都启动

MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.2
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000005
          Read_Master_Log_Pos: 366
               Relay_Log_File: relay-bin.000009
                Relay_Log_Pos: 654
        Relay_Master_Log_File: mysql-bin.000005
             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: 366
              Relay_Log_Space: 989
              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_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: No
                  Gtid_IO_Pos: 
      Replicate_Do_Domain_Ids: 
  Replicate_Ignore_Domain_Ids: 
                Parallel_Mode: conservative
1 row in set (0.00 sec)

MariaDB [(none)]> 


MariaDB [(none)]> SHOW PROCESSLIST\G;
*************************** 1. row ***************************
      Id: 5
    User: root
    Host: localhost
      db: NULL
 Command: Query
    Time: 0
   State: init
    Info: SHOW PROCESSLIST
Progress: 0.000
*************************** 2. row ***************************
      Id: 6
    User: system user
    Host: 
      db: NULL
 Command: Connect
    Time: 20
   State: Waiting for master to send event
    Info: NULL
Progress: 0.000
*************************** 3. row ***************************
      Id: 7
    User: system user
    Host: 
      db: NULL
 Command: Connect
    Time: 20
   State: Slave has read all relay log; waiting for the slave I/O thread to update it
    Info: NULL
Progress: 0.000
3 rows in set (0.00 sec)

ERROR: No query specified

MariaDB [(none)]>

   此时在主服务器上进行写操作,从复制会马上复制过来;

停止从服务器的线程:

STOP SLAVE

重启从服务器的mysqld会自动启动Slave_SQL_Running和Slave_IO_Running。


说明:

      如果 Last_SQL_Error 没有错误提示以及 Salve 中的 Read_Master_Log_Pos 值和 Master 中的 show master status; 中的 Postition 值是一样的,这样的话,MySQL 主从复制应该是成功的。


  写一个监控脚本,用来监控 Slave 中的两个"yes",如果只有一个"yes"或者零个,就表明主从有问题。(有报错时相应的线程就会停止)


三、双主

1、双主模型简介

    互为主从

    mysql从服务器复制主服务器的二进制日志时,会保留对方信息中的Server ID,如果从服务器发现Server是自己的,就不会复制到本地并执行。   

  需要解决的问题:

    1)必须设定双方的的自动增长属性,以避免冲突

       auto_increment_increment = N   # 设定起始值

       auto_increment_offset = 2     # 设定步长

          应该写在配置文件中

MariaDB [(none)]> show global variables like '%increment%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| auto_increment_increment     | 1     |     # 偏移量(每次增加多少)
| auto_increment_offset        | 1     |     # 从哪个数字开始偏移(增加)
| div_precision_increment      | 4     |
| innodb_autoextend_increment  | 64    |
| wsrep_auto_increment_control | ON    |
+------------------------------+-------+
5 rows in set (0.00 sec)

    2)数据不一致   # 服务避免

        某时刻会有此场景:AB服务器都操作同一行数据,A锁定1字段,修改2字段;B锁定2字段对,修改1字段,同步后就会造成数据不一致。

       双主模型数据不一致无法避免,只能使用工具不停的检测双方数据的一致性,不一致时,自动修复数据;或手动同步一次,风险很大。

功能:

   均衡读请求,写请求没有分摊,要想分摊写操作,只能将数据库分片(非常复杂)


2、双主的配置过程

 1)各自使用不同的server id

 2)都启用bin-log和relay-log

 3)定义自定增长的id字段的增长方式

 4)都授权有复制权限的用户帐号

 5)各自把对方指定为服务器


3、实例

   使用上面的环境,为了避免被之前的数据影响,都重新初始化

 1)修改配置文件

node2:

[root@Node2 mysql]# vim /etc/my.cnf 


log-bin=/mysql_log/bin_log/mysql-bin
relay-log=relay-bin
auto_increment_offset=1
auto_increment_increment=2
# binary logging format - mixed recommended
binlog_format=mixed

# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
server-id       = 111

node5:

log-bin=/mysql_log/bin_log/mysql-bin
relay-log=relay-bin
auto_increment_offset=2
auto_increment_increment=2
# binary logging format - mixed recommended
binlog_format=mixed

# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
server-id       = 222

 2)启动并授权用于复制的帐号

MariaDB [(none)]> grant replication slave,replication client on *.* to 'rpluser'@'192.168.%.%' identified by '123';
Query OK, 0 rows affected (0.00 sec)

 3)各自把对方指定为服务器并启动从服务器线程

MariaDB [(none)]> change master to master_host="192.168.10.5",master_user="rpluser",master_password="123";
Query OK, 0 rows affected (0.06 sec)

MariaDB [(none)]> start slave;

 4)测试

     各自增加数据,检查是否都同步了

node2:

MariaDB [(none)]> create database node2;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      773 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

MariaDB [(none)]> use node2
Database changed
MariaDB [node2]> create table tb1(id int unsigned not null auto_increment primary key,name char(8));
Query OK, 0 rows affected (0.41 sec)

MariaDB [node2]> insert into tb1 (name) value ("stu1"),("stu2");
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [node2]> select * from tb1;
+----+------+
| id | name |
+----+------+
|  1 | stu1 |
|  3 | stu2 |
+----+------+
2 rows in set (0.00 sec)

MariaDB [node2]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |     1170 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

MariaDB [node2]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.5
                  Master_User: rpluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 1052
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 1340
        Relay_Master_Log_File: mysql-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: 1052
              Relay_Log_Space: 1632
              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: 222
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: No
                  Gtid_IO_Pos: 
      Replicate_Do_Domain_Ids: 
  Replicate_Ignore_Domain_Ids: 
                Parallel_Mode: conservative
1 row in set (0.00 sec)

MariaDB [node2]>


node5:

MariaDB [(none)]> create database node2;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> use node5
Database changed
MariaDB [node5]>  create table tb1(id int unsigned not null auto_increment primary key,name char(8));Query OK, 0 rows affected (0.04 sec)

MariaDB [node5]> insert into tb1 (name) value ("stu1"),("stu2");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

MariaDB [node5]>  select * from tb1;
+----+------+
| id | name |
+----+------+
|  2 | stu1 |
|  4 | stu2 |
+----+------+
2 rows in set (0.00 sec)

MariaDB [node5]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |     1052 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

MariaDB [node5]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.2
                  Master_User: rpluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 1170
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 1458
        Relay_Master_Log_File: mysql-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: 1170
              Relay_Log_Space: 1750
              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: 111
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
                   Using_Gtid: No
                  Gtid_IO_Pos: 
      Replicate_Do_Domain_Ids: 
  Replicate_Ignore_Domain_Ids: 
                Parallel_Mode: conservative
1 row in set (0.00 sec)

MariaDB [node5]>

   

注意:

   实际生产应用中,双主模型我们手动维护的并不多,推荐使用主从,必须要使用双主或多主时可以使用多主且高可用的开源解决方案:

MMM:Multi Master MySQL

MHA:MySQL HA

Percona Galera Cluster



四、mysql主从复制的应用扩展

1、如何限制从服务器只读

 read_only=ON 

MariaDB [(none)]> show variables like 'read_only';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only     | OFF   |
+---------------+-------+
1 row in set (0.01 sec)
MariaDB [(none)]> set global read_only=1;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> select @@read_only;
+-------------+
| @@read_only |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

  read_only=1 应该配置在从服务器的[mysqld]段中

注意: 

   对于不具有super权限的用户有效,不能限制管理员,切勿使用root用户直接在从服务器上修改数据,ALL权限不包括super权限 


那如何限制所有用户呢?

  启用一个线程连接到从服务器执行flush tables with read locak并一直不释放(可以使用screen)

 FLUSH TABLES WITH READ LOCK;


2、如何保证主从复制时的事务安全

    默认情况下mysql为了提高二进制日志IO性能会将修改数据和有潜在可能性影响数据的语句先保存在二进制日志缓冲区(内存)中,当一个事务提交后,数据会持久的保存在innodb数据文件中,但二进制日志可能需要过一会才会保存在二进制日志中;当主服务器的事务尚未同步到二进制日志中时,如果主服务器宕机,则从服务器无法获取完整的事务,当从服务器指向其它主服务器时候,有可能导致事务回滚,从而使得事务丢失。

 

    可以在主服务器上配置一下参数解决,只要事务提交,则立即将事务从二进制缓冲区同步到二进制日志中。

   sync_binlog 和 innodb_flush_log_at_trx_commit 两个参数是控制MySQL 磁盘写入策略以及数据安全性的关键参数。本文从参数含义,性能,安全角度阐述两个参数为不同的值时对db 性能,数据的影响.

   innodb_flush_log_at_trx_commit 和 sync_binlog 是 MySQL 的两个配置参数,前者是 InnoDB 引擎特有的。之所以把这两个参数放在一起讨论,是因为在实际应用中,它们的配置对于 MySQL 的性能有很大影响。   


参数意义:

  sync_binlog

MariaDB [node5]> select @@sync_binlog;    # 默认为0
+---------------+
| @@sync_binlog |
+---------------+
|             0 |
+---------------+
1 row in set (0.00 sec)

    MyISAM存储引擎在我们的生产中用的并不多,但是系统的数据字典表元数据等都是存储在MyISAM引擎下。

    MyISAM不支持事务,且没有data cache,所有DML操作只写到OS cache中,flush disk操作均由OS来完成,因此如果服务器宕机,则这部分数据肯定会丢失。

 master写binlog与innodb引擎写redo类似,也有参数控制:sync_binlog

          = 0 :表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新

          > 0 :表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去

    其中最安全的就是=1,表示每次事务提交,MySQL都会把binlog缓存刷下去,这样在掉电等情况下,系统才有可能丢失1个事务的数据。当sync_binlog设置为1,对系统的IO消耗也是非常大的。


    sync_binlog 是MySQL 的二进制日志(binary log)从内存缓冲区同步到磁盘的频率。MySQL server 在 binary log(理解为事务提交) 每写入sync_binlog 次后,刷写到磁盘。

如果 autocommit 开启,每个语句都写一次 binary log,否则每次事务写一次。

sync_binlog 的默认值是 0,不主动同步,而依赖操作系统本身不定期把文件内容 flush 到磁盘。设为 1 最安全,在每个语句或事务后同步一次 binary log,即使在崩溃时也最多丢失一个语句或事务的日志,但因此也最慢。

大多数情况下,对数据的一致性并没有很严格的要求,所以并不会把 sync_binlog 配置成 1. 为了追求高并发,提升性能,可以设置为 100 或直接用 0. 而和 innodb_flush_log_at_trx_commit 一样,对于支付服务这样的应用,还是比较推荐 sync_binlog = 1.


如果用到的为innoDB存储引擎:

  inodb_support_xa=on 

       支持分布式事务

  innodb_flush_log_at_trx_commit

MariaDB [node5]> select @@global.innodb_flush_log_at_trx_commit;   # 默认就支持
+-----------------------------------------+
| @@global.innodb_flush_log_at_trx_commit |
+-----------------------------------------+
|                                       1 |
+-----------------------------------------+
1 row in set (0.00 sec)

MariaDB [node5]> select @@global.innodb_support_xa;
+----------------------------+
| @@global.innodb_support_xa |
+----------------------------+
|                          1 |
+----------------------------+
1 row in set (0.00 sec)

MariaDB [node5]>

  InnoDB支持事务,同Oracle类似,事务提交需要写redo、undo。采用日志先行的策略,将数据的变更在内存中完成,并且将事务记录成redo,顺序的写入redo日志中,即表示该事务已经完成,就可以返回给客户已提交的信息。但是实际上被更改的数据还在内存中,并没有刷新到磁盘,即还没有落地,当达到一定的条件,会触发checkpoint,将内存中的数据(page)合并写入到磁盘,这样就减少了离散写、IOPS,提高性能。

    在这个过程中,如果服务器宕机了,内存中的数据丢失,当重启后,会通过redo日志进行recovery重做。确保不会丢失数据。因此只要redo能够实时的写入到磁盘,InnoDB就不会丢数据。

先来看一下innodb_flush_log_at_trx_commit这个参数:

    = 0 :每秒 write cache & flush disk

    = 1 :每次commit都 write cache & flush disk

    = 2 :每次commit都 write cache,然后根据innodb_flush_log_at_timeout(默认为1s)时间 flush disk

    从这三个配置来看,显然innodb_flush_log_at_trx_commit=1最为安全,因为每次commit都保证redo写入了disk。但是这种方式性能对DML性能来说比较低,在我们的测试中发现,如果设置为2,DML性能要比设置为1高10倍左右。


简而言之,innodb_flush_log_at_trx_commit 参数指定了 InnoDB 在事务提交后的日志写入频率。这么说其实并不严谨,且看其不同取值的意义和表现。

  1. 当 innodb_flush_log_at_trx_commit 取值为 0 的时候,log buffer 会 每秒写入到日志文件并刷写(flush)到磁盘。但每次事务提交不会有任何影响,也就是 log buffer 的刷写操作和事务提交操作没有关系。在这种情况下,MySQL性能最好,但如果 mysqld 进程崩溃,通常会导致最后 1s 的日志丢失。

  2. 当取值为 1 时,每次事务提交时,log buffer 会被写入到日志文件并刷写到磁盘。这也是默认值。这是最安全的配置,但由于每次事务都需要进行磁盘I/O,所以也最慢。

  3. 当取值为 2 时,每次事务提交会写入日志文件,但并不会立即刷写到磁盘,日志文件会每秒刷写一次到磁盘。这时如果 mysqld 进程崩溃,由于日志已经写入到系统缓存,所以并不会丢失数据;在操作系统崩溃的情况下,通常会导致最后 1s 的日志丢失。

上面说到的「最后 1s」并不是绝对的,有的时候会丢失更多数据。有时候由于调度的问题,每秒刷写(once-per-second flushing)并不能保证 100% 执行。对于一些数据一致性和完整性要求不高的应用,配置为 2 就足够了;如果为了最高性能,可以设置为 0。有些应用,如支付服务,对一致性和完整性要求很高,所以即使最慢,也最好设置为 1.


在slave节点:

  read_only=on

  relay-log=/PATH/TO/SIME_FILE    # 中继日志放在另外一个路径下,不跟数据文件在同一磁盘下

  skip_slave_start            # 跳过slave启动(启动从节点mysqld时,不自动启动slave线程,从节点重启mysqld会自动启动slave线程) 


不考虑IO影响还可以设置以下参数:

主节点: 

  sync_master_info=1


从节点:

  sync_relay_log=1

  sync_relay_log_info=1

MariaDB [node5]> show global variables like 'sync_master%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| sync_master_info | 10000 |
+------------------+-------+
1 row in set (0.00 sec)

MariaDB [node5]> select @@global.sync_relay_log;
+-------------------------+
| @@global.sync_relay_log |
+-------------------------+
|                   10000 |
+-------------------------+
1 row in set (0.00 sec)

MariaDB [node5]> select @@global.sync_relay_log_info;
+------------------------------+
| @@global.sync_relay_log_info |
+------------------------------+
|                        10000 |
+------------------------------+
1 row in set (0.00 sec)


跟复制功能相关的文件

master.info:

    用于保存slave连接至master时的相关信息;

relay-log.info:

    保存了当前slave节点上已经复制的当前二进制日志和本地relay log日志对应关系; 



附:

   MySQL丢数据及主从数据不一致的场景