一个应用系统是否高可用,整个系统的效率是否达到预期,往往会受到各种制约,比如:运行环境、网络环境、数据吞吐量金额等;作为一个通用的大型应用系统,我们希望提高整个系统的效率。在大多数情况下,我们会优化我们的后端数据库来提高我们整个系统的数据吞吐量。如果我们的后端使用关系型数据,我们可能会想到两种解决方案,一种是更换非关系型数据库,成本比较高,而且会涉及到数据迁移和程序代码修改;另一个是通过数据库集群来横向和纵向扩展我们的数据库。该方案实现简单,程序代码修改量较小;根据MySQL官方文档,MySQL支持集群配置的读写分离,MySQL提供了两种读写分离的数据复制类型;一种是二进制日志文件形式的数据复制,另一种是全局事务标识符(GTID)。下面通过一个小实验,看看基于MySQL数据的二进制日志数据复制的主从集群是如何实现的。OS环境:CentOS7软件环境:Docker(最新版),MySQL:latestimage我们通过Docker容器dockerpullmysql[root@dev01~]#dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmysqllatest62a9f311b99c4weeksago445MB快速搭建了两台MySQL数据库服务器,可以看到我们拉取了最新的MySQLDockerContainer,在为了在本地环境中启动两个不同的MySQLDocker容器,我们需要通过修改容器的配置文件来改变MySQL的配置;首先,我们修改MySQLMaster(主库)的容器配置文件:1.创建Master数据库的配置文件vimaster.cnf[mysqld]#masterserveridserver-id=1#binloglog_bin=mysql-master-binserver-id,在MySQL集群数据库中,log_bin这个参数必须是唯一的,MySQL使用从二进制日志文件复制过来的文件名2.复制配置文件到MySQLDocker容器dockerrun--namemysql-eMYSQL_ROOT_PASSWORD=root-dmysqldockercpmaster.cnffdb98bbd52b6:/etc/mysql/conf.d3.提交修改后的Docker容器dockercommit-m"addmasterconfigurefile"fdb98bbd52b6mysql:master[root@dev01~]#dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmysqlmaster345465966cb53hoursago445MBcommit-m是修改容器后提交的信息,类似Git提交;fdb98bbd52b6是刚刚修改的容器;mysql:master是我们标记修改容器master的标签接下来我们修改MySQLSlave(Fromthedatabase)容器配置文件一,创建Slave数据库的配置文件vislave.cnf[mysqld]#slaveserveridserver-id=2#binloglog_bin=mysql-slave-binrelay_log=mysql-relay-binlog_slave_updates=1read_only=1server-id为从库的ID,该参数在MySQL集群中必须唯一;log_bin如果slave是其他slave的master,必须设置bin_log,这里我们暂时开启;relay_log配置中继日志log_slave_updates表示slave将复制事件写入自己的二进制日志(后面会看到它的用处);read_only尽量使用read_only,它可以防止更改数据(特殊线程除外);二、复制配置文件到容器dockerrun--namemysql-eMYSQL_ROOT_PASSWORD=root-dmysqldockercpslave.cnf8ee82abb2e91:/etc/mysql/conf.d三、提交修改后的Docker容器dockercommit-m"addslaveconfigurefile"8ee82abb2e91mysql:slave[root@dev01~]#dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmysqlslave3a53cd39ee454hoursago445MB至此,需要的两个MySQL容器已经修改完成,保存在我们本地的容器仓库中。接下来,我们启动刚才修改的两个容器,进行后续的配置。启动Master数据库dockerrun--namemaster-eMYSQL_ROOT_PASSWORD=root-dmysql:master--namemaster是我们启动的容器名称;mysql:master是我们刚刚修改提交到本地的Docker镜像默认数据库root密码设置为root二、启动Slave数据库在主容器和从容器之间,我们添加了--line选项来连接接收到我们刚刚启动的master容器;--nameslave是我们启动的容器的名称;mysql:slave是我们刚刚修改提交到本地的Docker镜像;默认数据库root密码设置为root三、进入master容器中,通过mysql命令dockerexec-itmaster/bin/bashmysql-uroot-proot进入数据库4.在master数据库中创建一个用于复制数据的账户,并给账号对应权限createuser'repl'@'%'identifiedby'repl-pwd';grantreplicationslaveon*.*to'repl'@'%';flushprivileges;五、查看master数据库状态mysql>showmasterstatus;+----------------------------+------------+------------+------------------+-------------------+|File|Position|Binlog_Do_DB|Binlog_Ignore_DB|Executed_Gtid_Set|+--------------------------+----------+------------+-----------------+------------------+|mysql-master-bin.000003|2743||||+----------------------+--------+------------+------------------+----------------+1rowinset(0.00sec)六、进入slave容器,通过mysql命令dockerexec-itsslave/bin/bashmysql-uroot-proot进入数据库七、配置slave,点master数据库到刚刚配置的master数据库节点,并启动slavechangemastertomaster_host='master',master_user='repl',master_password='repl-pwd',master_log_file='mysql-master-bin.000003',master_log_pos=0;startslave;八,查看slave数据库状态mysql>showslavestatus\G******************************1.row***************************Slave_IO_State:Master_Host:masterMaster_User:replMaster_Port:3306Connect_Retry:60Master_Log_File:mysql-master-bin.000003Read_Master_Log_Pos:4Relay_Log_File:mysql-relay-bin.000001Relay_Log_Pos:4Relay_Master_Log_File:mysql-master-bin.000003Slave_IO_Running:NoSlave_SQL_Running:NoReplicate_Do_DB:Replicate_Ignore_DB:Replicate_Do_Table:Replicate_Ignore_Table:Replicate_Wild_Do_Table:Replicate_Wild_Ignore_Table:Last_Errno:0Last_Error:Skip_Counter:0Exec_Master_Log_Pos:4Relay_Log_Space:155Until_Condition:NoneUntil_Log_File:Until_Log_Pos:0Master_SSL_Allowed:NoMaster_SSL_CA_File:Master_SSL_CA_Path:Master_SSL_Cert:Master_SSL_Cipher:Master_SSL_Key:Seconds_Behind_Master:NULLMaster_SSL_Verify_Server_Cert:NoLast_IO_Errno:2061Last_IO_Error:errorconnectingtomaster'repl@master:3306'-retry-time:60retries:1message:Authenticationplugin'caching_sha2_password'reportederror:Authenticationrequiressecureconnection.Last_SQL_Errno:0Last_SQL_Error:Replicate_Ignore_Server_Ids:Master_Server_Id:0Master_UUID:Master_Info_File:mysql.slave_master_infoSQL_Delay:0SQL_Remaining_Delay:NULLSlave_SQL_Running_State:Master_Retry_Count:86400Master_Bind:Last_IO_Error_Timestamp:19091206:06:14Last_SQL_Error_Timestamp:Master_SSL_Crl:Master_SSL_Crlpath:Retrieved_Gtid_Set:Executed_Gtid_Set:Auto_Position:0Replicate_Rewrite_DB:Channel_Name:Master_TLS_Version:Master_public_key_path:Get_master_public_key:0Network_Namespace:1rowinset(0.00sec)由于MySQL最新版本更改了密码验证插件,提高安全性,这里还是使用之前的密码验证插件,我们是在master数据库中使用如下命令修改用户alteruser'repl'@'%'identifiedby'repl-pwd'passwordexpirenever;alteruser'repl'@'%'identifiedwithmysql_native_passwordby'repl-pwd';刷新权限;查看slave状态mysql>showslavestatus\G******************************1.row***************************Slave_IO_State:WaitingformastertosendeventMaster_Host:masterMaster_User:replMaster_Port:3306Connect_Retry:60Master_Log_File:mysql-master-bin.000003Read_Master_Log_Pos:2743Relay_Log_File:mysql-relay-bin.000002Relay_Log_Pos:2971Relay_Master_Log_File:mysql-master-bin.000003Slave_IO_Running:YesSlave_SQL_Running:YesReplicate_Do_DB:Replicate_Ignore_DB:Replicate_Do_Table:Replicate_Ignore_Table:Replicate_Wild_Do_Table:Replicate_Wild_Ignore_Table:Last_Errno:0Last_Error:Skip_Counter:0Exec_Master_Log_Pos:2743Relay_Log_Space:3179Until_Condition:NoneUntil_Log_File:Until_Log_Pos:0Master_SSL_Allowed:NoMaster_SSL_CA_File:Master_SSL_CA_Path:Master_SSL_Cert:Master_SSL_Cipher:Master_SSL_Key:Seconds_Behind_Master:0Master_SSL_Verify_Server_Cert:NoLast_IO_Errno:0Last_IO_Error:Last_SQL_Errno:0Last_SQL_Error:Replicate_Ignore_Server_Ids:Master_Server_Id:1Master_UUID:f6e8062e-d521-11e9-9009-0242ac110008Master_Info_File:mysql.slave_master_infoSQL_Delay:0SQL_Remaining_Delay:NULLSlave_SQL_Running_State:Slavehasreadallrelaylog;waitingformoreupdatesMaster_Retry_Count:86400Master_Bind:Last_IO_Error_Timestamp:Last_SQL_Error_Timestamp:Master_SSL_Crl:Master_SSL_Crlpath:Retrieved_Gtid_Set:Executed_Gtid_Set:Auto_Position:0Replicate_Rewrite_DB:Channel_Name:Master_TLS_Version:Master_public_key_path:Get_master_public_key:0Network_Namespace:1rowinset(0.00sec)我们主要查看Slave_IO_Running和Slave_SQL_Running,表示我们的slave数据库节点已成功连接到我们的主数据库节点十、验证,我们在master数据库节点上创建一个空数据库mysql>createdatabasedata;QueryOK,1rowaffected(0.10sec)mysql>showdatabases;+---------------------+|数据库|+--------------------+|数据||information_schema||mysql||performance_schema||sys|+-------------------+5rowsinset(0.01sec)十一、验证slave,检查master数据库节点上刚刚创建的数据库是否同步到slave数据节点mysql>showdatabases;+--------------------+|数据库|+--------------------+|数据||information_schema||mysql||performance_schema||sys|+----------------+5rowsinset(0.01sec)可以看到我们刚刚在master数据库节点上创建的数据库已经synchronized到我们的slave数据库节点,master和slave的数据库数据已经一致了。在上面的实验中,我们选择了两个数据库(一主一从)。在实际应用中,根据我们的应用场景,也可以选择从数据库节点作为主数据库。此时从数据库节点可能是1到N。参考:https://dev.mysql.com/doc/refman/5.7/en/replication.html
