MYSQL主从复制原理及拓扑结构:

 

准备工作:
1)配置好主机名和IP地址
node1.forman.com  172.16.220.11
node2.forman.com  172.16.220.12
2)时间同步和双机互连

 
  
  1. Master:  
  2. #hwclock -s
  3. #vim /etc/hosts  
  4. 添加如下:  
  5. 172.16.220.11   node1.forman.com        node1  
  6. 172.16.220.12   node2.forman.com        node2  
  7. # ssh-keygen -t rsa  
  8. # ssh-copy-id -i .ssh/id_rsa.pub root@node2  
  9. # ssh node2 'ifconfig'  
  10.  
  11. Slave #hwclock -s # vim /etc/hosts
  12. 添加如下:  
  13. 172.16.220.11   node1.forman.com        node1  
  14. 172.16.220.12   node2.forman.com        node2  
  15. # ssh-keygen -t rsa  
  16. # ssh-copy-id -i .ssh/id_rsa.pub root@node1 
  17. # ssh node1 'ifconfig'  

 

 

一、准备两台mysql服务器

 
  
  1. Master Slave: 
  2. #fdisk /dev/sda  
  3. ....  
  4. 1个大小为20G 类型8e的分区,为sda5  
  5. ....  
  6. #partprobe /dev/sda  
  7. #pvcreate /dev/sda5  
  8. #vgcreate myvg /dev/sda5  
  9. #lvcreate -L 10G -n mydata myvg  
  10. #mke2fs -j /dev/myvg/mydata  
  11. #mkdir /data/mydata -pv  
  12. #vim /etc/fstab  
  13. /dev/myvg/mydata        /data/mydata            ext3    defaults        0 0  
  14. #mount -a  
  15. #useradd -r mysql  
  16. #chown -R mysql:mysql /data/mydata  
  17. 安装mysql  
  18. # tar xf mysql-5.5.22-linux2.6-i686.tar.gz -C /usr/local  
  19. #cd /usr/local  
  20. # ln -sv mysql-5.5.22-linux2.6-i686 mysql  
  21. # cd mysql  
  22. # chown -R mysql:mysql .  
  23. # scripts/mysql_install_db --user=mysql --datadir=/data/mydata  
  24.  
  25. #chown -R root .  
  26. # cp support-files/my-large.cnf /etc/my.cnf  
  27. # vim /etc/my.cnf  
  28. [mysqld]  
  29. thread_concurrency = 2 
  30. datadir = /data/mydata  
  31. # cp support-files/mysql.server /etc/rc.d/init.d/mysqld  
  32. # chmod +x /etc/rc.d/init.d/mysqld  
  33. # chkconfig --add mysqld  
  34. #service mysqld start  

 

二、配置主、从服务器

1 、配置Master

 
  
  1. 编辑mysql的主配置文件(二进制文件默认已启用;server-id =1 )
  2. 创建具有复制权限的用户  
  3. #/usr/local/mysql/bin/mysql  
  4. mysql>grant replication slave,replication client on *.* to repluser@'172.16.220.%' identified by 'redhat';  //这里授权的主机越少越好  
  5. mysql> flush privileges;  
  6. mysql> show master status;  
  7. +------------------+----------+--------------+------------------+  
  8. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  9. +------------------+----------+--------------+------------------+  
  10. | mysql-bin.000001 |      356 |              |                  |  
  11. +------------------+----------+--------------+------------------+  

 

2、配置Slave

2.1 启用中继日志(关闭二进制日志)设置server-id(与主服务器一定不能样)

 

 
  
  1. #vim /etc/my.cnf  
  2. 修改server-id  = 111           //server-id 中的连接线可以是"-"也可以是"_"  
  3. 添加relay-log=mysql-relay  
  4. 注释掉log-bin=mysql-bin  
  5.  
  6. # service mysqld restart  
  7. #/usr/local/mysql/bin/mysql  
  8.  
  9. 验证刚才的设置(关闭了log_bin 启用了relay_log)  
  10. mysql> show global variables like 'relay_log';  
  11. +---------------+-------------+  
  12. | Variable_name | Value       |  
  13. +---------------+-------------+  
  14. | relay_log     | mysql-relay |  
  15. +---------------+-------------+  
  16. mysql> show global variables like 'log_bin';  
  17. +---------------+-------+  
  18. | Variable_name | Value |  
  19. +---------------+-------+  
  20. | log_bin       | OFF   |  
  21. +---------------+-------+   
  22. mysql> show global variables like 'server_id';  
  23. +---------------+-------+  
  24. | Variable_name | Value |  
  25. +---------------+-------+  
  26. | server_id     | 111   |  
  27. +---------------+-------+  
  28.  

 

2.2 启动从服务,并指定主服务器参数

 
  
  1. mysql>help change master to;  
  2. 以下的这些参数,在mysql 5.5版本以前是可以直接写进配置文件my.cnf中的;但是msyql 5.5版本之后就不支持了,只有再命令行配置才生效;  
  3. 使用的命令是 change master to  
  4.  
  5. option:  
  6.   MASTER_HOST = 'host_name' 
  7.   | MASTER_USER = 'user_name' 
  8.   | MASTER_PASSWORD = 'password' 
  9.   | MASTER_PORT = port_num 
  10.   | MASTER_LOG_FILE = 'master_log_name' 
  11.   | MASTER_LOG_POS = master_log_pos 
  12.  
  13. 设置如上的参数内容:  
  14. mysql> change master to master_host='172.16.220.11',master_user='repluser',master_password='redhat',master_log_file='mysql-bin.000001',master_log_pos=356;  
  15. 可以测试这条命令配置的结果  
  16. #cat /data/mydata/master.info  
  17. 18  
  18. mysql-bin.000001  
  19. 356  
  20. 172.16.220.11  
  21. repluser  
  22. redhat  
  23. 3306  
  24. 60  
  25. 0  
  26. .......等内容(每当复制一次内容时,这个文件的内容都会改变,从服务关机,再启动时,会自动加载这个文件的)  
  27.  
  28. mysql> start slave; (这条语句,要在上条语句执行后就执行,不要退出mysql)  
  29. mysql> show slave status\G  
  30. 确保有以下内容:  
  31. Slave_IO_Running: Yes  
  32. Slave_SQL_Running: Yes  
  33.  

 

2.3 阻止从服务器的写操作

 
  
  1. mysql> set global read_only=1;  
  2. mysql> show global variables like 'read_only';  
  3. +---------------+-------+  
  4. | Variable_name | Value |  
  5. +---------------+-------+  
  6. | read_only     | ON    |  
  7. +---------------+-------+  
  8. 这项限制,只是阻止了普通用户不可写,管理员依然是有权限的;若是使用flush tables with read lock,会阻止所有用户的写操作,但同时也会阻止SQL Thread的写,数据就无法同步了)  

 

OK此时主从服务器配置完成

2.4 验证

 
  
  1. Master:  
  2.  
  3. mysql> create database testdb;  
  4. mysql> use testdb;   //创建数据库
  5. mysql> create table t1 (NAME VARCHAR(20));  //并创建表
  6. mysql> show tables;  
  7. +------------------+  
  8. | Tables_in_testdb |  
  9. +------------------+  
  10. | t1               |  
  11. +------------------+  
  12. node2:来验证一下  
  13. mysql>show databases;  
  14. +---------------------+  
  15. | Database            |  
  16. +---------------------+  
  17. | information_schema  |  
  18. | #mysql50#lost+found |  
  19. | mysql               |  
  20. | performance_schema  |  
  21. | test                |  
  22. testdb              |  
  23. +---------------------+  
  24. mysql> use testdb;  
  25. mysql> show tables;  
  26. +------------------+  
  27. | Tables_in_testdb |  
  28. +------------------+  
  29. t1               |  
  30. +------------------+  

三、对主从服务器的补充扩展

(建议配置)

1、事务的安全性

即在主服务器崩溃,事务已经提交的情况下--写入二进制文件;
 可以保证数据的完整性;实现事务的安全性;
 

 
  
  1. Master:  
  2. sync_binlog=1          将提交的二进制事务,写进二进制日志文件中;随时同步二进制缓存内容到二进制日志文件中去  
  3. inonodb_flush_logs_at_trx_commit=1    在事务日志提交时,是不是将事务日志的内容刷写进去  
  4. 操作如下:
    mysql> set global sync_binlog=1;  
    mysql> set global innodb_flush_log_at_trx_commit=1;  
    Slave:  
    skip_slave_start=1     跳过从服务的自动启动;需要手动start slave才生效。   

 


2 、若从服务挂了,那么从服务器的内容就全部丢失了,如何解决?

 
  
  1. (使用mysqldump是不能了,用msyqldump需要mysql服务,此时mysql服务不能使用了,这个命令就无从谈起了;若使用这个命令需要重新初始化mysql,会导致数据冲突的;因此使用物理备份即可)  
  2. 使用物理备份的:冷备份或快照的方式备份主服务上的内容,而后复制过来即可。  
  3.  
  4.  
  5. 模拟Slave不能工作  
  6. node2:  
  7. #service mysqld stop  
  8. #cd /data/mydata  
  9. #rm -rf *  
  10.  
  11. node1:  
  12. mysql>flush tables with read lock;  
  13. mysql>show master status;               //加锁之后要观察此时的二进制文件和时间点  
  14. +------------------+----------+--------------+------------------+  
  15. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  16. +------------------+----------+--------------+------------------+  
  17. | mysql-bin.000001 |      924 |              |                  |  
  18. +------------------+----------+--------------+------------------+  
  19.  
  20. 不要退出mysql  
  21. 再打开一个终端,执行  
  22. #lvcreate -L 50M -s -p r -n mydata-snap /dev/myvg/mydata   //创建快照卷,这条命令执行结束后,可以在上个终端释放锁了mysql>unlock tables;  
  23. #mount /dev/myvg/mydata-snap /mnt  
  24. #cd /mnt  
  25. #find . | cpio -o -H newc --quiet | gzip > /root/alldatabase.gz  
  26. #umount /mnt  
  27. #scp alldatabase.gz node2:/root  
  28.  
  29. 此时又对数据库做了改变:  
  30. mysql>use testdb;  
  31. mysql>create table tb2(id int);  
  32. mysql>show master status;  
  33. ------------------+----------+--------------+------------------+  
  34. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  35. +------------------+----------+--------------+------------------+  
  36. | mysql-bin.000001 |     1014 |              |                  |  
  37. +------------------+----------+--------------+------------------+//这些数据,在快照卷里是没有的  
  38.  
  39. node2:  
  40. 此时可以恢复数据了  
  41. #gzip -d alldatabase.gz  
  42. #cp alldatabase /data/mydata  
  43. #cd /data/mydata  
  44. #cpio -id < alldatabase 
  45. #rm -rf alldatabase  
  46. # service mysqld start  
  47. Starting MySQL...                                          [  OK  ]  
  48.  
  49. 此时,从服务的配置master.info都已经没了,需要重新配置  
  50. mysql>change master to master_host='172.16.220.11',master_user='repluser',master_password='redhat',master_log_file='mysql-bin.000001',master_log_pos=924;//从时间点924开始同步  
  51. mysql>start slave;  
  52. mysql> show slave status\G  
  53. 有这么一条信息  
  54. Read_Master_Log_Pos: 1014    和主服务的时间点是一样的  
  55. mysql>use testdb;  
  56. mysql>show tables;  
  57. | Tables_in_testdb |  
  58. +------------------+  
  59. | tb1              |  
  60. | tb2              |  
  61. +------------------+       //看到,数据已经完全同步过来了  
  62.  

 
3、设置半同步

在Master和Slave的mysql命令行运行如下代码:

 

 
  
  1. #Master    
  2. mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';  //安装支持主服务半同步的插件  
  3. mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;               //启动主服务器的半同步功能  
  4. mysql> SET GLOBAL rpl_semi_sync_master_timeout = 1000;            //超时时间  
  5.  
  6. #Slave    
  7. mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';    
  8. mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;    
  9. mysql> STOP SLAVE;  
  10. mysql> START SLAVE;  
  11.  
  12. 在Master和Slave的my.cnf中编辑,可以长久有效:  
  13.  
  14. # Master    
  15. [mysqld]    
  16. rpl_semi_sync_master_enabled=1    
  17. rpl_semi_sync_master_timeout=1000 # 1 second   
  18.  
  19. # Slave    
  20. [mysqld]    
  21. rpl_semi_sync_slave_enabled=1   
  22.  
  23.  
  24. # 也可通过设置全局变量的方式来设置,如下:  
  25. set global rpl_semi_sync_master_enabled=1   
  26. # 取消加载插件  
  27. mysql> UNINSTALL PLUGIN rpl_semi_sync_master;  
  28. ==============================================  
  29.  
  30. 查看从服务器上的semi_sync是否开启:  
  31. mysql> SHOW GLOBAL STATUS LIKE 'rpl_semi%';  
  32.  
  33. 查看主服务器上的semi_sync是否开启,注意clients 变为1 ,证明主从半同步复制连接成功:  
  34. mysql> SHOW GLOBAL STATUS LIKE 'rpl_semi%';  
  35.  

 

4、设置mysql的复制过滤(仅同步有限的数据库,或某个数据库的某些表)

 

 
  
  1. 在主服务器上实现:  
  2. 在主服务器过滤:任何不涉及到数据库相关的写操作都不会被记录到二进制日志当中;  
  3.  
  4. binlog-do-db           //binlog-do-db表示和哪个数据库相关的写入类、修改类指令会被写入到二进制文件中去  
  5. binlog-do-db  
  6.  
  7. binlog-ignore-db        //binlog-ignore-db表示忽略(黑名单),除了这个数据库之外的都复制  
  8.  
  9. 例如,只复制testdb这个表  
  10. node1:  
  11. #vim /etc/my.cnf  
  12. [mysqld]  
  13. binlog-do-db=testdb 
  14. #service mysqld restart  
  15. 测试即可(在主服务器的非testdb数据库中做的任何操作,在从服务上都不会有所改变)  
  16.  
  17. 从服务器:  
  18. replicate_do_db  
  19. rpplicate_ignore_db  
  20.  
  21. replicate_do_table  
  22. replicate_ignore_table  
  23.  
  24. replicate_wild_do_table  
  25. replicate_wild_ignore_table  
  26.  
  27. 例如  
  28. 在从服务器上只复制testdb这一个数据库:  
  29. #vim /etc/my.cnf  
  30. [mysqld]  
  31. replicate_do_db=testdb 
  32. #service mysqld restart  
  33. 建议:在从服务器上复制  
  34.  

 

四、基于SSL实现数据库复制

要求主从服务器各自都要有证书和私钥;默认情况下主从服务器的SSL功能是没有启用的,需要先启用。

1、配置Master为CA证书服务器

 
  
  1. #vim /etc/pki/tls/openssl.cnf  
  2. dir             = ../../cA修改为  
  3. dir             = /etc/pki/CA     
  4. #cd /etc/pki/CA  
  5. #(umask 077; openssl genrsa 1024 > private/cakey.pem)  
  6. #openssl req -new -x509 -key private/cakey.pem -out cacert.pem  
  7.  
  8. Country Name (2 letter code) [GB]:CN  
  9. State or Province Name (full name) [Berkshire]:HN  
  10. Locality Name (eg, city) [Newbury]:ZZ  
  11. Organization Name (eg, company) [My Company Ltd]:Forman  
  12. Organizational Unit Name (eg, section) []:Tech  
  13. Common Name (eg, your name or your server's hostname) []:node1.forman.com  
  14. Email Address []:  
  15. #mkdir newcerts certs crl  
  16. #touch index.txt  
  17. #echo 01 > serial  
  18.  

 

4.2 为Master上的mysql准备私钥以及颁发证书

 
  
  1. #mkdir /usr/local/mysql/ssl  
  2. #cd /usr/local/mysql/ssl  
  3. #(umask 077; openssl genrsa 1024 > mysql.key)  
  4. #openssl req -new -kdy mysql.key -out mysql.csr  
  5. CN  
  6. HN  
  7. ZZ  
  8. Forman 
  9. Tech  
  10. node1.forman.com  
  11.  
  12. #openssl ca -in mysql.csr -out mysql.crt  
  13. #cp /etc/pki/CA/cacert.pem /usr/local/mysql/ssl  
  14. #cd /usr/local/mysql  
  15. #chown -R mysql:mysql ssl/  
  16.  

 


4.3 为Slave上的mysql准私钥,证书申请、在Master上为Slave签发证书

 
  
  1. #mkdir /usr/local/mysql/ssl  
  2. #cd /usr/local/mysql/ssl  
  3. #(umask 077; openssl genrsa 1024 > mysql.key)  
  4. #openssl req -new -key mysql.key -out mysql.csr  
  5. CN  
  6. HN  
  7. ZZ  
  8. Forman  
  9. Tech  
  10. node1.forman.com  
  11.  
  12. #scp ./mysql.csr node1:/root  
  13.  
  14. Master上为Slave签发证书  
  15. #pwd  
  16. /root  
  17. #openssl ca -in mysql.csr -out mysql.crt  
  18. #scp ./mysql.crt node2:/usr/local/mysql/ssl  
  19. #scp /etc/pki/CA/cacert.pem node2:/usr/local/mysql/ssl  
  20.  
  21. 保证主从服务器上/usr/lcoal/mysql/ssl目录下的文件的属主,属组为mysql  
  22. #ll /usrl/local/mysql/ssl  
  23. -rw-r--r-- 1 mysql mysql 1119 Aug 20 20:13 cacert.pem  
  24. -rw-r--r-- 1 mysql mysql 3067 Aug 20 20:04 mysql.crt  
  25. -rw-r--r-- 1 mysql mysql  643 Aug 20 20:03 mysql.csr  
  26. -rw------- 1 mysql mysql  887 Aug 20 20:02 mysql.key  
  27.  

 

4.4 开启主从服务器mysql的SSL功能

 
  
  1. Master:  
  2. #vim /etc/my.cnf  
  3.  
  4. 在[mysqld]和[mysqldump]之间添加如下内容:  
  5. ssl  
  6. ssl-ca=/usr/local/mysql/ssl/cacert.pem  
  7. ssl-cert=/usr/local/mysql/ssl/mysql.crt  
  8. ssl-key=/usr/local/mysql/ssl/mysql.key  
  9. 保存退出  
  10. #service mysqld restart  
  11.  
  12. mysql> show global variables like '%ssl%';  
  13. +---------------+---------------------------------+  
  14. | Variable_name | Value                           |  
  15. +---------------+---------------------------------+  
  16. | have_openssl  | YES                             |  
  17. | have_ssl      | YES                             |  
  18. | ssl_ca        | /usr/local/mysql/ssl/cacert.pem |  
  19. | ssl_capath    |                                 |  
  20. | ssl_cert      | /usr/local/mysql/ssl/mysql.crt  |  
  21. | ssl_cipher    |                                 |  
  22. | ssl_key       | /usr/local/mysql/ssl/mysql.key  |  
  23. +---------------+---------------------------------+  
  24. mysql> show master status;  
  25. +------------------+----------+--------------+------------------+  
  26. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  27. +------------------+----------+--------------+------------------+  
  28. | mysql-bin.000003 |      107 | testdb       |                  |  
  29. +------------------+----------+--------------+------------------+  
  30.  
  31. Slave:(建议不要在配置文件中指定,而是在change to命令中指定)  
  32. #vim /etc/my.cnf  
  33. 在[mysqld]和[mysqldump]之间添加如下内容:  
  34. ssl  
  35. #service mysqld restart  
  36.  
  37. mysql>  change master to master_host='172.16.220.11',master_user='repluser',master_password='redhat',master_log_file='mysql-bin.000003',master_log_pos=107,master_ssl=1,master_ssl_ca='/usr/local/mysql/ssl/cacert.pem',master_ssl_cert='/usr/local/mysql/ssl/mysql.crt',master_ssl_key='/usr/local/mysql/ssl/mysql.key';  
  38. mysql> show global variables like '%ssl%';  
  39. +---------------+---------------------------------+  
  40. | Variable_name | Value                           |  
  41. +---------------+---------------------------------+  
  42. | have_openssl  | YES                             |  
  43. | have_ssl      | YES                             |  
  44. | ssl_ca        | /usr/local/mysql/ssl/cacert.pem |  
  45. | ssl_capath    |                                 |  
  46. | ssl_cert      | /usr/local/mysql/ssl/mysql.crt  |  
  47. | ssl_cipher    |                                 |  
  48. | ssl_key       | /usr/local/mysql/ssl/mysql.key  |  
  49. +---------------+---------------------------------+  
  50. msyql> show slave status\G  
  51. 输出的信息有:  
  52. Slave_IO_Running: Yes  
  53. Slave_SQL_Running: Yes  
  54. Master_SSL_Allowed: Yes  
  55. 说明,基于SSL的配置已经成功  
  56.  

 

4.5 验证是否使用了SSL加密

 
  
  1. Master上添加ssl的复制用户  
  2. mysql> grant replication slave,replication client on *.* to ssluser@'172.16.220.12' identified by 'redhat' require ssl;  
  3. mysql> flush privileges;  
  4.  
  5. Slave测试  
  6.  
  7. # /usr/local/mysql/bin/mysql --ssl-ca=/usr/local/mysql/ssl/cacert.pem --ssl-cert=/usr/local/mysql/ssl/mysql.crt --ssl-key=/usr/local/mysql/ssl/mysql.key -ussluser -h 172.16.220.11 -p  
  8. Enter password  
  9. mysql>\s  
  10. 输出信息中有这么一项  
  11. SSL:   Cipher in use is DHE-RSA-AES256-SHA  
  12.  
  13. 说明是加密连接了  
  14.  

 


操作的过程中也遇到了诸多的问题: 


 

 
  
  1. 问题  
  2. 1、在2.2步骤中  
  3. mysql>show slave status\G 时遇到这样的问题  
  4.  Slave_IO_Running: No  
  5.  Slave_SQL_Running: Yes  
  6. 原因:退出了mysql,而后登陆再执行的这条命令,就出现了这样的问题;不退出mysql,直接执行,就不会有问题了