1.1 产生背景
随着系统数据量的不断增加,由单台Mysql作为独立数据库无法满足业务需求,无论是在安全性(数据备份),高可用性(容错能力)及高并发(负载均衡)等各个方面。
因此,针对查询为主系统(select查询),可以采用主从复制策略。通过Mysql的主从复制(Master-Slave)来同步数据,再通过读写分离来提升数据库的并发负载能力,这样就可以得到更好的客户端响应时间。
1.2 工作原理
主从复制通过三个过程实现,其中一个发生在主服务器上,另外两个发生在从服务器上。
1.主服务器将用户对数据库的更新操作以二进制文件保存到BinaryLog日志文件中,然后由BinlogDump线程将BinaryLog日志文件传输给从服务器。
2.从服务器通过一个I/O线程将主服务器的BinaryLog日志文件中的更新操作复制到一个叫RelayLog的中继日志文件中。
3.从服务器通过另一个SQL线程将RelayLog中继日志文件中的操作依次在本地执行,从而实现主从之间数据的同步。
三个线程
1.BinLog Dump线程
BinLog Dump线程运行在主服务器上,主要工作是把BinaryLog二进制文件的数据发送到从服务器。使用SHOWPROCESSLIST语句查看该线程状态。
2.I/O线程
从服务器执行STARTSLAVE语句后,创建一个I/O线程。此线程运行在从服务器上,与主服务器建立连接,然后向主服务器发送更新请求。之后,I/O线程将主服务器的BinLogDump线程发送的更新操作,复制到本地RelayLog日志文件中。
3.SQL线程
SQL线程运行在从服务器上,主要工作是读取RelayLog日志文件中的更新操作,将这些操作依次执行,从而使主从服务器数据得到同步。
当有多台从服务器时,主服务器为每个当前连接的从服务器创建一个线程,每个从服务器有自己的I/O线程和SQL线程。关于这三个线程运行过程中可能出现的一些状态,可以参考Mysql参考手册:6.3.复制实施细节
2.1 Mysql兼容性
Mysql5.x与4.x版本使用的日志文件格式大大不同,所以主从库最好采用相同版本,如果达不到要求,必须保证主服务器版本不高于从服务器版本。
2.2 配置Master
在主服务器上为从服务器设置一个连接账户,授予REPLICATIONSLAVE权限。假定你想要创建用户名为slave1的一个账户,从服务器可以使用该账户从你的域内的任何主机使用密码passwd来访问主服务器。要创建该账户,可使用GRANT语句:
1 2 | mysql> GRANT REPLICATION SLAVEON *.*
-> TO 'slave1' @ '%' IDENTIFIED BY 'passwd' ; |
接着打开my.ini(my.cnf)配置文件,指定log-bin及唯一的serverid。
1 2 3 | [mysqld] log-bin = mysql-bin server-id = 1 |
重启mysql服务器,运行SHOWMASTER STATUS查看
File表示主服务器正在使用的binlog文件,如果是第一次配置,则此处显示为mysql-bin.000001,并且每次重启服务器都会递增生成新文件;Position的值与binlog文件的大小相同,表示下一个被记录事件的位置;Binlog_Ignore_DB与Binlog_Do_DB是主服务器控制写入binlog文件内容的过滤选项,默认为空,表示不做任何过滤。
File和Position两列指明从服务器将从哪个binlog文件中复制,以及复制的开始位置,也是用来配置从服务器的参数。
2.3 配置Slave
从服务器的配置与主服务器类似,必须提供唯一的server-id(不能跟主服务器ID相同),配置完成后重启服务器。
1 2 3 | [mysqld] log-bin = mysql-bin server-id = 2 |
接下来需要使用CHANGEMASTER TO语句指定主服务器的信息。
1 2 3 4 5 | CHANGE MASTER TOMASTER_HOST=’192.168.191.1’, MASTER_USER=’slave1’, MASTER_PASSWORD=’passwd’, MASTER_LOG_FILE=’mysql-bin.000005’, MASTER_LOG_POS=825 |
使用SHOW SLAVESTATUS语句查看从服务器的设置是否正确
2.4 运行操作
1.在从服务器上执行STARTSLAVE开始复制:
1 | mysql > START SLAVE; |
运行SHOWSLAVE STATUS查看输出结果:
从结果看出,从服务器的I/O线程和SQL线程都已经成功开始运行。
在主服务器上运行SHOWPROCESSLIST查看BinlogDump进程:
在从服务器上执行SHOWPROCESSLIST查看:
2.row为I/O线程,3.row为SQL线程。
2. 测试主从复制
在主服务器上执行数据库的更新操作:
1 2 3 4 5 6 7 8 | mysql> create database ms_test; Query OK, 1 row affected (0.00 sec) mysql> use ms_test; Database changed mysql> create table test(idint); Query OK, 0 rows affected (0.25sec) mysql> insert into testvalues(1), (2), (3); Query OK, 3 rows affected (0.08sec) |
在从服务器上,执行查询,可以看到数据已经成功更新到了从服务器上。
3. 读写分离性能提升测试
由于网络、服务器等的环境差异,以及测试工具的局限性,无法做严格的测试,所以此处使用apache的ab工具测试在高并发情况下,使用读写分离对主库执行更新操作的效率变化。
1.准备好测试代码和测试工具
采用表复制的方法,预先向test表插入300W+条数据,数据分散为1,2,3.
1 | insert into test select * from test; |
ms.php连接主库执行插入操作。
1 2 3 | $conn_m = new Mysqli( '192.168.191.1' , 'root' , '123456' , 'ms_test' ); $conn_m ->query( 'INSERTINTO `test` values(' . rand(1, 1000) . ')' ); $conn_m ->close(); |
ms2.php连接主库执行耗时查询.
1 2 3 | $conn_s = new Mysqli( '192.168.191.1, ' root ', ' 123456 ', ' ms_test'); $conn_s ->query( 'SELECTcount(*) FROM `test` WHERE id=' . $i ); $conn_s ->close(); |
2.同时启动两个ab进程,测试同时连接主库执行查询和更新。
1 | ab.exe-n2000 -c200 http: //localhost/ms2.php(请求2000次,每次并发200个) |
1 | ab.exe-n100 -c10 http: //localhost/ms2.php(请求100次,每次并发10个) |
3.将ms2.php的连接指向从库。
1 | $conn_s = new Mysqli( '192.168.191.2’, ' root ', ' 123456 ', ' ms_test'); |
1 | ab.exe-n2000 -c200 http: //localhost/ms2.php(请求2000次,每次并发200个) |
1 | ab.exe-n100 -c10 http: //localhost/ms2.php(请求100次,每次并发10个) |
可以看到在查询时间无太大变化的情况下(并发的更新操作较少),更新时间是有了较快的提升。
4. 总结
Mysql主从复制可以较好的解决高并发情况下数据库锁的性能瓶颈,不过在数据及时同步方面稍显不足,如果主服务器宕机,会导致从服务器不能及时更新到数据,这种情况下可以考虑半同步复制和主主复制。
架构在演变,技术在更新,唯有保持一颗永不懈怠之心,才能跟上时代的步伐。
- 正在加载用户留言,请稍后~