mysql主从配置

MySQL Replication 又叫做AB复制或者主从复制。它主要用于MySQL的时时备份或者读写分离。在配置之前先做一下准备工作,配置两台mysql服务器,或者在一台服务器上配置两个端口也可以。这里的的实验中就是在一台服务器上跑了两个mysql。

原理:MySQL的Replication是一个异步的复制过程,从一个MySQL实例(Master)复制到另一台MySQL实例上。在Master和Slave之间复制的整个过程主要由3个线程完成,其中两个线程(SQL线程和IO线程)在Slave端,另外一个线程(IO线程)在Master端。

要实现主从复制,首先要在Master端打开Binary Log功能。因为整个复制过程实际上就是Slave从Master上获取二进制日志,然后在自己身上完全按照产生的顺序一次执行日志中记录的各种操作的过程。

复制的具体过程如下:

  1. Slave的IO线程连上Master,并请求日志文件指定位置(或从开始的日志)之后的日志的内容。
  2. Master接收到来自Slave的IO线程请求后,负责复制IO线程根据请求的信息读取指定日志之后的日志信息,返回给Slave端的IO线程。返回信息中除了日志所包含的信息,还包含了包括本次返回的信息在Master端的Binary Log文件的名称和位置。
  3. Slave的IO线程接受到信息后,将日志内容一次写入Slave端的Relay Log文件(mysql-relay-bin.xxxx)的末端,并将读取到的Master端的bin-log的文件和位置记录到master-info文件中,以便在下一次读取时能够清楚地告诉Master,下次从bin-log哪个位置开始往后的日志内容。
  4. Log中更新内容后,会马上解析该Log文件中的内容,还原成在Master端真实执行时的可执行的SQL语句,并执行这些SQK语句。实际上Master和Slave执行同样的语句。

1. 配置mysql服务

MySql的安装和配置请看 Mysql 安装
按照上面的步骤,你可以成功搭建好一个mysql,跑的是3306端口,下面我们搭建第二个mysql,指定的端口为:3307:

1
2
3
4
cd /usr/local/
cp -r mysql mysql_slave
cd mysql_2
./scripts/mysql_install_db --user=mysql --datadir=/data/mysql_slave

最后一步是初始化数据库目录,如果出现两个“OK”并且生成/data/mysql2目录才正确,否则请仔细查看错误信息.
拷贝配置文件到mysql_2下,并修改相关项目:

1
2
cp /etc/my.cnf  ./my.cnf
vim my.cnf


1
2
port          = 3306
socket = /tmp/mysql.sock

改为: 并增加一行

1
2
3
port          = 3307
socket = /tmp/mysql_slave.sock
datadir = /data/mysql_slave

拷贝编辑启动脚本:

1
2
cp /etc/init.d/mysqld /etc/init.d/mysqldslave
vim /etc/init.d/mysqldslave

需要修改的部分,修改后为:

1
2
3
basedir=/usr/local/mysql_slave
datadir=/data/mysql_slave
conf=$basedir/my.cnf

之后启动即可。

至此,在一台机器上已经启动了两个mysql:

1
2
3
4
5
netstat -lnp |grep mysqld
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 7217/mysqld
tcp 0 0 0.0.0.0:3307 0.0.0.0:* LISTEN 7469/mysqld
unix 2 [ ACC ] STREAM LISTENING 42591 7217/mysqld /tmp/mysql.sock
unix 2 [ ACC ] STREAM LISTENING 48423 7469/mysqld /tmp/mysql_slave.sock

2. 配置主从准备工作

这里我们打算把3306端口的mysql作为主(master),而把3307的mysql作为从(slave). 为了让实验更加像生产环境,所以在master上创建一个库db1,并且把mysql的库数据复制给它:

1
2
3
4
5
6
7
mysql -uroot -S /tmp/mysql.sock

mysql> create database db1;
Query OK, 1 row affected (0.06 sec)

mysql> quit
Bye

-S 后面指定mysql的socket文件路径,这也是登陆mysql的一种方法,因为在一台服务器上跑了两个mysql端口,所以,只能用 -S 这样的方法来区分。首先创建了db1库,然后把mysql库的数据复制给它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
mysqldump -uroot -S /tmp/mysql.sock mysql > 123.sql
mysql -uroot -S /tmp/mysql.sock db1 < 123.sql

//进入mysql后可以看到:

mysql> use db1;
Database changed
mysql> show tables;
+---------------------------+
| Tables_in_db1 |
+---------------------------+
| columns_priv |
| db |
| event |
| func |
| general_log |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| ndb_binlog_index |
| plugin |
| proc |
| procs_priv |
| servers |
| slow_log |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| user |
+---------------------------+
23 rows in set (0.00 sec)

3. 配置主(master)

1
vim /etc/my.cnf

在[mysqld]部分查看是否有以下内容,如果没有则添加:

1
2
server-id=1
log-bin=keso

除了这两行是必须的外,还有两个参数,你可以选择性(2选1)的使用:

1
2
binlog-do-db=databasename1,databasename2 #用来指定需要同步的库
binlog-ignore-db=databasename1,databasename2 #用来指定忽略不同步的库

完成后重启mysqld服务。然后进入主mysql并授权给从一个用来同步数据的用户 repl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> grant replication slave on *.* to 'repl'@'127.0.0.1' identified by '111111';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec) #刷新MySQL的系统权限相关表

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec) #锁定数据库,此时不允许更改任何数据

show master status; #查看状态,这些数据是要记录的,一会要在slave端用到
+-------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------+----------+--------------+------------------+
| keso.000001 | 331 | | |
+-------------+----------+--------------+------------------+
1 row in set (0.00 sec)

4. 配置从(slave)

先修改slave的配置文件my.cnf:

1
vim /usr/local/mysql_slave/my.cnf

修改

1
server-id = 2 #可以是出1意外的其他任何数字

总之不能让这个id和master一样,否则会报错。另外在从上,你也可以选择性的增加如下两行,意义同主的那两个可选参数,如果在主上已经定义过了,那么在从上就不用再定义了。

1
2
replicate-do-db=databasename1,databasename2
replicate-ignore-db=databasename1,databasename2

改完后,重启slave:

1
/etc/init.d/mysqldslave restart

拷贝master上的db1库的数据到slave上,因为master和slave都在一台服务器上,所以操作起来简单了很多,如果是不同的机器,可能就需要远程拷贝了,希望你注意这一点:

1
2
mysql -S /tmp/mysql_slave.sock -e "create database db1"
mysql -S /tmp/mysql_slave.sock db1<123.sql

登录从,并执行如下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
mysql -S /tmp/mysql_slave.sock 

mysql> slave stop ;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> change master to master_host='127.0.0.1', master_port=3306,master_user='repl', master_password='111111',master_log_file='keso.000001', master_log_pos=331;
Query OK, 0 rows affected (0.00 sec)

mysql> slave start;
Query OK, 0 rows affected (0.03 sec)

mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: keso.000001
Read_Master_Log_Pos: 331
Relay_Log_File: KesoLinux-relay-bin.000002
Relay_Log_Pos: 246
Relay_Master_Log_File: keso.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 331
Relay_Log_Space: 405
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: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
1 row in set (0.00 sec)

确认Slave_IO_Running和Slave_SQL_Running 同时为yes时,才算正常。

5. 测试主从

在master上执行如下命令:

1
2
3
4
5
6
7
8
9
10
select count(*) from db; 
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.00 sec)

mysql> truncate table db;
Query OK, 0 rows affected (0.00 sec)

这样清空了db1.db表的数据,下面查看slave上的该表数据:

1
2
3
4
5
6
elect count(*) from db;
+----------+
| count(*) |
+----------+
| 0 |
+----------+

slave上的该表也被清空了。这样好像不太明显,不妨继续把db表删除试试:

1
drop table db;

在slave上可以再使用select是可以看到:

1
2
select count(*) from db"
ERROR 1146 (42S02) at line 1: Table 'db1.db' doesn't exist

主从配置起来很简单,但是这种机制也是非常脆弱的,一旦我们不小心在从上写了数据,那么主从也就被破坏了。另外如果重启master,务必要先把slave停掉,也就是说需要在slave上去执行 slave stop 命令,然后再去重启master的mysql服务,否则很有可能就会中断了。当然重启完后,还需要把slave给开启 slave start.