故障
问题:主从复制不止何故停止了,我该怎么办?
答案:复制错误多半是因为日志错误引起的,所以首先要搞清楚是主日志错误还是中继日志错误,从错误信息里一般就能判断,如果不能可以使用类似下面的mysqlbinlog命令:
shell> mysqlbinlog <MASTER_BINLOG_FILE> > /dev/null
shell> mysqlbinlog <SLAVE_BINLOG_FILE> > /dev/null
如果没有错误,则不会有任何输出,反之如果有错误,则会显示出来。
如果是主日志错误,则需要在从服务器使用SET GLOBAL sql_slave_skip_counter,如下:
mysql> SET GLOBAL sql_slave_skip_counter = 1;
mysql> START SLAVE;
注:如果有多个错误,可能需要执行多次(提醒:主从服务器数据可能因此不一致)。
如果是中继日志错误,只要在从服务器使用SHOW SLAVE STATUS结果中的日志信息重新CHANGE MASTER TO即可,系统会抛弃当前的中继日志,重新下载:
mysql> CHANGE MASTER TO
MASTER_LOG_FILE='<Relay_Master_Log_File>',
MASTER_LOG_POS=<Exec_Master_Log_Pos>;
mysql> START SLAVE;
至于为什么使用的是Relay_Master_Log_File & Exec_Master_Log_Pos,参见概述。
问题:主服务器宕机了,如何把从服务器提升会主服务器?
答案:在一主多从的环境总,需选择数据最新的从服务器做新的主服务器。如下图所示:
提升从服务器为主服务器
在一主(Server1)两从(Server2,、Server3)的环境中,Server1宕机后,等到Server1和Server2把宕机前同步到的日志都执行完,比较Master_Log_File和Read_Master_Log_Pos就可以判断出谁快谁慢,因为Server2从 Server1同步的数据(1582)比Server3从Server1同步的数据(1493)新,所以应该提升Server2为新的主服务器,那么 Server3在CHANGE MASTER TO到Server2的时候应该使用什么样的参数呢?1582-1493=89,而Server2的最后的二进制日志位置是8167,所以答案是 8167-89=8078。
技巧
主从服务器中的表可以使用不同的表类型。比如主服务器可以使用InnoDB表类型,提供事务,行锁等高级特性,从服务器可以使用MyISAM表类型,内存消耗少,易备份等优点。还有一个例子,一台主服务器如果同时带很多个从服务器的话,势必会影响其性能,此时可以拿出一台服务器作为从服务器代理,使用BLACKHOLE表类型,只记录日志,不写数据,由它带多台从服务器,从而提升性能。
主从服务器中的表可以使用不同的键类型。比如主服务器用InnoDB,键用VARCHAR的话节省空间,从服务器使用MyISAM,键用CHAR提高速度,因为MyISAM有静态表一说。
主从服务器中的表可以使用不同的索引。主服务器主要用来应付写操作,所以除了主键和唯一索引等保证数据关系的索引一般都可以不加,从服务器一般用来应付读操作,所以可以针对查询特征设置索引,再进一步,不同的从服务器可以针对不同的查询设置不同的索引。
MySQL同步功能由3个线程(master上1个,slave上2个)来实现。执行 DE>START SLAVEDE> 语句后,slave就创建一个I/O线程。I/O线程连接到master上,并请求master发送二进制日志中的语句。master创建一个线程来把日志的内容发送到slave上。这个线程在master上执行 DE>SHOW PROCESSLISTDE> 语句后的结果中的 DE>Binlog DumpDE> 线程便是。slave上的I/O线程读取master的 DE>Binlog DumpDE> 线程发送的语句,并且把它们拷贝到其数据目录下的中继日志(relay logs)中。第三个是SQL线程,salve用它来读取中继日志,然后执行它们来更新数据。
如上所述,每个master/slave上都有3个线程。每个master上有多个线程,它为每个slave连接都创建一个线程,每个slave只有I/O和SQL线程。
show slave master 用于提供有关从属服务器线程的关键参数的信息
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.2.40
Master_User: photorepl
Master_Port: 4331
Connect_Retry: 60
Master_Log_File: mysql-bin.005502
Read_Master_Log_Pos: 64401238
Relay_Log_File: mysqld-relay-bin.015418
Relay_Log_Pos: 13456757
Relay_Master_Log_File: mysql-bin.005152
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB: mysql
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table: photo.%
Replicate_Wild_Ignore_Table: mysql.%
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 13456620
Relay_Log_Space: 36764898503
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: 249904
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
SHOW SLAVE STATUS会返回以下字段:
? Slave_IO_State
SHOW PROCESSLIST输出的State字段的拷贝。SHOW PROCESSLIST用于从属I/O线程。如果线程正在试图连接到主服务器,正在等待来自主服务器的时间或正在连接到主服务器等,本语句会通知您
? Master_User
被用于连接主服务器的当前用户。
? Master_Port
当前的主服务器接口。
? Connect_Retry
–master-connect-retry选项的当前值
? Master_Log_File
I/O线程当前正在读取的主服务器二进制日志文件的名称。
? Read_Master_Log_Pos
在当前的主服务器二进制日志中,I/O线程已经读取的位置。
? Relay_Log_File
SQL线程当前正在读取和执行的中继日志文件的名称。
? Relay_Log_Pos
在当前的中继日志中,SQL线程已读取和执行的位置。
? Relay_Master_Log_File
由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称。
? Slave_IO_Running
I/O线程是否被启动并成功地连接到主服务器上。
? Slave_SQL_Running
SQL线程是否被启动。
? Replicate_Do_DB,Replicate_Ignore_DB
使用–replicate-do-db和–replicate-ignore-db选项指定的数据库清单。
? Replicate_Do_Table,Replicate_Ignore_Table,Replicate_Wild_Do_Table,Replicate_Wild_Ignore_Table
使用–replicate-do-table,–replicate-ignore-table,–replicate-wild-do-table和–replicate-wild-ignore_table选项指定的表清单。
? Last_Errno,Last_Error
被多数最近被执行的查询返回的错误数量和错误消息。错误数量为0并且消息为空字符串意味着“没有错误”。如果Last_Error值不是空值,它也会在从属服务器的错误日志中作为消息显示。
举例说明:
Last_Errno: 1051
Last_Error: error ‘Unknown table ‘z” on query ‘drop table z’
该消息指示,表z曾经存在于在主服务器中并已被取消了,但是它没有在从属服务器中存在过,因此对于从属服务器,DROP TABLE失败。(举例说明,在设置复制时,如果您忘记了把此表拷贝到从属服务器中,则这有可能发生。)
? Skip_Counter
最近被使用的用于SQL_SLAVE_SKIP_COUNTER的值。
? Exec_Master_Log_Pos
来自主服务器的二进制日志的由SQL线程执行的上一个时间的位置(Relay_Master_Log_File)。在主服务器的二进制日志中的(Relay_Master_Log_File, Exec_Master_Log_Pos)对应于在中继日志中的(Relay_Log_File,Relay_Log_Pos)。
? Relay_Log_Space
所有原有的中继日志结合起来的总大小。
? Until_Condition,Until_Log_File,Until_Log_Pos
在START SLAVE语句的UNTIL子句中指定的值。
Until_Condition具有以下值:
o 如果没有指定UNTIL子句,则没有值
o 如果从属服务器正在读取,直到达到主服务器的二进制日志的给定位置为止,则值为Master
o 如果从属服务器正在读取,直到达到其中继日志的给定位置为止,则值为Relay
Until_Log_File和Until_Log_Pos用于指示日志文件名和位置值。日志文件名和位置值定义了SQL线程在哪个点中止执行。
? Master_SSL_Allowed,Master_SSL_CA_File,Master_SSL_CA_Path,Master_SSL_Cert,Master_SSL_Cipher,Master_SSL_Key
这些字段显示了被从属服务器使用的参数。这些参数用于连接主服务器。
Master_SSL_Allowed具有以下值:
o 如果允许对主服务器进行SSL连接,则值为Yes
o 如果不允许对主服务器进行SSL连接,则值为No
o 如果允许SSL连接,但是从属服务器没有让SSL支持被启用,则值为Ignored。
与SSL有关的字段的值对应于–master-ca,–master-capath,–master-cert,–master-cipher和–master-key选项
########################################################################
Replication延时的类型
1、固定性的延时
——Slave的数据持续性的落后于Master并且一直无法与Master的数据保持一致。
——Slave的数据经常在白天落后于Master,而在晚上可以赶上并与Master的记录保持一致。
这种类型的延时通常是由于Slave服务器的负载已经到达了上限或在白天访问量大的时候到达上限造成的。
2、非固定性的延时
——Slave的数据只是短暂的落后于Master,可在短时间内恢复,这类型的延时通常与批量任务和报表有关,效率差的查询也会导致这类延时。
Mysql Replication的限制
Mysql的Replication是单线程的,意味着只能有效的使用一个CPU内核和一个磁盘,一条复杂的查询或者事务都导致进程被阻塞,不过现在针对5.1版本的多线程Replication补丁,http://forge.mysql.com/wiki/ReplicationFeatures/ParallelSlave,还是pre版,有很多限制,感兴趣的可以去看看。
Replication的容量
1、理解什么是Replication的容量
可以将Replication暂停一个小时,重新启动Replication后,观察Slave的数据多久可以与Master一致。从Replication重新启动到和Master数据一致所花费的时间与Replication暂停的时间的比值就是Replication的容量。
2、建议保持Replication的容量在3倍以上,即延迟一个小时的数据,Slave只需要20分钟就能与Master的数据一致。
Replication的优化
1、5.0的mysql中避免类似以下的更新语句
INSERT … SELECT
UPDATE .... WHERE
复杂的查询会导致Replication线程阻塞。如果是insert或update与select结合的语句,可以讲select单独执行并保存在临时表中,然后再执行insert或者update。
如果使用的是5.1的mysql,新功能中的行级Replication(RBR)可以解决这个问题。RBR可以将在Master上通过复杂查询后更新的结果直接传给Slave,Slave可以直接将结果更新到数据库中。
2、避免大的事务
太大的事务会造成Replication长时间阻塞,数据会严重滞后于Master。
Slave服务器的硬件选择
更快的CPU内核,对于单线程的Replication多核CPU是没有任何优势的。更高速的硬盘,包括更高的转速和更好的高速缓存命中率,如果有钱的话上SSD吧。
主从结构的扩展性问题
1、如何降低写操作的频率
Master的写操作会扩散到所有的Slave上,所以高频率的写操作会降低Slave的读操作效率。
至少保持一台Slave做全库同步,其他的Slave可以只做部分表的同步。当然,这需要web应用程序的配合来分配哪些查询读哪些Slave。将一些更新操作放到memcached中,例如session和计数器。Slave使用myisam引擎,将一些写入量很大的更新操作直接在slave上执行,而不通过Replication。
2、如何更有效的利用Slave的硬件资源[ 变形虫]
使用分区
有选择的对表进行同步
在Slave上对数据进行归档。
Session的持久化
为不同的应用服务器分配不同的Slave进行读操作。
或者根据查询类型的不同来分配不同的Slave。
3、如何使你的程序最大化的利用Slave
将对数据更新不敏感的查询放到Slave上,而需要实时数据的查询则放到Master。通过session的持久化,让做了修改的用户首先看到修改的内容,其他的用户可以等待Slave更新后再查看新内容。
对于某些数据,可以用memcached来存放数据的版本号,读Slave的程序可以先对比Slave的数据和memcached数据的版本,如果不一致则去读master。用户和博客类的信息可以用这种方法。在查询前可以通过SHOW SLAVE STATUS检测Slave的状态,然后根据返回的结果进行服务器的选择。