天天看点

mysql之主从复制详解

在实际企业应用环境当中,单台mysql数据库是不足以满足日后业务需求的。譬如服务器发生故障,没有备份服务器来提供服务的话,业务就得停止。介于这种情况,我们来学习一下mysql主从复制。

说明:由于MySQL不同版本之间的(二进制日志)binlog格式可能会不一样,因此最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低,

Master的版本肯定不能高于Slave版本。(版本向下兼容)

使用mysql主从复制的好处有:

1、采用主从服务器这种架构,稳定性得以提升。如果主服务器发生故障,我们可以使用从服务器来提供服务。

2、在主从服务器上分开处理用户的请求,可以提升数据处理效率。

3、将主服务器上的数据复制到从服务器上,保护数据免受意外的损失。

环境描述:

新企业要搭建架构为主从复制的mysql数据库。

主服务器(mysql-master):IP地址:192.168.48.128,mysql已安装,没有用户数据。

从服务器(mysql-slave):IP地址:192.168.48.130,mysql已安装,没有用户数据。

主从服务器均可正常提供服务。

mysql之主从复制详解

主从复制配置如下:

在主服务器上操作:

1)、确保/etc/my.cnf中有如下参数,没有的话需手工添加,并重启mysql服务。

[mysqld]

log-bin=mysql-bin 启动二进制文件

server-id=1 服务器ID

2)、登录mysql,在mysql中添加一个backup的账号,并授权给从服务器。

[root@localhost ~]# mysql -uroot –p123456 登录mysql

mysql> grant replication slave on *.* to 'backup'@'192.168.48.130' identified by 'backup'; 创建backup用户,并授权给192.168.48.130使用。

mysql之主从复制详解

3)、查询主数据库状态,并记下FILE及Position的值,这个在后面配置从服务器的时候要用到。

mysql> show master status; 

mysql之主从复制详解

在从服务器上操作:

1)、确保/etc/my.cnf中有log-bin=mysql-bin和server-id=1参数,并把server-id=1修改为server-id=10。修改之后如下所示:

server-id=10 服务器ID

2)、重启mysql服务。

[root@localhost ~]# mysqladmin -p123456 shutdown 

[root@localhost ~]# mysqld_safe --user=mysql &

mysql之主从复制详解

3)、登录mysql,执行如下语句

[root@localhost ~]# mysql -uroot –p123456

mysql> change master to master_host='192.168.48.128',master_user='backup',master_password='backup',master_log_file='mysql-bin.000003',master_log_pos=401;

mysql之主从复制详解

4)、启动slave同步。

mysql> start slave;

mysql之主从复制详解

5)、检查主从同步,如果您看到Slave_IO_Running和Slave_SQL_Running均为Yes,则主从复制连接正常。

mysql> show slave status\G

mysql之主从复制详解

验证配置是否正常,mysql主从能否正常复制。

在主数据库上新建一个库,并且在库中写一个表和一些数据。

mysql> create database mysqltest;

mysql> use mysqltest;

mysql> create table user(id int(5),name char(10));

mysql> insert into user values (00001,'zhangsan');

mysql之主从复制详解

在从数据库中验证一下,是否正常复制到数据。

mysql> show databases;

mysql之主从复制详解

mysql> select * from mysqltest.user;

mysql之主从复制详解

从上图中的结果,我们可以看到mysql主从复制已经在起作用了,我们在主数据库中写入的数据已经复制到我们的从数据库中了。

环境如下:

单台数据库存有数据,要升级为主从复制的架构。

主数据库:mysql-master:IP192.168.48.128,数据库正常提供服务,有数据。

从数据库:mysql-slave:IP192.168.48.130,数据库正常提供服务,无数据。

mysql之主从复制详解

升级大致步骤如下:

1、修改主数据库配置文件,开启总从复制必要的功能。

2、在主数据库中创建一个账号并授权给从数据库使用。

3、导出主数据库中的数据作。

4、修改从数据库配置文件,开启总从复制必要的功能。

5、把刚才主数据库中导出的数据导入到从数据库。

6、在从数据库中配置连接主数据库要用到的账户、密码等。

7、启动主从复制功能,并检查是否正常复制。

开始升级:

在主数据库上操作:

mysql之主从复制详解

3)、查看已有的数据库有哪些;

mysql之主从复制详解

4)、进行锁表操作,不让数据进行写入动作,这么做事为了防止从数据库的原始数据和主数据库的原始数据不一致。

mysql> flush tables with read lock;

mysql之主从复制详解

5)、查询主数据库状态,并记下FILE及Position的值,这个在后面配置从服务器的时候要用到。

mysql> show master status;

mysql之主从复制详解

6)、切换一个终端,使用mysqldump命令将刚才查询到的两个库导出来。

mysql> mysqldump –uroot –p123456 mysqltest > mysqltest.sql

mysql> mysqldump –uroot –p123456 test1234 > test1234.sql

mysql之主从复制详解

7)、将导出来的库文件传送到从数据库的/root目录下。

[root@localhost ~]#scp mysqltest.sql test1234.sql [email protected]:/root/

这中间需要输入一次验证口令。见下图

mysql之主从复制详解

8)、切换回之前的终端,进行表解锁操作。

mysql> unlock tables;

mysql之主从复制详解

主数据库服务器上的操作告一段落。

在从数据库上操作:

2)、重启mysql服务。

mysql之主从复制详解

3)、登录数据库,确认要同步的库名不存在。

mysql之主从复制详解

4)、创建名为mysqltest和test1234的库。

mysql> create database test1234;

mysql之主从复制详解

4)、切换一个终端,将传过来的两个数据文件分别导入对应的数据库下。

[root@localhost ~]# mysql -uroot –p123456 mysqltest < mysqltest.sql

[root@localhost ~]# mysql -uroot –p123456 test1234 &lt; test1234.sql

mysql之主从复制详解

5)、切换回之前的终端,执行如下语句

mysql> change master to master_host='192.168.48.128',master_user='backup',master_password='backup',master_log_file='mysql-bin.000003',master_log_pos=1650;

6)、启动主从复制功能。

mysql之主从复制详解

7)、

检查主从同步,如果您看到Slave_IO_Running和Slave_SQL_Running均为Yes,则主从复制连接正常。

mysql之主从复制详解

验证主从是否正常配置:

在主数据库上插入数据:

mysql> show tables;

mysql> select * from user;

mysql> insert into user values (4,'ergou');

mysql> insert into user values (5,'sanwazi');

mysql之主从复制详解

在从数据库上查看是否正常同步:

mysql之主从复制详解

上图可以看出,主从之间已经可以正常复制了。

今天就先到这里吧O(∩_∩)O~

mysql主从复制碰到的小问题

一个朋友在做mysql主从复制的时候碰到了一些问题,他已经按照我之前的教程一步步做了。但是就是不知道是怎么回事。从数据库中使用命令show slave status\G查看到的结果如下图:

mysql之主从复制详解

我们知道,要想mysql主从复制成功的先决条件是Slave_IO_Running和Slave_SQL_Running均为Yes,而上图所示的结果显然是有一个不满足条件。

再根据Last_IO_Error的错误代码2013及下面的错误提示我们可以知道,从数据库无法正常连接到主数据库。

这里原因有三:

1、主数据库没有给从数据库登录授权

2、网络不通

3、有防火墙

明白这三点之后我们就可以针对原因依次来解决它们:

登录主数据库,给从数据库授权

[root@localhost ~]# mysql -uroot –p123456 登录主数据库

mysql> grant replication slave on *.* to 'backup'@'192.168.48.130' identified by 'backup'; 创建backup用户,并授权给从数据库连接使用。

mysql之主从复制详解

检查网络是否通畅

[root@localhost ~]# ping -c 4 192.168.48.128 再从服务器上ping主服务器。

mysql之主从复制详解

分别在主从服务器上检查防火墙状态

我们可以直接关闭防火墙

运行命令:[root@localhost ~]# setup

mysql之主从复制详解

选择防火墙(Firewall configuretion)这一项.

mysql之主从复制详解

将它Disabled掉。

mysql之主从复制详解

或者你可以直接使用命令:

[root@localhost ~]# service iptables stop 即时生效,系统重启后失效

[root@localhost ~]# chkconfig iptables off 当前状态无效,系统重启后生效

大家可以结合使用

mysql之主从复制详解

以上情况都排除完毕,我们来再测试一下主从是否能正常连接。

在从数据库中执行如下命令:

mysql>stop slave;

mysql>start slave;

mysql之主从复制详解

然后查看主从连接状态

mysql>show slave status\G

mysql之主从复制详解

经过上述操作,我那位朋友成功排除了主从不能复制的故障。

故障2:报错如下:

mysql之主从复制详解

意思就是从上的server_id和主的一样的,经查看发现从上的/etc/my.cnf中的server_id=1这行我没有注释掉(在下面复制部分我设置了server_id),于是马上把这行注释掉了,然后重启mysql,发现还是报同样的错误。

使用如下命令查看了一下server_id

show variables like 'server_id';

发现,mysql并没有从my.cnf文件中更新server_id,既然这样就只能手动修改了

mysql> set global server_id=10; #此处的数值和my.cnf里设置的一样就行 

mysql> slave start;

如此执行后,slave恢复了正常。

不过稍后蚊子使用/etc/init.d/mysqld restart重启了mysql服务,然后查看slave状态,发现又出现了上面的错误,然后查看server_id发现这个数值又恢复到了1。

之后蚊子又重新查看了一下/etc/my.cnf的内容,确认应该不是这个文件的问题,于是去google查了一下,看到mysql在启动的时候会查找/etc/my.cnf、DATADIR/my.cnf,USER_HOME/my.cnf。 

===========================主从配置常见问题===========================

一、做了MySQL主从也有一段时间了,这两天检查磁盘空间情况,发现放数据库的分区磁盘激增了40多G,一路查看下来,发现配置好主从复制以来到现在的binlog就有40多G,原来根源出在这里,查看了一下my.cnf,看到binlog的 size是1G就做分割,但没有看到删除的配置,在MySQL里show了一下variables:

  mysql>show variables like '%log%';

  查到了,

  | expire_logs_days | 0 |

  这个默认是0,也就是logs不过期,这个是一个global的参数,所以需要执行

  set global expire_logs_days=8;

  这样8天前的log就会被删除了,如果有回复的需要,请做好备份工作,但这样设置还不行,下次重启mysql了,配置又恢复默认了,所以需在my.cnf中设置,

  expire_logs_days = 8

  这样重启也不怕了。

  现在我在生产环境下的做法是将此时间设为0,然后备份mysql日志文件,然后再手动清理此文件。

  想要恢复数据库以前的资料,执行

  mysql>show binlog events;

  由于数据量很多,查看起来很麻烦,光打开个文件就要闪半天,所以应该适当删除部分可不用的日志。

  并且如果使用的时间足够长的话,会把我的硬盘空间都给吃掉。

  1、登录系统,/usr/bin/mysql

  使用mysql查看日志:

  mysql>show binary logs;

  +—————-+———–+

  | Log_name | File_size |

  | ablelee.000001 | 150462942 |

  | ablelee.000002 | 120332942 |

  | ablelee.000003 | 141462942 |

  2、删除bin-log(删除ablelee.000003之前的而没有包含ablelee.000003):

  mysql> purge binary logs to ′ablelee.000003′;

  Query OK, 0 rows affected (0.16 sec)

  3、查询结果(现在只有一条记录了):

  mysql> show binlog events\G

  *************************** 1. row ***************************

  Log_name: ablelee.000003

  Pos: 4

  Event_type: Format_desc

  Server_id: 1

  End_log_pos: 106

  Info: Server ver: 5.1.26-rc-log, Binlog ver: 4

  1 row in set (0.01 sec)

  (ablelee.000001和ablelee.000002已被删除)

  mysql> show binary logs;

  | ablelee.000003 | 106 |

  1 row in set (0.00 sec)

  (删除的其它格式运用!)

  PURGE {MASTER | BINARY} LOGS TO ‘log_name’

  PURGE {MASTER | BINARY} LOGS BEFORE ‘date’

  用于删除列于在指定的日志或日期之前的日志索引中的所有二进制日志。这些日志也会从记录在日志索引文件中的清单中被删除,这样被给定的日志成为第一个。

  例如:

  PURGE MASTER LOGS TO 'mysql-bin.010'; PURGE MASTER LOGS BEFORE '2008-06-22 13:00:00';

  二、现在手上蛮多项目的数据库用的是MySQL,由于权限等原因,暂时不方便部署Nagios监控MySQL主从复制,所以我一般在从机上配置了SHELL脚本用来监控MySQL的主从状态(设置为每十分钟运行一次),并且每次出问题时将确切日期写进错误日志,方便事后排查原因,脚本内容如下:

  #!/bin/bash

  #check MySQL_Slave Status

  #crontab time 00:10

  MYSQLPORT=`netstat -na|grep "LISTEN"|grep "3306"|awk -F[:" "]+ '{print $4}'`

  MYSQLIP=`ifconfig eth0|grep "inet addr" | awk -F[:" "]+ '{print $4}'`

  STATUS=$(/usr/local/webserver/mysql/bin/mysql -u yuhongchun -pyuhongchun101 -S /tmp/mysql.sock -e "show slave status\G" | grep -i "running")

  IO_env=`echo $STATUS | grep IO | awk ' {print $2}'`

  SQL_env=`echo $STATUS | grep SQL | awk '{print $2}'`

  if [ "$MYSQLPORT" == "3306" ]

  then

  echo "mysql is running"

  else

  mail -s "warn!server: $MYSQLIP mysql is down" [email protected]

  fi

  if [ "$IO_env" = "Yes" -a "$SQL_env" = "Yes" ]

  echo "Slave is running!"

  echo "####### $date #########">> /data/data/check_mysql_slave.log

  echo "Slave is not running!" >> /data/data/check_mysql_slave.log

  mail -s "warn! $MySQLIP_replicate_error" [email protected] << /data/data/check_mysql_slave.log

  建议每十分钟运行一次。

  */10 * * * * root /bin/sh /root/mysql_slave.sh

  记得在每台MySQL从机上分配一个yuhongchun的用户,权限大些也没关系,只限定在本地运行,如下所示:

  grant all privileges on *.* to "yuhongchun"@"127.0.0.1" identified by "yuhongchun101";

  grant all privileges on *.* to "yuhongchun"@"localhost" identified by "yuhongchun101";

  脚本设计思路:

  1、此脚本应该能适应各种各样不同的内外网环境,即IP不同的环境;

  2、让脚本也顺便监控下MySQL是否正常运行;

  三、innodb_buffer_pool_size的设置。

  这个参数定义了InnodDB存储引擎的表数据和索引数据的最大内存缓冲区大小。和MyISAM存储引擎不同,MyISAM的key_buffer_size只缓存索引键,而innodb_buffer_pool_size却是同时为数据块和索引块 做缓存,这个特征和Oracle是一样的,这个值设得越高,访问表中数据需求的I/O就越少。在一个专用的数据库服务器,可以设置这个参数达机器物理内存的80%,我现在一般的做法是配置成物理内存的 1/4,比如8G内存的生产数据库,我一般会配置成2G左右。

  四、测试了很长一段时间的MySQL的负载均衡,最后综合了老男孩和其它技术高手的意见,最终决定还是用LVS+Keepalived来作为MySQL的负载均衡,这是因为后端机器超过10台时,LVS的性能还是最好的;如果在3-5台左右,HAProxy也可以很轻松的搞定工作。

  五、大家都很清,磁盘I/O总会成为数据库的性能瓶颈,这时候我们应该如何在生产环境下选择合适的RAID级别呢?

  1、如果数据读写都很频繁,可靠性要求也很高,最好选择RAID10;

  2、如果数据读很频繁,写相对较少,对可靠性有一定要求,可以选择RAID5;

  3、如果数据读写都很频繁,但可靠性要求不高,可以选择RAID0。

  4、对于核心业务的数据库主从同步,建议从机的备份时间往后延迟一段时间,通常的做法是延迟一天左右。

继续阅读