MySQL
的日志包括:事务日志,错误日志,一般查询日志,中继日志,慢查询日志
二进制日志:
mysql-bin.xxxxxx
日志会执行滚动操作:当日志大小达到最大上限时,或者执行FLUSH LOGS
,或者服务器重新启动时;statement row mixed
;SHOW MASTER STATUS;
SHOW BINARY LOGS;
SHOW BINLOG EVENTS IN | BEFORE 'file';
二进制日志记录的事件内容包括:timestamp postion events
二进制日志用于即时点还原:在完全使用二进制日志在进行数据内容的恢复过程中,和原始数据不一定是一样的,存在以下几点原因:
CPU
的MySQL
服务器,可能会支持多事务,或者在事务的隔离级别影响下交叉执行,或者是并行执行,但是对于二进制日志文件只有一个,向文件里面写入内容都是串行的;一种情况就是使用事务的隔离级别为REPEATABLE-READ
并且二进制日志的记录格式为STATEMENT
,会导致数据不一致的可能性变大;
还有一种情况是:二进制日志的隔离级别为READ-UNCOMMITTED READ-COMMITTED
,并且二进制日志的记录格式为MIXED
,也会导致数据不一致的可能性变大;
statement
的格式的日志记录格式不建议使用;
关于主从复制的原理:
服务器A
接受前端用户的写入操作,这些写操作首先会被写入二进制日志文件中,并且一份写入数据文件;
服务器B
不接受任何前端用户的写操作,但是实时同步服务器A
的二进制日志文件,首先保存在自己的二进制日志文件里面,并且按照一定的时间读取里面的内容写入数据文件;
服务器A
称为master
,其二进制日志是由于数据的写入操作导致的;
服务器B
称为slave
,其二进制日志称为中继日志relay log
,这些日志不是由于自己的写入操作导致的,而是同步过来的日志文件进行重放;
slave
的数据写入肯定是慢于master
的,很可能由于master
和slave
的服务器性能差异太多,导致数据差异更大;
关于数据同步的三种模型:同步,异步,半同步;
MySQL
默认的同步策略是异步的,保证数据写入的速度,数据写入本地的二进制日志,并且写入磁盘设备,就认为写入完成;TCP/IP
的缓冲区里面,主从架构中的从节点中只要一个从节点返回数据保存成功,就认为数据已经保存成功,MySQL 5.5
通过补丁可以支持半同步,之前的版本都是不支持的,在一主多从的架构下,只要有一个结点返回数据插入成功,那么就认为数据插入完成;MySQL
服务器允许一主多从架构,所以异步同步策略是最佳同步策略,从服务器可以用于保证查询的效率,并且可以用于进行备份;从服务器需要备份的时候,如果需要进行即时点还原,需要的是主服务器的二进制日志,而不是从服务器的中继日志;
中继日志的格式和二进制日志格式是一致的,但是主服务器的二进制日志滚动,从服务器的二进制日志是不一定滚动的;例如FLUSH LOGS
,主服务器重新启动等;
slave
服务器是否需要二进制日志:
A---->B----->C
,A
的二进制日志传递给B
,B
生成中继日志,但是B
的中继日志不能够直接给C
,所以B
是需要记录二进制日志的;如果主服务器宕机,从服务器需要执行完主服务器上面产生的未同步过来的二进制日志,并且修改权限为可写,这样快速的执行故障恢复,可以提供类似于高可用的功能;
不能够把中继日志当作数据恢复的手段,必须使用主服务器的二进制日志来进行还原;
并且可以用于实现异地容灾;
最主要的功能是用于实现分摊负载,通常来说是读多写少,用于实现读写分离,通常来说读写分离需要通过前端的MySQL Proxy
代理来实现,这个代理成为rw-spliting
,这个读写分离代理必须理解前端的语句,代理并不能够实现读写分离,可以再代理和MySQL
服务器之间进行Directory
的实现负载均衡;
多个读服务器可以通过Memory Cache
来实现缓存共享,或者使用MySQL
自己的缓存,并且结合持久连接;
如果主从架构采用简单的架构进行复制,那么master
就需要为每一个slave
创建复制线程,负载仍然较大,所以这里需要使用多级复制,减轻master
的负担;
对于第二个节点:
在MySQL
服务器架构中,不适用MySQL
代理,如何实现主写从读,这个功能可以交给PHP
连接MySQL
的应用程序来解决,通过制定主服务器和从服务器来实现读写分离,但是这种方法也存在缺点,会破坏负载均衡,因为制定的算法都是各自进行调度的;
如果不想通过上述两种办法来解决,那么就可以通过MySQL
的双主模型来解决,但是不建议使用这种方式,因为性能低下;
上述模型可能出现的问题:
* 由于数据中继日志写入,会更新二进制日志,然后二进制日志会在另一个服务器上面执行,生成新的二进制日志,这样会导致无限循环;
* 对于上面的问题需要引入服务器ID
用于标示语句的执行情况,对于中继日志执行的写入操作,是必须写入自己的二进制日志文件里面的,因为一旦这个master
作为了slave
的master
,二进制就是不完善的 ,所以server ID
为对方ID
的是必须写入二进制日志的;
二进制日志中的格式会记录这个问题
双主模型是可以分担的是读负载,但是不能够分担写负载;
会因为更新特殊的数据导致数据不一致无法合并的问题;
主键使用的增长导致的主键冲突的问题;
当数据库的内容十分庞大时,查询,写入速度十分缓慢时,可以采用拆库的策略,将各个库独立出来,用于减轻服务器的压力;
垂直拆分:将一个库拆分为多个库,数据库存在数据热区的,有时候是某张表的频繁查询减低了查询速度;
水平拆分:可以将表进行拆分;
在执行水平拆分以及垂直拆分之后,当查询的操作涉及多个表,并且需要将这些表的数据整合返回时,就需要借助于MySQL
路由设备 ,用于完成上述操作;
数据的插入操作需要按照拆分表时的逻辑,来执行数据的的插入负载均衡,而不是统一在某个服务器上面完成操作;
数据库的拆分,需要理解业务逻辑,根据业务来进行拆分,
MySQL多主模型的循环复制 需要解决
读写分离的工具:MySQL -proxy amoba cobar(业务逻辑拆分工具)
配置MySQL
的主从复制架构:
通常是一个master
多个slave
架构,但是不能够一slave
多个master
;
MySQL 5.5
之前的版本:复制功能比较简单,但是在MySQL 5.6
之后引入了gtid[全局事务号]
,以及multi-thread replcation
[多线程复制];
MySQL 5.5主从服务的配置
master
:
log-bin=master-bin log-bin=master-bin.index
;server-id(0-->2^32)
;REPLICATION SLAVE
[从主服务器中复制事件的权限]以及REPLICATION CLIENT
[连接主服务器的权限];slave
:
relay-log = relay-log relay-log-index
,如果不作为其他slave
的主时,可以关闭二进制日志;server-id(0--->2^32)
;mysql >CHANGE MASTER TO MASTER_HOST=' ',MASTER_PORT=' ',MASTER_LOG_FILE=' ',MASTER_LOG_FILE_POS=' ',MASTER_USER=' ',MASTER_PASSWORD=' ';
mysql >START SLAVE;
mysql > START SLAVE IO_THREAD; mysql > START SLAVE SQL_THREAD;
master
会启动DUMP
线程,来发送改变的二进制日志;
slave
的两个关键进程:
IO thread
会启动主动去master
读取二进制日志Binary log
,如果某些事件是slave
上面没有的,master
会通过DUMP
线程将这些改变发送给IO thread
,slave
的IO thread
线程会接受这些改变,并且保存在中继日志中;SQL thread
会启动,读取中继日志,并且在本地进行重放;支持的多线程复制,也就是支持多个SQL thread
来进行数据的复制;多线程复制对于单个数据库来说,仍然是单个线程的;对于IO thread
来说,如果DUMP
进程宕机或者是master
宕机,IO thread
线程就无法工作,但这这个并不影响SQL thread
的工作,SQL thread
只需要监控中继日志是否发生改变就可以了,所以说在salve
进行了某些配置的改变的时候,只需要重新启动IO thread
这个线程就可以工作了;
MySQL5.5主从复制架构
master: server60.com 172.25.23.100 MySQL 5.5
slave:server14.com 172.25.23.14 MySQL 5.5
master
的配置文件上面启用二进制日志[root@server60 ~]# vim /etc/my.cnf
log-bin=master-bin
log-bin-index=master-bin.index
binlog_format=mixed //不建议使用statement
server-id = 1 //主从服务器一定不能够一样
datadir = /mysql/mydata
innodb_file_per_table = 1
[root@server60 mysql]# /etc/init.d/mysqld start
Starting MySQL... [ OK ]
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'172.25.23.%' IDENTIFIED BY 'replpass';
Query OK, 0 rows affected (0.02 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
slave
上面修改主配置文件relay-log=relay-log
relay-log-index=relay-log.index
server-id = 2
innodb_file_per_table = 1
datadir= /mysql/mydata
[root@server14 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. [ OK ]
Starting MySQL. [ OK ]
mysql> CHANGE MASTER TO MASTER_HOST='172.25.23.100', MASTER_USER='repluser', MASTER_PASSWORD='replpass', MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=1568;
Query OK, 0 rows affected (1.03 sec)
slave
的状态mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 172.25.23.100
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60 //连接尝试时长
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1568
Relay_Log_File: relay-log.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: master-bin.000001
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: 1568
Relay_Log_Space: 107
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 //slave落后的事件
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
1 row in set (0.00 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.03 sec)
slave
状态mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 172.25.23.100
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1568
Relay_Log_File: relay-log.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Connecting
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: 1568
Relay_Log_Space: 107
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
1 row in set (0.00 sec)
mysql> CREATE DATABASE newdb;
Query OK, 1 row affected (0.06 sec)
mysql> FLUSH TABLES WITH READ LOCK;
[root@server14 ~]# vim /etc/my.cnf
read-only = 1
[root@server14 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. [ OK ]
Starting MySQL. [ OK ]
slave
的复制线程mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.25.23.100
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1740
Relay_Log_File: relay-log.000004
Relay_Log_Pos: 254
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: 1740
Relay_Log_Space: 404
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
1 row in set (0.00 sec)
mysql> SHOW GLOBAL VARIABLES LIKE 'read%';
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| read_buffer_size | 1048576 |
| read_only | ON |
| read_rnd_buffer_size | 4194304 |
+----------------------+---------+
master
的信息保存在file /mysql/mydata/master.info
[root@server14 ~]# cat /mysql/mydata/master.info
18
master-bin.000001
1827
172.25.23.100
repluser //用户和密码信息
replpass
3306
60
0
0
1800.000
0
[root@server14 ~]# ll /mysql/mydata/master.info
-rw-rw---- 1 mysql mysql 87 05-15 20:42 /mysql/mydata/master.info
[root@server14 ~]# cat /mysql/mydata/relay-log.info
./relay-log.000004
341
master-bin.000001
1827
master
还是salve
都无法进行读写操作;SUPER
权限的用户是不生效的,读写操作都是正常的;master
出现故障,由于事务日志存在缓冲区,这些信息可能还没有同步到二进制日志中,slave
是无法得到这些事务信息的,可以通过修改服务器变量,使得事务日志在事务执行完成之后,立即提交,而不是停留在缓冲区中;master
上面进行设定,用于事务安全; sync_binlog 0
slave
在某些情况下是不需要开机立即就去master
上面同步数据的,例如master
上面的误删除操作,slave
的开机启动主要是依赖于relay-log.info
以及master.info
,所以可以将这两个文件放到其他位置;mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> START SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)
master
和slave
的半同步操作,这里需要两个插件,在目录/usr/local/mysql/lib/plugin/
里面semisync_slave.so semisync_master.so
ON MASTER
上面进行操作:mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.20 sec)
mysql> SHOW GLOBAL VARIABLES LIKE '%rpl%';
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_no_slave | ON |
+------------------------------------+-------+
5 rows in set (0.00 sec)
slave
上面也是需要装载模块的mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW GLOBAL VARIABLES LIKE '%rpl%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
3 rows in set (0.00 sec)
rpl_semi_sync_master_enabled
,并且可以定义超时时间mysql> SET GLOBAL rpl_semi_sync_master_enabled=1;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW GLOBAL VARIABLES LIKE '%rpl%';
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_no_slave | ON |
+------------------------------------+-------+
5 rows in set (0.00 sec)
slave
上面的mysql> set global rpl_semi_sync_slave_enabled=1;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW GLOBAL VARIABLES LIKE '%rpl%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_recovery_rank | 0 |
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
3 rows in set (0.00 sec)
master
全局状态变量+--------------------------------------------+-------------+
| Variable_name | Value |
+--------------------------------------------+-------------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
| Rpl_status | AUTH_MASTER |
+--------------------------------------------+-------------+
15 rows in set (0.00 sec)
Rpl_semi_sync_master_clients
显示的值为0
;slave
的线程,并且进行重新连接就可以恢复正常mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW GLOBAL STATUS LIKE 'Rpl%';
+--------------------------------------------+-------------+
| Variable_name | Value |
+--------------------------------------------+-------------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
| Rpl_status | AUTH_MASTER |
+--------------------------------------------+-------------+
15 rows in set (0.00 sec)
mysql> USE newdb;
Database changed
mysql> CREATE TABLE tb1(id int);
Query OK, 0 rows affected (0.76 sec)
slave
的IO_THREAD
线程mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE tb3(id int);
Query OK, 0 rows affected (0.04 sec)
[root@server14 ~]# yum localinstall percona-toolkit-2.2.1-2.noarch.rpm -y --nogpgcheck
生成了一堆pt
开头的命令
pt-slave-delay
:有意使slave
慢于master
的,用于在master
上面误操作时,可以进行挽救;这些功能需要自己可以去了解