全部博文(2065)
分类: Mysql/postgreSQL
2009-03-04 12:57:58
为什么使用主从复制?
1、主服务器/从服务器设置增加了健壮性。主服务器出现问题时,你可以切换到从服务器作为备份。
2、通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间。但是不要同时在主从服务器上进行更新,这样可能引起冲突。
3、使用复制的另一个好处是可以使用一个从服务器执行备份,而不会干扰主服务器。在备份过程中主服务器可以继续处理更新。
MySQL数据库支持数据库的主从复制功能,使用主数据库进行数据的插入、删除与更新操作,而从数据库则专门用来进行数据库查询,这样就可以将更新操作与查询操作分离到不同的数据库上,从而提高查询的效率。2)监控从数据库服务器的状态
我们可以通过show slave status来查看从数据库服务器的状态,它的基本输出如下:
+----------------------------------+---------------+-------------+-------------+---------------+------------------+---------------------+-----------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
|
Slave_IO_State | Master_Host | Master_User |
Master_Port | Connect_Retry | Master_Log_File | Read_Master_Log_Pos |
Relay_Log_File | Relay_Log_Pos | Relay_Master_Log_File |
Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB |
Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table |
Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno |
Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space |
Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed |
Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert |
Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master |
+----------------------------------+---------------+-------------+-------------+---------------+------------------+---------------------+-----------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
| Waiting for master to send event | 172.16.11.221 | repuser | 3306 | 60 | mysql-bin.000003 | 370558 |
WEB2-relay-bin.000206 | 12251 | mysql-bin.000003 |
Yes | Yes |
| | |
| | | 0
| | 0 | 370558 | 12251 |
None | | 0 | No
| | |
| | | 0 |
+----------------------------------+---------------+-------------+-------------+---------------+------------------+---------------------+-----------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
1 row in set (0.00 sec)
我们看到红色的部分,分别表示的是Master_Log_File和Read_Master_Log_Pos,即主数据库服务器上的日志文件和要读取的主
数据库服务器上的日志的位置,通常这个Read_Master_Log_Pos是和主数据库服务器上的Position是一致的,当然这个是指同步以后
的,如果从数据库服务器还没有同步完毕,那么这个值通常比主数据库服务器上的要小。
如果从数据库服务器在同步的过程中出现了问题,那么我们可以通过reset slave来重置从数据库服务器的复制线程,从数据库服务器上的通常操作命令有:
Slave start; --启动复制线程
Slave stop; --停止复制线程
Reset slave; --重置复制线程
Show slave status; --显示复制线程的状态
Change master to; --动态改变到主数据库的配置
++修改配置需要注意
需要删除从服务器上的/var/lib/mysql/master.info文件
++主服务器上的相关命令
show master status
show slave hosts
show logs
show binlog events
purge logs to ‘log_name’
purge logs before ‘date’
reset master(老版本flush master)
set sql_log_bin=
++从服务器上的相关命令
slave start
slave stop
SLAVE STOP IO_THREAD //此线程把master段的日志写到本地
SLAVE start IO_THREAD
SLAVE STOP SQL_THREAD //此线程把写到本地的日志应用于数据库
SLAVE start SQL_THREAD
reset slave
SET GLOBAL SQL_SLAVE_SKIP_COUNTER
load data from master
show slave status(SUPER,REPLICATION CLIENT)
CHANGE MASTER TO MASTER_HOST=, MASTER_PORT=,MASTER_USER=, MASTER_PASSWORD= //动态改变master信息
PURGE MASTER [before 'date'] 删除master端已同步过的日志
++产生了mysql-bin.00000x文件可以删除
reset master; #`
++同步出错时,如果被同步语句确定在从库上可以被忽略
slave stop;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = n;
slave start;
# 看show slave status \G中的Seconds_Behind_Master: 0为正常
附件1:检查从服务器状态脚本
#!/bin/bash
#/blog.zhangjianfeng.com/sh/mysql/CheckMysqlStatus.sh
DATE=`date +%Y%m%d-%H%M%S`
LOGPATH=/blog.zhangjianfeng.com/logs/Mysql
LOG=$LOGPATH\/SlaveStatus_log_$DATE
IP_LIST=(219.xx.xx.xx 60.xx.xx.xx)
if [ ! -d $LOGPATH ]
then
mkdir -p $LOGPATH
fi
checkstatus()
{
for i in ${IP_LIST[*]}
do
echo -e “\n====== Checking $i ======”
ssh $i “mysql -ppassword -e \”show slave status\\G \”"
done
}
case “$1″ in
checkselect)
checkselect
;;
*)
checkstatus
;;
esac
附件2:自动同步从服务器数据
#!/bin/bash
now=`date +%y%m%d-%H%M`
date=`date +%Y%m%d`
srcdir=/blog.zhangjianfeng.com/backup/mysql/forscript/$date/
DBNAME=ptv
DSTDIR=/blog.zhangjianfeng.com/tmp/mysql/$date/
IP_LIST=(xx.xx.xx.13 xx.xx.xx.14 xx.xx.xx.15)
[ ! -d $srcdir ] && mkdir -p $srcdir
savelog()
{
echo -e “\nSaving error logs,pls wait…”
/blog.zhangjianfeng.com/sh/mysql/CheckMysqlStatus.sh wlog
}
start ()
{
#savelog
### MYSQLDUMP & GZIP ###
echo -e “\eMysqlDump running, pls wait…”
cd $srcdir
rm -f $srcdir/*
mysqldump -ppassword –master-data $DBNAME > $DBNAME.$date
SRCFILEMD5=`md5sum $DBNAME.$date|awk ‘{print $1}’ `
gzip $DBNAME.$date
echo “MysqlDump and GZIP done!”
### transfer
echo “starting transfer…”
ssh $DSTIP ” [ -d $DSTDIR ] && rm -rf $DSTDIR ”
ssh $DSTIP ” mkdir -p $DSTDIR ”
scp $srcdir$DBNAME.$date\.gz $DSTIP:$DSTDIR
echo “Transfer done…”
ssh $DSTIP “cd $DSTDIR && gzip -d $DBNAME.$date\.gz”
DSTFILEMD5=` ssh $DSTIP “cd $DSTDIR && md5sum $DBNAME.$date” |awk ‘{print $1}’`
echo $SRCFILEMD5 $DSTFILEMD5
if [ ! $SRCFILEMD5 == $DSTFILEMD5 ]
then
echo “Transfer failed, pls check!”
exit 999
fi
echo “MD5 check passed”
ssh $DSTIP “mysql -ppassword -A -e \”slave stop\” && mysql -ppassword $DBNAME < $DSTDIR$DBNAME.$date && mysql -ppassword -A -e \”slave start\”"
}
check()
{
echo -e “\n`date +%Y.%m.%d\ %R:%S\ start…`”
mysql -ppassword -e “use $DBNAME; insert into slavetest(field1) values (\”slavetest-$now\”);”
echo MasterDB
mysql -ppassword -e “select * from $DBNAME.slavetest order by id desc limit 10 ”
sleep 10
for i in ${IP_LIST[*]}
do
echo $i
ssh $i “mysql -pletv0580 -e \”select * from $DBNAME.slavetest order by id desc limit 10 \”"
done
echo -e “\n`date +%Y.%m.%d\ %R:%S\ END!`”
}
checkandmail()
{
logfile=/blog.zhangjianfeng.com/tmp/checkallslavedbstatus
> $logfile
echo -e “\n`date +%Y.%m.%d\ %R:%S\ start…`” >>$logfile
mysql -e “use $DBNAME; insert into slavetest(field1) values (\”slavetest-$now\”);” -ppassword
sleep 10
echo ==$DSTIP1== >>$logfile
ssh $DSTIP1 “mysql -e \”select * from $DBNAME.table1 order by id desc limit 1 \”" >>$logfile
echo -e “`date +%Y.%m.%d\ %R:%S\ END!`” >>$logfile
cat $logfile | mail -s “Check all SlaveDB status every week.” admin@zhangjianfeng.com
}
case $1 in
xx.xx.xx.13|13)
DSTIP=xx.xx.xx.13
start
;;
xx.xx.xx.14|14)
DSTIP=xx.xx.xx.14
start
;;
xx.xx.xx.15|15)
DSTIP=xx.xx.xx.15
start
;;
check)
check
;;
checkandmail)
checkandmail
;;
*)
echo “$0 {SLAVEIP|check}”
;;
esac
A为主机,B为备份机, 同为双网卡,而且可以通过内网相连
A 内网IP : 192.168.195.28
B 内网IP : 192.168.195.30
数据库版本(5.0.22),目录,初始的库,表 两台机器是一样的
需要备份的库 ad_data , alexa_info , log_db , oblog , union_db , zm0061_db
不需要备份的库 mysql , test
正述
1. 在主机上添加帐号 mysqlrepl 为备份帐号
GRANT REPLICATION SLAVE ON *.* TO 'mysqlrepl'@'192.168.195.30' IDENTIFIED BY '123456789';
如果是4.02版本以前用
GRANT FILE ON *.* TO 'mysqlrepl'@'192.168.195.30' IDENTIFIED BY '123456789';
然后让两台机器的数据库都 shutdown ,锁表也成,但为了直达目的,咱没玩那么高深 :)
2. 修改 A 机器上的 /data/8le8le/database/statusdb/cnf/my-status.cnf
# 日志的名称
log-bin=mysql-bin
# 主服务器ID
server-id=1
# 需要备份的库
binlog-do-db=ad_data
binlog-do-db=alexa_info
binlog-do-db=log_db
binlog-do-db=oblog
binlog-do-db=union_db
binlog-do-db=zm0061_db
# 忽略的数据库
binlog-ignore-db=mysql
binlog-ignore-db=test
3. 修改 B 机器上的 /data/8le8le/database/statusdb/cnf/my-status.cnf
# 日志的名称
log-bin=mysql-bin
# 从服务器ID
server-id=2
# 主服务器的IP地址或者域名
master-host=192.168.195.28
# 主数据库的端口号
master-port=30001
# 同步数据库的用户
master-user=mysqlrepl
# 同步数据库的密码
master-password=123456789
# 如果从服务器发现主服务器断掉,重新连接的时间差
master-connect-retry=60
# 需要备份的库
replicate-do-db=ad_data
replicate-do-db=alexa_info
replicate-do-db=log_db
replicate-do-db=oblog
replicate-do-db=union_db
replicate-do-db=zm0061_db
# 忽略的数据库
replicate-ignore-db=mysql
replicate-ignore-db=test
4. 启动主 服务器 启动 从服务器
从B机器登上数据库
mysql> show slave status\G;
其中两行显示
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
MySQL同步机制基于master把所有对数据库的更新、删除等)都记录在二进制日志里。因此,想要启用同步机制,在master就必须启用二进制日
志。每个slave接受来自master上在二进制日志中记录的更新操作,因此在slave上执行了这个操作的一个拷贝。应该非常重要地意识到,二进制日
志只是从启用二进制日志开始的时刻才记录更新操作的。所有的
slave必须在启用二进制日志时把master上已经存在的数据拷贝过来。如果运行同步时slave上的数据和master上启用二进制日志时的数据不
一致的话,那么slave同步就会失败。把master上的数据拷贝过来的方法之一实在slave上执行 LOAD DATA FROM MASTER
语句。不过要注意,LOAD DATA FROM MASTER 是从MySQL 4.0.0之后才开始可以用的,而且只支持master上的
MyISAM
类型表。同样地,这个操作需要一个全局的读锁,这样的话传送日志到slave的时候在master上就不会有更新操作了。当实现了自由锁表热备份时(在
MySQL 5.0中),全局读锁就没必要了。由于有这些限制,因此我们建议只在master上相关数据比较小的时候才执行 LOAD DATA
FROM MASTER 语句,或者在master上允许一个长时间的读锁。由于每个系统之间 LOAD DATA FROM MASTER
的速度各不一样,一个比较好的衡量规则是每秒能拷贝1MB数据。这只是的粗略的估计,不过master和slave都是奔腾700MHz的机器且用
100MBit/s网络连接时就能达到这个速度了。slave上已经完整拷贝master数据后,就可以连接到master上然后等待处理更新了。如果
master当机或者slave连接断开,slave会定期尝试连接到master上直到能重连并且等待更新。重试的时间间隔由
--master-connect-retry
选项来控制,它的默认值是60秒。每个slave都记录了它关闭时的日志位置。msater是不知道有多少个slave连接上来或者哪个slave从什么
时候开始更新。
MySQL同步功能由3个线程(master上1个,slave上2个)来实现。执行 START SLAVE
语句后,slave就创建一个I/O线程。I/O线程连接到master上,并请求master发送二进制日志中的语句。master创建一个线程来把日
志的内容发送到slave上。这个线程在master上执行 SHOW PROCESSLIST 语句后的结果中的 Binlog Dump
线程便是。slave上的I/O线程读取master的 Binlog Dump
线程发送的语句,并且把它们拷贝到其数据目录下的中继日志(relay
logs)中。第三个是SQL线程,salve用它来读取中继日志,然后执行它们来更新数据。如上所述,每个mster/slave上都有3个线程。每个
master上有多个线程,它为每个slave连接都创建一个线程,每个slave只有I/O和SQL线程。在MySQL
4.0.2以前,同步只需2个线程(master和slave各一个)。slave上的I/O和SQL线程合并成一个了,它不使用中继日志。slave上
使用2个线程的优点是,把读日志和执行分开成2个独立的任务。执行任务如果慢的话,读日志任务不会跟着慢下来。例如,如果slave停止了一段时间,那么
I/O线程可以在slave启动后很快地从master上读取全部日志,尽管SQL线程可能落后I/O线程好几的小时。如果slave在SQL线程没全部
执行完就停止了,但I/O线程却已经把所有的更新日志都读取并且保存在本地的中继日志中了,因此在slave再次启动后就会继续执行它们了。这就允许在
master上清除二进制日志,因为slave已经无需去master读取更新日志了。执行 SHOW PROCESSLIST
语句就会告诉我们所关心的master和slave上发生的情况。