在Soundbreak我们每天24小时不间断地播放实况音频和视频,所以对于MySQL的新增 
的复制特性,我们 
不能做出很令人信服的测试。通过测试我们发现,可以使用这个特性来与备份数据库服 
务器保持数据同步, 
这样当主服务器因为某种原因处理失效时,能够使用备份机处理所有的查询。对于这样 
的要求,配置两台服 
务器并不困难。我将详细讨论整个处理过程,同时讨论一下当主服务器失效时,如何使 
用PHP来重定向查询。 
  MySQL内部复制功能是建立在两个或两个以上服务器之间,通过设定它们之间的主- 
从关系来实现的。其 
中一个作为主服务器,其它的作为从服务器。我将详细讨论如何配置两台服务器,将一 
个设为主服务器,另 
一个设为从服务器。并且描述一下在它们之间进行切换的处理过程。我是在MySQL的3.2 
3.23版本上进行的配 
置设置过程,并且也是在这个版本上进行的测试。MySQL开发人员建议最好使用最新版本 
,并且主-从服务器 
均使用相同的版本。同时MySQL 3.23版本仍然是beta测试版,而且这个版本可能不能向 
下兼容。所以因为这 
个原因,在实际的网站中,我现在还没有使用这个版本。拥有容错能力具有一个好处是 
,在不需中断任何查 
询的情况下,对服务器进行升级。 
第一步:配置主服务器 
  在这篇文章的剩下篇幅中,我将指定两台服务器。A(IP为10.1.1.1)作为主服务器 
(简称为主机)。B 
(IP为10.1.1.2)作为后备服务器(简称为备机)。 
  MySQL的复制功能的实现过程为:备机(B)与主机(A)连接,然后读出主机的二进制更 
新日志,再将发生 
的变化合并到自已的数据库中。备机需要一个用户帐号来与主机连接,所以在主机上创 
建一个帐号,并只给 
它FILE权限,如下操作: 
GRANT FILE ON *.* TO [email protected] IDENTIFIED BY 'password'; 
  为了备机能够与主机连接,要在主机上运行'FLUSH PRIVILEGES',不过不要担心, 
因为我们将在下面的 
步骤中停掉服务器。 
  现在我们需要主机数据库的一个快照,并且对主机进行配置,允许生成二进制的更 
新日志。首先编辑 
'my.cnf'文件,以便允许二进制更新日志,所以在[mysqld]部分的下面某个地方增加一 
行:'log-bin'。在 
下一次服务器启动时,主机将生成二进制更新日志(名为:<主机名>-bin.<增量序号#>) 
。为了让二进制更新 
日志有效,关闭MySQL服务程序,然后将主机上的所有数据库目录到另一个目录中,接着 
重新启动mysqld。 
请确定得到了所有数据库,否则在进行复制时,如果一个表在主机上存在但在备机上不 
存在,将因为出错而 
退出。现在你已经得到了数据的快照,和一个从建立快照以来的二进制日志,上面记录 
着任何对数据库的修 
改。请注意MySQL数据文件(*.MYD,*.MYI和*.frm)是依赖于文件系统的,所以你不能仅 
仅进行文件传输,如 
从Solaris到Linux。如果你处于一个异种的服务器环境,你将不得不使用mysqldump实用 
程序或其它的定制 
脚本来得到数据快照。 
第二步:配置备机 
  让我们继续。停掉备机上的MySQL服务程序,并且把从主机上拷贝来的数据库目录移 
到备机上的data目 
录下。请确认将目录的拥有者和属组改变为MySQL用户相应值,并且修改文件模式为660 
(只对拥有者和属组 
可读、可写),目录本身为770(只对拥有者和属组可读、可写和可执行)。 
  继续。在备机上启动MySQL服务程序,确认MySQL工作正常。运行几个select查询(不 
要update或insert 
查询),看一看在第一步中得到的数据快照是否成功。接着,在测试成功后关掉MySQL服 
务程序。 
  在备机上配置需要访问的主机,以便接收主机的更改。所以需要编辑务机上的'my. 
cnf'文件,在[mysqld] 
部分中增加下面几行: 
master-host=10.1.1.1 
master-user=replicate 
master-password=password 
  在启动备机服务程序后,备机服务程序将查看在'my.cnf'文件中所指定的主机,查 
看是否有改变,并且 
将这些改变合并到自已的数据库中。备机保持了主机的更新记录,这些记录是从主机的 
'master.info'文件中 
接收下来的。备机线程的状态可以通过sql命令'SHOW SLAVE-STATUS'看到。在备机上处 
理二进制日志中如果 
发生错误,都将导致备机线程的退出,并且在*.err的日志文件中生成一条信息。然后错 
误可以被改正,接着 
可以使用sql语句'SLAVE START'来重新启动备机线程。线程将从主机二进制日志处理中 
断的地方继续处理。 
  至此,在主机上所发生的数据改变应该已经复制到备机上了,要测试它,你可以在 
主机上插入或更新一 
条记录,而在备机上选择这条记录。 
  现在我们拥有了从A机到B机的这种主-从关系,这样当A机可能当机的时候,允许我 
们将所有的查询重定 
向到B机上去,但是当A机恢复时,我们没有办法将发生的改变恢复到A机中去。为了解决 
这个问题,我们创建 
从B机到A机的主-从关系。 
第三步:创建相互的主从关系 
  首先在B机上的my.cnf文件中,在[mysqld]部分中加入'log-bin',接着重新启动my 
sqld,然后创建可在 
它的上面执行复制功能的用户帐号,使用: 
GRANT FILE ON *.* TO [email protected] IDENTIFIED BY 'password'; 
  在B机上运行'FLUSH PRIVILEGES'命令,以便装入在加入复制用户后的新的授权表, 
接着回到A机上,在 
它的'my.cnf'中加入下面几行: 
master-host=10.1.1.2 
master-user=replicate 
master-password=password 
  在重启A机的服务程序之后,现在我们一拥有了在A机与B机之间的相互主-从关系。 
不管在哪个服务器上 
更新一条记录或插入一条记录,都将被复制到另一台服务器上。要注意的是:我不敢确 
定一个备机合并二进 
制日志变化的速度有多快,所以用这种方法来进行插入或更新语句的负载平衡可能不是 
一个好办法。 
第四步:修改你的数据库连接程序 
  既然你已经在A机和B机之间建立了一个相互的关系,你需要修改数据库连接程序, 
以便从这种方式中得 
到好处。下面的函数首先试图与A机连接,如果不能建立连接则与B机连接。 
/******************************************************** 
function db_connect() 
returns a link identifier on success, or false on error 
********************************************************/ 
function db_connect(){ 
$username = "replUser"; 
$password = "password"; 
$primary = "10.1.1.1"; 
$backup = "10.1.1.2"; 
# attempt connection to primary 
if(!$link_id = @mysql_connect($primary, $username, $password)) 
# attempt connection to secondary 
$link_id = @mysql_connect($secondary, $username, $password) 
return $link_id; 

?> 
  我在两种情况下对使用了上面技术的数据库连接建立过程进行了测试,一种是主My 
SQL服务程序关闭了, 
但是服务器还在运行,另一种情况是主服务器关闭了。如果只是mysqld关闭了,连接会 
马上转向备机;但是 
如果整个服务器关闭了,就出现了无限地等待(两分钟后我放弃了跟踪 -- 很短的注意跨 
度),因为PHP在查 
找一个不存在的服务器。不幸地是,不象fsockopen函数,mysql_connect函数没有一个 
超时参数,然而我们 
可以使用fsockopen来模拟一个超时处理。 
第五步:一个改进的数据库连接程序 
/******************************************************** 
function db_connect_plus() 
returns a link identifier on success, or false on error 
********************************************************/ 
function db_connect_plus(){ 
$username = "username"; 
$password = "password"; 
$primary = "10.1.1.1"; 
$backup = "10.1.1.2"; 
$timeout = 15; // timeout in seconds 
if($fp = fsockopen($primary, 3306, &$errno, &$errstr, $timeout)){ 
fclose($fp); 
return $link = mysql_connect($primary, $username, $password); 

if($fp = fsockopen($secondary, 3306, &$errno, &$errstr, $timeout)){ 
fclose($fp); 
return $link = mysql_connect($secondary, $username, $password); 

return 0; 

?> 
  这个新改进的函数向我们提供了一个可调的超时特性,这正是mysql_connect函数所 
缺少的。如果连接 
立即失败,这种情况如机器"活"着,但mysqld"当"掉了,函数立即移到第二个服务器。 
上面的函数相当健壮, 
在试图进行连接之前先测试一下,查看服务程序是否在指定端口进行监听,让你的脚本 
在一段可接受的时间 
段后超时,允许你适当地对出错情况进行处理。如果你修改了缺省端口3306,请保证对 
端口号进行修改。 
结论和意见 
  首先,要确定得到了一个完整的数据快照。如果忘记拷贝一个表或数据库将导致备 
机线程序停止。生成 
快照的时刻是很关健的。你应该确保在拷贝数据文件之前二进制日志功能是无效的。如 
果在得到快照之前就 
允许了二进制日志功能,备机的线程可能会停止,原因就是当线程试图导入重要的记录 
时,可能会由于主键 
重复而停止。最好就是接照第二部分所讨论的处理办法来做:关闭-拷贝-允许二进制日 
志功能重启。 
  你可能想要按照最初的一种方式来配制复制处理,并且在合适的时间关注备机,确 
保备机与主机保持同 
步。 
  我没有测试过一个使用了复制特性的系统的负载平衡处理性能,但是我会灵活地使 
用这样系统来平衡插 
入和更新。例如,如果在两台服务器上两条记录都给出了同一个auto_increment值,这 
种情况备机线程会在 
哪一条记录上停掉呢?象这样的问题将会让负载平衡作为只读的处理,一台服务器处理 
所有的插入和更新, 
同时一组备机(是的,你可以有多个与主机分离的备机)处理所有的选择。 
  我非常高兴,MySQL已经具备了复制系统的某些功能,并且配置很简单。使用它,你 

解决方案 »

  1.   

    谢谢,我虽然看了MYSQL的文档中的这一部分,但是没有中文看起来容易,很感谢你提供的示例程序。对了,怎么加分呀?我刚才在管理中给你加分,但是看起来好像没加上。
      

  2.   

    webmin:你好!   
        我在两台Sun ultra60(双CPU,1G内存,Solaris2.6)上安装了MySQL-4.0.1-alpha,安装完后,没发现有“my.cnf”文件,只在share/mysql下发现有my-***.cnf文件,我将其中一个改名为“my.cnf”后启动数据库(mysqld_safe &),然后对从数据库也做了修改,2个数据库的库和表的结构完全一样,我对主数据库进行插入操作,但是没发现有日志产生,从数据库也没发生变化,不知是何原因?另外,文中提到的运行“FLUSH PRIVILEFES”该如何做?
        谢谢!
      

  3.   

    不要用mysql-4.0.1他不是稳定版本请用3.23.xx你要打开--log-bin才有日志。./mysql -uroot >FLUSH PRIVILEFES;或者用mysqladmin
      

  4.   

    不好意思,麻烦你们了。
    在看到你的说明后,我今天抽空试了一下,直接运行mysql安装目录/libexec/mysqld启动数据库(以前是运行bin/safe_mysqld启动数据库),增加参数“--log-bin=mysql安装目录/man/主机名-bin.log”,操作数据库后生成了2个文件:主机名-bin.001,主机名-bin.index.在mysql>show slave status;显示Slave_Running为No,在mysql>slave start;出现“ERROR 1200: The server is not configured as slave, fix in config file or with CHANGE MASTER TO”,在mysql>change master to Master_Host='192.168.1.125', Master_User='root', MASTER_PASSWORD='mysql', MASTER_PORT=3306,MASTER_LOG_FILE='ultra64-bin.001', MASTER_LOG_POS=4;后,输入slave start出现的错误信息同上。在我安装的mysql中没有my.cnf,我将share/mysql/my-*.cnf 改名成my.cnf,然后修改里面的设置,不知这样有没有问题?在主数据库操作,从数据库没有任何变化,不知适合原因?请指教,谢谢!
      

  5.   

    上面的主数据库的IP地址:192.168.1.125,主机名:ultra64.