6.10. Replication FAQ
Q:如果主服务器正在运行并且不想停止主服务器,怎样配置一个从服务器?
A:有多种方法。如果你在某时间点做过主服务器备份并且记录了相应快照的二进制日志名和偏移量
(通过
SHOW MASTER STATUS命令的输出
),采用下面的步骤:
1. 确保从服务器分配了一个唯一的服务器
ID号。
2. 在从服务器上执行下面的语句,为每个选项填入适当的值:
1.
mysql> CHANGE MASTER TO
2.
-> MASTER_HOST='master_host_name',
3.
-> MASTER_USER='master_user_name',
4.
-> MASTER_PASSWORD='master_pass',
5.
-> MASTER_LOG_FILE='recorded_log_file_name',
6.
-> MASTER_LOG_POS=recorded_log_position;
3.
在从服务器上执行
START SLAVE
语句。
如果你没有备份主服务器,这里是一个创建备份的快速程序。所有步骤都应该在主服务器主机上执行。
1. 发出该语句以获得一个全局的读锁定:
mysql> FLUSH TABLES WITH READ LOCK;
2. 在锁起作用时,执行该命令(或它的变体):
shell> tar zcf /tmp/backup.tar.gz /var/lib/mysql
3. 发出该语句并且记录下输出的结果
,烧火会用到:
mysql>SHOW MASTER STATUS;
4. 释放锁:
mysql> UNLOCK TABLES;
一个可选择的方法是,对主服务器做一个
SQL
的
dump
转储来代替前面步骤中的做一个二进制备份。要这样做,你可以在主服务器上使用
mysqldump --master-data
,
以后装载
SQL
转储到到你的从服务器。然而,这比进行二进制复制速度慢。
不管你用的是两种方法中的哪一个
,
之后就依照当你有了快照和记录日志名称及偏移量的情况执行那些指令
.
你可以用一个快照搭建多个从
.
一个但你有了一个主的快照
,
只要主的二进制日志完整你就可以等着创建一个从了
.
你可能等待的时间长短相关的两个实际限制是指在主服务器上保存二进制日志的可用硬盘空间和从服务器同步所用的时间。
Q
:从服务器需要始终连接到主服务器吗?
A
:不,不需要。从服务器可以宕机或断开连接几个小时甚至几天,重新连接后获得更新信息。例如,你可以在通过拨号的链接上设置主服务器
/
从服务器关系,其中只是偶尔短时间内进行连接。这意味着,在任何给定时间,从服务器不能保证与主服务器同步除非你执行某些特殊的方法。
Q
:我怎样知道从服务器与主服务器相比延迟多少
?
换句话说,我怎样知道从服务器复制的最后一个语句的日期?
A:你可以查看
SHOW SLAVE STATUS语句的
Seconds_Behind_Master列的结果。参见
6.3节,“复制实施细节”。
当从服务器
SQL
线程执行从主服务器读取的事件时,它把自己的时间修改为此事件的时间戳
timestamp
(这是
TIMESTAMP
能够很好复制的原因)。在
SHOW PROCESSLIST
语句输出的
Time
列内,为从服务器
SQL
线程显示的秒数是最后一个复制事件的时间戳和从服务器主机的实际时间之间相差的秒数。你可以使用它来确定最后一个复制事件的日期。注意,如果你的从服务器与主服务器连接断开一个小时,然后重新连接,在
SHOW PROCESSLIST
结果中,你可以立即看到从服务器
SQL
线程的
Time
值为
3600
。这是因为从服务器执行的语句是一个一小时之前的。
Q
:我怎样强制主服务器阻塞更新直到从服务器同步?
A:使用下面的步骤:
1. 在主服务器上,执行这些语句:
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
记录
SHOW
语句的输出的日志名和偏移量。这个被成为复制坐标
replication coordinates
(日志名和偏移量)
2. 在从服务器上,发出下面的语句,其中
Master_POS_WAIT()函数的参量是前面步骤中的得到的复制坐标值:
mysql> SELECT MASTER_POS_WAIT('log_name', log_offset);
SELECT
语句阻塞直到从服务器达到指定的日志文件和偏移量。此时,从服务器与主服务器同步,语句返回。
3. 在主服务器上,发出下面的语句允许主服务器重新开始处理更新:
mysql> UNLOCK TABLES;
Q
:当设置双向复制时我应该知道发出那些语句?
A:
MySQL复制目前不支持主服务器和从服务器之间的任何锁定协议来保证分布式
(跨服务器
)更新的原子性。换句话说,这样做是可能的:客户
A根据协作
-主服务器
1更新,同时,在它传给协作
-主服务器
2之前,客户
B能够根据协作
-主服务器
2更新,这样客户
A的更新与它在协作
-主服务器
1的更新不同。这样,当客户
A根据协作
-主服务器
2更新时,它产生的表与在协作
-主服务器
1上的不同,即使所有根据协作
-主服务器
2的更新已经传过来。这意味着,在双向复制关系中,你不应该把两个服务器串连在一起,除非你确信任何顺序的更新是安全的,或者除非你在客户端代码中注意怎样避免更新顺序错误。
你还必须认识到从更新角度,双向复制实际上并不能显著地提高性能(或者根本不能提高性能)。两个服务器都需要做相同数量的更新,如同在一个服务器做的那样。唯一的差别是锁竞争要少,这因为源于另一个服务器的更新在一个从线程中序列化。即使这个益处可能被网络延迟抵消。
Q
:怎样通过复制来提高系统的性能?
A:你应将一个服务器设置为主服务器并且将所有写指向该服务器。然后根据预算配置尽可能多的从服务器以及栈空间,并且在主服务器和从服务器之间分发读取操作。你也可以用
--skip-innodb、
--skip-bdb、
--low-priority-updates以及
--delay-key-write=ALL选项启动从服务器,以便在从服务器端提高速度。在这种情况下,为了通过排除掉事务的花费来提高速度,从服务器使用非事务
MyISAM表来代替
InnoDB和
BDB表。
Q
:为了使用高性能的复制,我应该在自己的应用程序中怎样准备客户端代码?
A:如果你的代码中数据库访问部分已经正确地模块化,应该能够平滑和容易地转换为在复制步骤中运行的代码。仅需要更改数据库访问执行部分,以便发送所有的写操作到主服务器,以及发送读操作到主服务器或某个从服务器。如果你的代码没有这个级别,设置一个复制系统以便清除。应先通过下面的函数创建一个包装库或模块:
・ safe_writer_connect()
・ safe_reader_connect()
・ safe_reader_statement()
・ safe_writer_statement()
每个函数名的
safe_意味着函数比较小心地处理所有错误。你可以使用不同名的函数。重要是对于读连接、写连接、读和写有一个统一的接口。
然后,你应该转换客户端代码使用包装库。刚开始这可能是痛苦和恐慌的过程,但从长远来看是值得的。使用刚才讨论的方法的所有应用程序都能够利用主服务器
/从服务器配置的优越性,即使是含有多个从服务器的配置。代码非常容易维护,并且添加排错选项也很容易。你仅需要修改一两个函数;例如,记录每个语句执行的时间,或者你的上千个语句中哪个语句发生了错误。
如果你已经编写了许多代码,你可能想使用
replace工具自动进行转换,该工具随标准
MySQL一起发布,或可以自己编写转换脚本。理想情况,你的代码使用一致的程序转换风格。否则,可能最好重新编写代码,或者至少手工对其进行规则化以使用一致的风格。
Q:
MySQL复制能够何时和多大程度提高系统性能?
A:
MySQL复制对于频繁读和频繁写的系统具有最大好处。理论上,通过使用单个主服务器
/多从服务器设置,可以通过添加更多的从服务器来扩充系统,直到用完网络带宽,或者你的更新负载已经增长到主服务器不能处理的点。
在获得的收益开始持平之前,为了确定可以有多少从服务器,以及可以将你的站点的性能提高多少,需要知道查询模式,并且要通过基准测试并根据经验确定一个典型的主服务器和从服务器中的读取(每秒钟读取量,或者
max_reads)吞吐量和写(
max_writes)吞吐量的关系。通过一个假设的带有复制的系统,本例给出了一个非常简单的计算结果。
假设系统负载包括
10%的写和
90%的读取,并且我们通过基准测试确定
max_reads是
1200 �C2 × max_writes。换句话说,如果没有写操作,系统每秒可以进行
1,200次读取操作,平均写操作是平均读操作所用时间的两倍,并且关系是线性的。我们假定主服务器和每个从服务器具有相同的性能,并且我们有一个主服务器和
N个从服务器。那么,对于每个服务器(主服务器或从服务器),我们有:
reads = 1200 �C 2 × writes
reads = 9 × writes / (N + 1) (读操作是分离的
, 但是写操作会写到所有的服务器
)
9 × writes / (N + 1) + 2 × writes = 1200
writes = 1200 / (2 + 9/(N+1))
最后的等式表明了
N个从服务器的最大写操作数,假设最大可能的读取速率是每分钟
1,200次,读操作与写操作的比率是
9。
如上分析可以得到下面的结论:
・ 如果
N
= 0(这表明没有复制),系统每秒可以处理大约
1200/11 = 109个写操作。
・ 如果
N
= 1,每秒得到
184个写操作。
・ 如果
N
= 8,每秒得到
400个写操作。
・ 如果
N
= 17,每秒得到
480个写操作。
・ 最后,当
N
趋于无穷大(以及我们预算的负无穷大)时,可以得到非常接近每秒
600个写操作,系统吞吐量增加将近
5.5倍。然而,如果只用
8个服务器,增加接近
4倍。
请注意,这些计算假设网络带宽无穷大并忽略掉了其它一些因素,那些因素可能对系统产生重要的影响。在许多情况下,不能执行与刚才类似的计算,即如果添加
N台复制从服务器,应该准确预报系统将发生哪些影响。回答下面的问题应能够帮助你确定复制是否和在多大程度上能够提高系统的性能:
・ 系统上的读取
/写比例是什么
?
・ 如果减少读取操作,一个服务器可以多处理多少写负载?
・ 网络带宽可满足多少从服务器的需求
?
Q:如何使用复制来提供冗余
/高可用性
?
A:利用目前的可用特性,必须设置一个主服务器和一个从服务器(或多个从服务器),以及写一个脚本来监视主服务器是否启动。如果主服务器失败,通知应用程序和从服务器切换主服务器。下面是一些建议:
・
告知从服务器更改其主服务器,使用
CHANGE MASTER TO
语句。
・
通知应用程序主服务器位置的一个很好的方法是对主服务器提供动态
DNS
入口。用
bind
可以使用
nsupdate
动态更新
DNS
。
・ 应该用
--logs-bin选项而不用
--logs-slave-updates选项运行从服务器。这样,一旦你在其它从服务器上发出
STOP SLAVE; RESET MASTER, 以及
CHANGE MASTER TO语句,该从服务器可以切换为主服务器。例如,假设有下面的设置:
・ WC
・ \
・ v
・ WC----> M
・ / | \
・ / | \
・ v v v
・ S1 S2 S3
M
代表主服务器,
S
代表从服务器,
WC
代表发出数据库写和读取操作的客户;只发出数据库读取操作的客户没有给出,因为它们不需要切换。
S1
、S2
以及
S3
是从服务器,用
--logs-bin
选项而没有用
--logs-slave-updates
运行。因为从服务器收到的主服务器的更新没有记录在二进制日志中,除非指定
--logs-slave-updates
选项
,
初始时每个从服务器上的二进制日志是空的。如果因为某些原因
M
变得不可用,你可以选取一个从服务器变为新的主服务器。例如
,
如果你选择了
S1,
所有的
WC
应该重新指向到
S1,S1
就将会将所有的更新写入二进制日志
.S2
和
S3
接着就能从
S1
上复制了
.
不带
--log-slave-updates
参数运行从服务器的原因是为了避免当你使一个从成为新的主时从服务器会收到两次更新.架设S1启动带有--log-slave-updates选项,它就会把从M那里收到的更新都写入自己的二进制日志中.当S2把主从M切换到S1之后,它可能会从S1那里收到它之前已经从M那里得到的更新.
确保所有从服务器已经处理了中继日志中的所有语句。在每个从服务器上,发出
STOP SLAVE IO_THREAD
语句,然后检查
SHOW PROCESSLIST
语句的输出,直到你看到
Has read all relay log
。当所有从服务器都执行完这些,它们可以被重新配置为一个新的设置。在被提升为主服务器的从服务器
S1
上,发出
STOP SLAVE
和
RESET MASTER
语句。
在其它从服务器
S2
和
S3
上
,使用
STOP SLAVE
和
CHANGE MASTER TO MASTER_HOST='S1'
(其中
'S1'
表示
S1
实际的主机名)。为
CHANGE MASTER
添加关于如何从
S2
或
S3
连接到
S1
的
所有信息(
user
、
password
、
port
)。在
CHANGE MASTER
命令中,不需要指定从其读取的
S1
的二进制日志名或二进制日志位置:我们知道它是第
1
个二进制日志,位置是
4
,这是
CHANGE MASTER
命令的默认值。最后,在
S2
和
S3
上
使用
START SLAVE
命令。
然后,指示所有
WC
把它们的语句指向
S1
。此后,
WC发出的所有发送到
S1
的更新语句被写入
S1
的二进制日志,
S1则包含
M死掉之后的发送到
S1的每一个更新语句。
结果是下面的配置:
WC
/
|
WC | M(unavailable)
\ |
\ |
v v
S1<--S2 S3
^ |
+-------+
当
M
重新启动后,你必须在
M
上
发出相同的
CHANGE MASTER
语句,与在
S2
和
S3
上发出的语句一样,以便
M
变为
S1
的
从服务器并且恢复在它宕机后丢失的所有
WC
写操作。要把
M
再次作为主服务器(例如,因为它是功能最强的机器),使用前面的步骤,好像
S1
不可用并且
M
变为一个新的主服务器一样。在这个过程中,在
S1
、S2
以及
S3
作为
M
的
从服务器之前,不要忘记在
M
上
运行
RESET MASTER
。否则,它们可能拾取
M
变得不可用之前的旧
WC
写操作。
注意
:
在一个主的多个从之间是没有同步的
.
一些从可能会超前另一些
.
这意味着之前例子中的概念可能不能工作
.
尽管如此
,
实际中
,
不同的从的中继日志大都不会落后主很多
,
因此运行没问题的
.(
但是没有保证
)
Q
:怎么阻止
GRANT
和
REVOKE
语句复制到从
?
A
:启动服务器的时候带
--replicate-wild-ignore-table=mysql.%
参数
Q:
在多种操作系统下复制能工作吗?(例如,主运行在linux上,而从运行在Mac OS X和Windows上)?
A:
可以
Q:
在多种硬件平台下复制能工作吗
?(
例如
,
主运行在
64
位的机器上而从运行在
32
位的机器上
)?
A:
可以
6.11. 复制故障诊断与排除
如果你遵从了上述说明,复制设置仍然不工作,首先
检查错误日志的消息。许多用户遇到问题后没有及时地这样做而浪费了时间。
如果你从错误日志中不能判断问题出在哪里的话
,试试以下的技巧
:
・ 用
SHOW MASTER STATUS检查主服务器是否记录到了二进制日志。如果已经记录,
Position应为非零。如果没有记录,确认正用
log-bin和
server-id选项运行主服务器
・
是否从服务器在运行?使用
SHOWSHOW SLAVE STATUS
检查是否
slave_IO_Running
和
slave_SQL_Running
的值均为
Yes
。如果不是,验证当启动从服务器时使用的选项。例如
,
--skip-slave-start
会阻止从线程启动直到你发出START SLAVE语句.
・
如果从服务器正在运行,建立了与主服务器的连接吗?使用
SHOW PROCESSLIST
,找出
I/O
和
SQL
线程并检查它们的
State
列所显示的内容。参见
6.3节,“复制实施细节”
。如果
I/O
线程状态为
Connecting to master
,验证主服务器上复制用户的权限、主服务器主机名、
DNS
设置,是否主服务器真正在运行,以及是否可以从从属服务器访问。
・
如果从服务器以前在运行但是现在已经停止,原因通常是一些语句在主服务器上成功而在从服务器上失败了。如果你正确快照了主服务器,并且从来没有不通过服务器线程修改从服务器上的数据,这种现象不应发生。如果发生,应为一个
bug
或你遇到了一个
6.7节,“复制特性和已知问题”
描述的已知的复制限制。如果是一个
bug
,参见
6.12节,“通报复制缺陷”
查阅如何通报的说明。
・ 如果某个在主服务器上成功的语句拒绝在从服务器上运行,并且不能执行完全的数据库重新同步
(即删除从服务器的数据库并从主服务器复制新的快照
),尝试:
1.
确定是否从服务器的表与主服务器的不同。尽力了解发生的原因。然后让从服务器的表与主服务器的一样并运行
START SLAVE
。
2. 如果前面的步骤不工作或不适合,尽力了解手动更新是否安全
(如果需要
),然后忽视来自主服务器的下一个语句。
3. 如果你确定可以跳过来自主服务器的下一个语句,执行下面的语句:
mysql> SET GLOBAL SQL_slave_SKIP_COUNTER = n;
mysql> START SLAVE;
如果来自主服务器的下一个语句不使用
AUTO_INCREMENT
或
LAST_INSERT_ID()
,
n
值应为
1
。否则,值应为
2
。使用
AUTO_INCREMENT
或
LAST_INSERT_ID()
的语句使用值
2
的原因是它们从主服务器的二进制日志中取两个事件。
4. 如果你确保从服务器启动时完好地与主服务器同步,并且没有通过从服务器线程之外的手段更新表,则大概诧异是由于
bug。如果你正运行最近的版本,请通报该问题。如果你正运行旧版本
MySQL,尽力升级到最新的产品版本。
6.12.
通报复制缺陷
6.13
多主服务器复制中的
Auto-Increment
当有多个服务器被配置为主服务器时
,
必须采取一些特殊的步骤来避免运用
AUTO_INCREMENT
列时出现键
(key)
冲突
,
否则在多个主插入行时可能会用同一个
AUTO_INCREMENT
值
.
服务器变量
auto_increment_increment和
auto_increment_offset可以帮助协调多主服务器带
AUTO_INCREMENT列的复制。每个变量有一个默认的
(并且是最小的
)值
1,最大值为
65,535。它们在
5.0.2中被引入
.
这两个变量这样影响
AUTO_INCREMENT列:
l
auto_increment_increment控制连续的
AUTO_INCREMENT值增加的间隔。
l
auto_increment_offset
确定
AUTO_INCREMENT
列值的起点。
通过在不同的主上面选择这些变量的不冲突的值
,
在一个多主配置中的服务器在向一个相同表插入新行时就不会用冲突的
AUTO_INCREMENT
值
.
要配置
N
个主服务器
,
就像下面这样设置变量
:
l
在每个主上面将
auto_increment_increment
设为N
l
将每个主的
auto_increment_offset
设为一个不同的值,用1,2,…N
关于 auto_increment_increment 和 auto_increment_offset的更多信息查看, see Section 5.2.3, “System Variables”.
(全文完)