Mysql Replication运维与实施(三)
2017-12-12 11:45
218 查看
十三、Replication部署准备
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
十四、架构过程与要求
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
十五、要点描述
十六、运维操作
Java代码 收藏代码
Java代码 收藏代码
十七、Failover
Java代码 收藏代码
Java代码 收藏代码
十八、Replication模式问题
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
Java代码 收藏代码
我们在三台机器上构建Replication架构,使用MySQL 5.7.10: 1)三个mysql实例分别为“mysql-1”、“mysql-2”、“mysql-3” 2)IP分别为“192.168.1.100”、“192.168.1.101”、“192.168.1.102”,其中mysql-1为初始master。 3)mysql安装目录为“/usr/local/mysql”,即“basedir”。 4)配置文件为my.cnf,放置在安装目录下。 5)他们的datadir为“/data/mysql”,在构建replicaiton架构之前,我们首先准备实例化三个mysql实例: 1、简要配置文件
Java代码 收藏代码
[mysqld] server_id=10 bind_address=0.0.0.0 #绑定端口 port=3306 socket=/tmp/mysql.socket #mysql的安装路径 basedir=/usr/local/mysql #数据文件保存的目录 datadir=/data/mysql #binlog log_bin=my-binlog binlog_checksum=CRC32 binlog_format=MIXED sync_binlog=1 binlog_row_image=FULL max_binlog_size=2G binlog_order_commits=1 ##binlog保存的时间,单位“天” ##自动删除早期的binlog文件 expire_logs_days=180 #开启GTID,强烈建议开启 gtid_mode=ON enforce_gtid_consistency=ON #replication模式下选项 relay_log_purge=1 ##当前实例的IP地址 report_host=192.168.1.100 ##当前实例的端口 report_port=3306 ##replication的用户账号名 report_user=rpl_sys ##slave上是否将执行的变更操作写入binlog log_slave_updates=0 master_verify_checksum=1 relay_log=relay-bin relay_log_info_repository=TABLE sync_relay_log=1 master_info_repository=TABLE #slave与master链接超时时间 slave_net_timeout=3600 ##建议为database个数 + 1,或者简单为2 slave_parallel_workers=2 slave_sql_verify_checksum=1 配置文件内容在三个节点上基本保持一致,全部配置信息请参考【MySQL配置】,如果使用“伪分布式”部署,那么需要将datadir等参数调整以防止冲突。 2、依次初始化三个mysql:
Java代码 收藏代码
#mysql >sudo ./mysqld --datadir=/data/mysql --initialize --user=mysql 3、用户权限: 因为“mysql”这个系统默认的数据库,通常不能(严格来说绝对不能)被replication;因此,我们在master上创建的用户权限,也不会被replication到slaves上,为了便于管理,我们需要在每个节点上都增加如下用户: 1)root,最高级权限 2)test,一个模拟的用户,具有指定数据库的所有操作权限(需要master与slaves上必须严格一致,否则application无法对reads操作进行load balance) 3)rpl_sys,用于master与slaves之间replication的特殊用户 按照如下指令依次在三个实例上执行:
Java代码 收藏代码
##以无权限验证模式,启动mysql >sudo ./mysqld_safe --defaults-file=../my.cnf --skip-grant-tables &
Java代码 收藏代码
#访问mysql >./mysql --host=127.0.0.1 --port=3306 #初始化root密码 >use mysql; >UPDATE user SET authentication_string = PASSWORD('root'), password_expired = 'N' WHERE User = 'root' AND Host = 'localhost'; >FLUSH PRIVILEGES;
Java代码 收藏代码
#关闭mysql,并以授权认证的方式重新启动,并增加两个用户 >./mysqladmin --host=127.0.0.1 --port=3306 shutdown; #重新启动 >./mysqld_safe --defaults-file=../my.cnf & #使用root用户登录mysql >./mysql --host=127.0.0.1 --port=3306 -u root -p >#输入密码登录 >CREATE DATABASE mydb;##貌似需要首先创建DB,才能授权 >GRANT ALL ON mydb.* TO 'test'@'%' IDENTIFIED BY 'test'; #新增一个rpl_sys,用于在replication模式中可以复制binlog数据 >GRANT REPLICATION SLAVE ON *.* TO 'rpl_sys'@'%' IDENTIFIED BY 'replication'; >FLUSH PRIVILEGES; 在初始化root密码之后,关闭mysql需要指定密码:
Java代码 收藏代码
>./mysqladmin --host=127.0.0.1 --port=3306 -u root -p shutdown; 最终我们达成,三个mysql实例持有相同的用户授权信息。
十四、架构过程与要求
1、架构模式 本文使用三个mysql实例构建replicaiton,全部采用“半同步”模式,我们暂且选定mysql-1为master,其他两个实例为slaves。为了避免一些不必要的错误或者bug,我们在任何时候都需要尽可能保证,master与slaves上的配置文件基本一致,且master和slaves的数据库引擎设置和模式一致,而且不会在slaves上直接变更数据或者修改table的引擎类型、字段类型等。
Java代码 收藏代码
#常用架构方式 |---------| |---------| | master |------semisync----| slave | |---------| |---------| | (2~5个) (任意多个) | |---------| |---------| -------semisync----| slave |-----aysnc----| slave | |---------| |---------| 2、安装semi插件: semi插件有2个,分别为“semisync_master”、“semisync_slave”,默认情况下“plugin_dir”为“<basedir>/lib/plugin”,我们可以查看这个目录下是否有这两个插件,我们则在三个mysql实例上均安装此插件:
Java代码 收藏代码
>INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; >INSTALL PLUGIN rpl_semi_sync_SLAVE SONAME 'semisync_slave.so'; >use mysql; >select * from plugin; 需要在三个节点上都执行上述命令,无论master还是slaves;即使你的环境为“伪分布式”,仍然需要在每个实例上执行,插件数据将会写入各自的“mysql”数据库中。 3、设定semisync全局变量: 在三个mysql实例上均执行如下命令,设置semisync变量:
Java代码 收藏代码
#只在master上执行, #或者为了便于Failover,可以在所有节点都执行 >SET GLOBAL rpl_semi_sync_master_enabled=ON; #可以只在slave上执行 >SET GLOBAL rpl_semi_sync_slave_enabled=ON; 如果你觉得使用全局变量的方式可读性不强,也可以在配置文件中增加如下配置:
Java代码 收藏代码
rpl_semi_sync_master_enabled=1 rpl_semi_sync_master_timeout=10000 rpl_semi_sync_master_wait_no_slave=0 rpl_semi_sync_slave_enabled=1 replicate_ignore_db=mysql 修改配置文件后,需要重启mysql实例。 4、备份Master数据(可选) 为了测试,我们首先在在master上的“mydb”数据库中插入一些测试数据,来模拟“单点架构扩展成replicaiton架构”的场景。 1)锁定数据库
Java代码 收藏代码
>./mysql -h 127.0.0.1 -P3306 -u root -p; >FLUSH TABLES WITH READ LOCK; >SET GLOBAL read_only=1; 2)dump数据
Java代码 收藏代码
>./mysqldump -h 127.0.0.1 -P3306 -u root -p -B mydb>/tmp/mydb.sql 3)释放锁
Java代码 收藏代码
>UNLOCK TABLES; >SET GLOBAL read_only=0; 5、将数据导入到slaves(可选)
Java代码 收藏代码
#首先把master上的mydb.sql文件同步到各个slaves #在slave上逐个执行,不过需要首先启动slave实例 >mysql -h 127.0.0.1 -P3306 -u root -p >/tmp/mydb.sql #登陆mysql >show databases; #将会列出mydb数据库 6、初始化replication 到目前为止,我们已经将master和slaves单点准备完毕,且master上先前的数据也已经导入到slaves中,接下来我们将初始化replicaiton集群:
Java代码 收藏代码
#slaves上执行 >SET GLOBAL read_only=1; >CHANGE MASTER TO MASTER_HOST='192.168.1.100',MASTER_PORT=3306, MASTER_USER='rpl_sys', MASTER_PASSWORD='replication', MASTER_AUTO_POSITION=1; >START SLAVE; 千万别忘了最后执行“START SLAVE”,否则将无法执行replicaiton。在一个slave上执行“START SLAVE”之后,即使此slave 重启,它仍然保持自己的“slave”角色,且不需要再次执行“CHARGE MASTER TO”,因为这些信息已经被保存在内部数据库中。我们可以使用“STOP SLAVE”在停止replicaiton,此后slave可以作为master或者执行“CHARGE MASTER TO”跟进其他的master。 我们可以在master上执行“SHOW SLAVE HOSTS”指令,查看slaves列表:
Java代码 收藏代码
mysql> SHOW SLAVE HOSTS; +-----------+---------+------+-----------+--------------------------------------+ | Server_id | Host | Port | Master_id | Slave_UUID | +-----------+---------+------+-----------+--------------------------------------+ | 11 | mysql-2 | 3306 | 10 | 4694924e-b818-11e5-b9ad-ccddf019aa0c | | 12 | mysql-3 | 3306 | 10 | 26baac30-b820-11e5-ad9c-933c718547d4 | +-----------+---------+------+-----------+--------------------------------------+ 2 rows in set (0.00 sec) 7、数据测试 我们可以在master上写入数据一些数据测试,然后在slaves上查看,发现数据已经正确的被replication,目前架构基本达成了我们的需要。
十五、要点描述
1、配置部分 1)binlog_format:replication时使用的格式,为了数据一致性和性能,我们选用“MIXED”模式,让mysql在合适的时机选用“row”、“statement”模式。在后续的版本中,我们已经不建议使用“statement”模式。 2)log_slave_updates:slave是否将变更操作也写入自己的binlog,如果此slave后端没有slave跟进,则建议关闭。 3)gtid_mode,enforce_gtid_consistency:这两个参数需要配合,同时开启“ON”,在replicaiton模式中GTID特性强烈建议开启。 4)report_port,report_host,report_user:需要在slave上配置,主要在master上使用“SHOW SLAVE HOSTS”查看slaves列表时展示。 5)slave_parallel_workers:是否开启并发replication,默认为“0”表示不开启,此时slave只有一个SQL线程,用于读取relay log并执行statements;如果此值大于0,表示开启worker线程的个数,此时SQL线程只负责从relay log读取statements,然后转发给workers线程,有worker线程负责执行。通常workers线程的个数与database的个数一样,或者简单设置为2。 6)binlog_checksum,master_verify_checksum,slave_sql_verify_checksum:建议开启,对binlog开启校验和验证。 7)server_id:这个配置项必备,每个节点都不同,数字类型。 8)sync_binlog=1、innodb_flush_log_at_trx_commit=1,这两个参数配合用于控制binlog刷新磁盘的时机,“1”表示每次事务提交都立即刷新磁盘,效率较低但是可以尽可能的保证数据完整性;如果你的数据库是一些社交内容的数据(而非订单数据),可以为了考虑并发能力,而稍微降低binlog刷新频率。 2、数据与replication:首先“mysql”这个特殊的系统数据库是不能被replication的,我们需要在配置文件中通过“replicate_ignore_db=mysql”来忽略;然后在master上授权一个具有“REPLICATION SLAVE”权限的用户,比如本文中的“rpl_sys”用户,slaves可以使用此用户与master建立链接并进行数据同步;如果你希望Failover的话,需要在所有的节点上都添加此用户,而且所有的节点上的配置把包括root用户都应该一样,因为任何节点都有可能被提升为master。 3、GTID是一个新的特性,它保证了master事务在replication的一致性、有序性,可以有效的简化replication的复杂度和人工干预,我们应该开启此特性。(无论是修改MyISAM,还是InnoDB,无论是否手动开始事务还是自动提交的事务,均会生成GTID,每个事务一个ID,自动提交模式下每个操作一个GTID) 4、多线程replication,即“slave_parallel_workers”控制,这个是个需要权衡的配置项,如果你的系统中writes操作比较密集、databases个数较多、大事务较多,那么你应该考虑开启此参数来提高relay log的执行效率,线程数不建议特别多,通常设置为“2”或者根据和databases的个数一致。 5、semisync特性,即“半同步”也是新特性,官方推荐使用特性以降低数据丢失的可能性,半同步的核心就是在master与slaves之间有一次同步 + 消息确认的过程,会降低master事务并发提交,但是它保证master与slave之间binlog复制的同步能力。通常,我们将集群中“大多数”slaves开启半同步,部分slaves仍然采用异步同步,这是在数据完整性和性能上做权衡。 6、在从master上dump数据时,一定要首先对master实例进行LOCK,我们期望dump的数据是完整的(而非变动、增量的),即使用“FLUSH TABLES WITH READ LOCK;”,此指令将导致binlog、数据文件立即刷新磁盘,且阻止writes操作提交,在dump结束后,我们通过“UNLOCK TABLES”释放锁。上文中已经提到“mysql”这个系统数据通常不能参与replicaiton,所以我们也不能将“mysql”数据dump到其他slaves中。 7、关于是否在slave上开启read_only参数,存在一些权衡,按照规范,我们应该在slave上开启read_only,以避免slave上的数据被客户端意外变更,而导致replication集群中数据无法对齐的问题。即slave上的数据是可以直接修改的。 此外slave原则上,仍然可以创建其他databases,这些databases与replication master没有关系,application可以直接操作slaves并修改数据。为了避免这种纠缠不清的问题,我们建议slaves统一开启“read_only”。read_only并不会影响replication进程对数据的变更,也不会影响SUPER用户对“系统”状态的变更(比如SET GLOBAL ...) 8、在普通的replication模式下,通常master失效后,优先恢复master,而不是failover到其他slaves上。 如果master无法恢复: 1)将某个slave提升为master,这种方式下可能需要调整客户端Connector的URL配置(因为jdbc没有角色感知的功能,需要开发额外的代码)。 2)将slave提升为master,且此slave也使用master的IP(VIP方式,或者硬性路由),此后再重新搭建一个slave即可(可以使用原slave的IP),此种方式需要修改客户端Connector URL配置。
十六、运维操作
1、mysqldump脚本:
Java代码 收藏代码
./mysqldump -h 127.0.0.1 -P 3306 -u root -p -B mydb >/home/data/mydb.sql 这是mysqldump脚本常用的模式,它还有几个有用的参数选项,全部参数请参考【mysqldump】: 1)--add-drop-database:默认情况下,dump文件中会写入“CREATE DATABASE”语句,如果slave上已经有了此database,在导入数据时可能会发生错误;此选项,就是在“CREATE DATABASE”语句之前首先添加一行“DROP DATABASE”,这样在导入数据时不会发生冲突。 2)--no-create-db:简写为“-n”,是否添加“CREATE DATABASE”语句。 3)--ignore-table=<db>.<table>:指定忽略的数据库表,此参数可以重复出现多次。 4)--no-data:简写“-d”,只写入“CREATE TABLE”不写入表数据,即只dump表结构。 5)--default-character-set=<character-set>:使用的字符集,默认为utf8。 6)--all-databases:简写“-A”,dump所有的数据库。 7)--databases:简写“-B”,指定需要dumpl的数据库列表,以空格分隔。 2、show processlist:我们可以在master或者slave上执行“SHOW PROCESSLIST”查看与replication有关的进程。 3、show slave hosts:在master执行此命令,用于查看跟进master的所有slaves列表以及相应的report信息。 4、show master status:用于查看master的状态,主要是查看master上GTID的状况。 5、show slave status:查看slave的状态,涉及到的内容很多,【参见详情】。我们需要关注两项:Retrieved_Gtid_Set 和 Executed_Gtid_Set,前者表示IO线程已经读取的GTID的范围,后者表示SQL线程已经执行的GTID的范围,我们可以根据这两个参数来判断slave与master上数据的距离。
Java代码 收藏代码
mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 127.0.0.1 Master_User: rpl_sys Master_Port: 3306 Connect_Retry: 60 Master_Log_File: my-binlog.000008 ##IO线程已读取的master binlog位置 ##如果没有开启GTID,在“CHANGE MASTER TO”中 ##可以使用此POS Read_Master_Log_Pos: 2403 Relay_Log_File: relay-bin.000006 Relay_Log_Pos: 789 Relay_Master_Log_File: my-binlog.000008 ##slave IO线程状态 Slave_IO_Running: Yes ##slave SQL线程状态 Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: mysql Replicate_Do_Table: Replicate_Ignore_Table: ... ##SQL线程已执行的binlog位置 Exec_Master_Log_Pos: 2403 Relay_Log_Space: 1030 ... ##slave与master的步差 Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No ... Replicate_Ignore_Server_Ids: Master_Server_Id: 10 Master_UUID: 8a542af6-b79d-11e5-b2cf-c699ad96e9cc Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates ... ##GTID模式下 ##已经从master读取的GTID范围 Retrieved_Gtid_Set: 8a542af6-b79d-11e5-b2cf-c699ad96e9cc:1-7 ##SQL线程已经执行的GTI范围 Executed_Gtid_Set: 8a542af6-b79d-11e5-b2cf-c699ad96e9cc:1-7 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 6、show status like “rpl_semi_sync%”:用于查看semisync的各项变量的值。 7、slave有2种线程类型:IO线程、SQL线程,可以通过“START(或STOP) SLAVE IO_THREAD”,“START(或STOP) SLAVE SQL_THREAD”对两种线程单独控制。IO线程就是与master建立链接读取binlog、写入relay log的线程,通常一个slave只有一个;SQL线程,负责从relay log中读取变更操作并执行语句,默认为单线程,我们可以通过“slave_parallel_workers”来开启多线程方式。
十七、Failover
如果master失效或者人工干预,可以将slave提升为master;在实际环境中,如果master失效,我们建议优先将master重新上线,而不是急于Failover,除非master无法短时间内恢复。因为在普通的replication架构下,failover机制尚不是非常健全,而且还涉及到客户端Connection相关策略问题。 1、终止Master节点(人工干预): 如果希望将一个活跃的master节点角色迁移成slave,那么需要首先中断master的写服务:
Java代码 收藏代码
#在master上执行 >FLUSH TABLES WITH READ LOCK; >SET GLOBAL read_only=1; 2、将slave提升为master: 1)如果master已经失效,那么就需要将逐个查看slaves的状态,并确定一个数据最完整的slave(Retrieved_Gtid_Set范围最大的那个),并将其选定为master候选;且等待此slave数据复制完成之后,再切换成master,即“show slave status”中“Exec_Master_Log_Pos”=“Read_Master_Log_Pos”。 2)如果人工终止Master,如1、,master上终止writes服务之后,可以通过“show master status”查看当前master已经执行的GTIDs;当所有的slaves的“Retrieved_Gtid_Set”值与master相等时,再将此slave切换为master。 3、在所有的slaves执行(包括候选master候选):“STOP SLAVE”。在候选master上,还需要并关闭read_only。 4、在其他slaves上执行(新master除外):“CHANGE MASTER TO”指令,与新master跟进,然后执行“START SLAVE”。 5、如果是人工终止Master,别忘了释放锁。与1、对应。
Java代码 收藏代码
>UNLOCK TABLES; >SET GLOBAL read_only=0; 6、如果旧的master需要再次成为master,它首先需要与当前master跟进并保持数据完整(其实还需要将当前master处于read_only状态),然后在旧master上执行“RESET MASTER”,此指令会导致旧master上原有的binlog清除,以避免slaves跟进时带来问题。
十八、Replication模式问题
1、模式一致:在replicaiton架构中,Master与slaves核心配置项应该保持一致,所有的database的引擎保持一致,表结构保持一致等。我们不应该在replication架构中,人为将数据的模式修改为不同,比如手动修改slaves的引擎类型,将Innodb改为MyISAM,有可能你是基于“slaves上使用MyISAM引擎可以提供更好的read效率”考虑,但是这种调整将会导致很多意外的问题。 而且我们通常在slalves上设定全局的“read_only=1”以避免人为的、或者客户端意外的在slaves上修改数据。 2、限定binlog的数据库:我们可以在master端设定“binlog_do_db”、“binlog_ignore_db”配置项,来指定master端将那些数据库的操作写入binlog,以及忽略哪些数据库的binlog。默认情况下,所有的databases中的数据变更都将写入binlog。如果指定了“binlog_do_db”,那么binlog中只会写入相应数据库的操作日志;如果指定了“binlog_ignore_db”,那么此数据库的操作记录将不会被写入binlog。 不过,在SBR和RBR两种replication不同的格式下,binlog的写入行为有些不同,这一点需要非常小心。 binlog_do_db: 1)SBR:根据“默认”数据库(即USE指令选择)名来判断是否写入binlog,而不是根据updates的目标数据库判断,比如我们指定“binlog_do_db=sales”,下面两个SQL语句的binlog行为将是不同的:
Java代码 收藏代码
1、 > USE prices; > UPDATE sales.january SET amount = amount + 1000; 2、 >USE sales; >UPDATE prices.discounts SET percentage = percentage + 10; 通过“USE”选择的数据库为“默认数据库”,因为“binlog_do_db”值检测“默认数据库”是否匹配,而不关注实际的updates语句中的目标数据库(即跨数据库操作的),因此对于1、情况将不会写入binlog,但是2、会写入binlog。 2)RBR:基于row-based格式的binlog模式,binlog的写入似乎更加合乎逻辑,它不在单纯的只判断“默认数据库”,而是判断updates实际的目标数据库是否匹配,如果匹配则写入binlog,即使此时“默认数据库”不匹配。比如“binlog_do_db=sales”,上例中1、语句仍然会被写入binlog,但是2、语句尽管“默认数据库”为“sales”但是其updates的目标数据库不匹配,将不会被写入binlog。 binlog_ignore_db: 1)SBR:基本思路同上,即根据“默认数据库”来判断是否忽略此statements,比如“binlog_ignore_db=sales”,那么上例中2、语句将不会写入binlog(被忽略)。 2)RBR:思路同上,根据updates实际的目标数据库来判断是否忽略此statements,比如“binlog_ignore_db=sales”,那么上例中1、语句将不会写入binlog,而2、语句会被写入。 3、限定replicate数据库:binlog_do_db和binlog_ignore_db是在master端生效,那些写入binlog的内容将会被全权发送给slaves,当slave的SQL线程读取binlog变更操作后,slave还可以判断是否继续执行此变更操作,有两个配置项来决定“replicate_do_db”、“replicate_ignore_db”。它们基本思路同2、部分,请参看“binlog_do_db”、“binlog_ignore_db”。 4、log_slave_updates:本文一再强调,如果你的slave后端没有其他的slaves跟进,即二级slaves,那么建议关闭此选项。如果开启,那么slave的SQL线程在执行变更操作时也会写入binlog日志,在failover时,如果此slave被选举为master,其他slaves与它跟进时,其本地的binlog会再次发给其他slaves,那么也意味着其他slaves接收了2次相同的binlog内容。(GTID开启时应该不会接受2次,未测试!如果slave上开启了此特性,那么当次slave被提升为master后,需要执行一次“RESET MASTER”指令) 5、AUTO_INCREMENT:基于SBR的replication格式下,AUTO_INCREMENT、LAST_INSERT_ID()、TIMESTAMP的值都可以正确的被复制,但是需要注意如下几个问题(RBR不需要考虑): 1)Master与slaves的存储引擎必须一致,表的schema必须一致。即master和slave上AUTO_INCREMENT的字段必须一一对应。 2)如果slave端有trigger,且在trigger中修改了AUTO_INCREMENT的字段值,这种方式有可能导致replication下数据不一致问题。 3)如果是组合主键(composite primary key),那么AUTO_INCREMENT字段必须是组合主键的首个字段。(InnoDB) 4)对于“INSERT ... SELECT ...”语句,可能导致在master与slaves上执行时得到的数据顺序不同,连带导致AUTO_INCREMENT的值不同。所以,我们必须在SELECT语句中使用“ORDER BY”来完全保障顺序。 6、字符集:为了避免乱码,我们应该在master和slaves上配置相同的字符集类型,而且尽可能在create表时指定字符集,而不是使用默认字符集,这样可以避免replication过程中产生乱码。 7、NOW():这个函数,可能是我们用的最多的,表示当前系统的时间;在SBR模式下,大家肯定会疑惑,如果slave与master的时间不同步怎么办?会不会导致数据不一致?无论是SBR还是RBR,NOW()总是在解析时计算并替换成“TIMESTAMP”,所以在replication到slave端时已经是计算后的值,而不是NOW()语句。但是最大的问题是“time_zone”,因为timestamp的转换成日期时将会受到时区的影响,这也就要求master和slaves上必须配置相同的time_zone,而不是使用默认的系统时区。
Java代码 收藏代码
> SHOW VARIABLES LIKE '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | SYSTEM | +------------------+--------+ > SELECT @@GLOBAL.time_zone; 我们可以使用如下几种方式来设置time_zone:
Java代码 收藏代码
##配置文件中 default_time_zone=+8:00 ##全局变量 SET GLOBAL time_zone=+8:00
Java代码 收藏代码
#查看binlog内容 >./mysqlbinlog binlog.000001 ... SET TIMESTAMP=1453473604/*!*/; INSERT INTO test(created) value(now()) ... 注意time_zone值采用UTC格式,中国采用“+8:00”,可参考列表【timezone】 8、LIMIT:在SRB模式下,delete、updates、insert...select批量操作且使用了LIMIT时,如果操作不能有效限定特定的行(比如指定主键ID),那么将可能导致语句在slave与master上执行的结果不同,所以,对于上述语句,指定LIMIT的同时还要使用order by,以保证被操作的行是一致性的。(底层存储,大家都知道“holes”) 9、REPAIR:当MySQL实例异常中断后,或者希望对表进行repair,那么需要首先暂停所有slaves上的IO线程,即中断binlog复制。然后在master上执行“repair table”执行,这个过程会导致部分“不完整的行”被删除,但是这种删除是基于底层文件存储,而不会记录在binlog中;所以在repair结束之后,需要将master上相应table的frm、ibd文件数据copy到slaves上,并在master上执行“REST MASTER”。 (表空间优化指令“OPTIMIZE TABLE”则不需要上述过程,只需要相应的节点处于只读状态即可。) 10、系统数据库mysql:我们都知道,MySQL实例在初始化时会创建mysql数据库,这是一个系统数据库,mysql数据库中保存了当前实例的很多状态信息。在replication模式下,mysql数据库的数据变更仍然会被写入binlog,对于有些statements比如“GRANT”、“REVOKE”等将会以SBR格式写入binlog,进而同步给slaves。直观来说,如果你在master上新增了系统用户或者授权操作,也将会被同步给slaves,这种情况存在利弊,或许你希望这么做,但或许你不希望。所以,我们建议“mysql”数据库不能被replicate,在slaves端使用“replicate_ignore_db=mysql”来限定。 11、事务:最大的问题就在于一个事务中同时修改了非事务表和事务表,这种情况我们应该避免,将会导致replication模式下数据不一致问题。首先非事务性表的修改是立即生效,而且无法rollback;当事务中,穿插执行“事务性表”和“非事务性”表更新的操作时,任何一个事务性表操作都可能发生异常而rollback,进而那些非事务性表的修改将变得不可确定,那么最终数据一致性(逻辑上)将是无法保证的。 1) 如果在一个事务中,在修改事务性表数据之前,执行任何修改非事务性表的操作,都将立即被写入binlog,此后的修改事务性表的操作将首先被cached,并在COMMIT时写入binlog(COMMIT和ROLLBACK指令也会写入binlog)。 2)如果配置中开启了GTID且指定“enfore_gtid_consistency=ON”时,那么在事务中,执行修改事务性表数据之后,再尝试修改非事务性表时将会抛出异常。通常我们建议非事务性表则不需要再事务中执行。
Java代码 收藏代码
ERROR 1785 (HY000): Statement violates GTID consistency: Updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables. 为了避免不必要的问题,我们建议在所有数据库表均采用InnoDB引擎,对于目前而言,InnoDB引擎在读写效率上已经和MyISAM没有太大性能差别。 12、slave_preserve_commit_order:对于多线程slaves,来保障事务在slave上执行的顺序与relay log中的顺序严格一致,只有当“slave_parallel_workers”开启时有效;此时“log_bin”、“log_slave_updates”必须开启,而且“slave_parallel_type”值必须为“LOGICAL_CLOCK”(默认值为DATABASE)。即当多线程开启时,且根据relay log中事务的逻辑顺序执行statements,是否需要严格保持顺序,默认值为0表示并发执行忽略顺序。slave_parallel_type默认为DATABASE,能够确保每个DATABASE中的事务顺序严格一致,但是无法保证所有databases的事务执行顺序也是严格一致的(gap),比如两个事务依次操作了2个DB:A和B,尽管事务A、B分别被worker X、Y线程接收,但是因为线程调度的问题,有可能导致A的执行时机落后于B。如果你的事务经常是“跨DB”操作,那么可以考虑使用此参数限定顺序。当此参数开启时,这要求任何worker线程执行的事务时,只有当前事务中此之前的所有事务都执行后(被其他worker线程执行),才能执行和提交。(每个事务中,都记录了当前GTID的privious GTID,只有privious GTID被提交后,当前GTID事务才能提交) 13、TRUNCATE:清理表数据,并重建表的schema。这个指令其实是个DML指令,不过replication模式中,它将作为DDL语句写入binlog,无论是SBR、RBR还是MIXED模式。
相关文章推荐
- DG实施方案(主库为双节点rac)--rman duplicate方式
- 【Vegas改编】RMAN Catalog建立、备份及还原实施
- 实施一个Web服务
- 如何对SAP进行实施与控制
- 基于TestNG 与Selenium 的自动化测试设计与实施
- SharePoint 2010、2013多个域之间互信(Domain Trust)的设计与实施
- HR在ERP实施过程中的作用
- 智能卡COS产品强制性认证实施规则
- 企业BPM的管理特点及实施的主要阶段分析
- 厂商实施“去谷歌化”战略:Android地位遭挑战
- 小公司如何部署实施Linux集群网站
- 网络安全系列之五十一 CC攻击的实施与防护
- 凌云ERP系统成功实施的关键因素分析
- 外出实施问题总结
- 网站架构实施ABC-系统选型篇
- 自己项目实施规划
- 企业成功实施云ERP项目管理的关键点
- [项目实施失败讨论Case] “凭心而论,在这家公司很敬业的工作了3年多,老板最后给我下的评语,大家都看看吧,千万别和我走同一条路!”(摘自csdn)