20180402MySQL关于replication filter和trigger的一些应用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20180402MySQL关于replication filter和trigger的一些应用相关的知识,希望对你有一定的参考价值。

需求描述

1.内网服务器有俩套主从复制环境,一套是基于传统复制的5.6.26版本,另外一套是基于GTID的5.7.19版本的复制。现在开发的需求是需要将基于传统复制的上面的俩个表同步到基于基于GTID复制上面去,并且要求同步的俩个表中有一个表的一列的值必须是源的10倍。

[email protected] 15:51:  [remix_test]> show create table sbtest1 \G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL,
  `k` int(11) NOT NULL DEFAULT ‘0‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

表结构如上所示,在原来的基础上column k必须乘以10,即new_k = old_k*10

难点

1.如何将俩个表的数据同步过来。在这里我们采用了使用主从同步的方案,但是主从同步的方案又带来了以下几个问题:

  • 基于传统复制的主从是根据binlog file 和 binlog position进行复制的,基于GTID的主从是根据GTID进行复制,这俩者创建主从是使用基于传统复制还是GTID复制。
  • 基于GTID复制的主从的binlog的格式是ROW格式,基于传统复制的主从的binlog格式是STATEMENT格式,在将数据同步到从传统复制的master上面同步到基于GTID复制的master上,这个时候基于GTID的主从复制的SLAVE是否能够正常应用binlog日志,或者说slave能否应用没有使用GTID的binlog日志。
  • 仅仅只是需要同步俩张表,其他的库表的数据不需要同步过来。所以需要进行复制过滤。

2.如何将同步过来的数据做修改。在这里我们采取的方案是使用触发器,但是触发器本身会消耗资源;因为触发器是基于row行的,所以假如我们一次性修改500条数据花费1s中,触发器触发修改会触发500次,加入每行数据修改花费1s,那么触发器就会花费500s。

  • 在测试的过程中,我们发现在INSERT插入一行数据之后,在针对这行的数据进行update操作,触发器无法被应用到,并且show slave status\G会报错:
    Last_SQL_Error: Error ‘Can‘t update table ‘sbtest1‘ in stored function/trigger because it is already used by statement which invoked this stored function/trigger.‘ on query. Default database: ‘remix_test‘. Query: ‘insert into sbtest1(id,k) values(39039,1),(39040,10)‘

解决方案

1.数据同步:

  • 为了使得基于GTID主从复制的master能够应用来自于传统复制的主从的master的binlog日志,在GTID主从复制的master上面必须修改SQL_MODE,将SQL_MODE更改成ON_PERMISSIVE(本地产生GTID事务,并且接受隐性事务(即非GTID事务)):
    mysql> set global sql_mode=‘ON_PERMISSIVE‘;
  • 至于基于GTID复制的主从的SLAVE同步来自于MASTER的数据,这里暂时没有什么好的方案,或者我们还没有进行实验。但是之前我们忘记在本地进行修改SQL_MODE导致在SLAVE上面执行SHOW SLAVE STATUS \G可以看出很明显的错误:ERROR:1236
  • 复制过滤:需要注意的如果你仅仅只是写replication_do_table的话,虽然一般的DDL,DML操作不是这俩个表是不会复制过来的,但是当你创建新库的时候(create database schema_name;)还是会将新库的创建命令同步过来的,但也是仅仅同步新库的创建命令,其他的例如在新库创建表之类的是不会同步过来的。
    mysql> Change replication filter REPLICATE_DO_DB=(remix_test),REPLICATE_DO_TABLE = (remix_test.sbtest1,remix_test.sbtest2);
  1. 触发器的创建。
    • 创建下面触发器的时候虽然是创建成功的,但是但你在基于传统复制的master做insert插入操作的时候是可以触发触发器但是却无法执行,会抛出上面所说的错误。
      mysql> delimiter || ;
      mysql> create trigger tr1 after insert on sbtest1
      -> for each row
      -> begin
      ->     update sbtest1 set k=new.k*10 where id=new.id;
      -> end||
      mysql> delimiter ;
    • 最后还是打算创建一个新表,每次旧表又什么操作就在新表上面进行修改。

实际操作:

  1. 基于传统复制数据的slave上面的备份
    shell> mysqldump --set-gtid-purged=OFF --single-transaction --dump-slave=2 -uroot -p -t remix_test sbtest1 > sbtest1_20180402.sql
    shell> mysqldump --set-gtid-purged=OFF --single-transaction --dump-slave=2 -uroot -p -t remix_test sbtest2 > sbtest2_20180402.sql
  2. 基于GTID复制的MASTER上面的恢复
    shell> mysql -S /var/lib/mysql/mysql_3306.sock -uroot -p remix_test< sbtest1_20180402.sql
    shell> mysql -S /var/lib/mysql/mysql_3306.sock -uroot -p remix_test<sbtest2_20180402.sql
  3. 基于传统复制的MASTER上面创建复制账号
    mysql> grant replication slave on ‘slave‘@‘ip_address‘ identified by ‘new_password‘;
    mysql> flush privileges;
  4. 基于GTID复制的MASTER的sql_node修改
    mysql> set global sql_mode=‘ON_PERMISSIVE‘;
  5. 基于GTID复制的MASTER上面搭建主从(从基于后面备份的sbtest2_20180402.sql上面获取binlog file和position信息)
    mysql> change master  ......
  6. 基于GTID复制的MASTER上面做复制过滤
    mysql> change replication replication_do_db=(remix_test),replication_do_table=(remix_test.sbtest1,remix_test.sbtest2);
  7. 基于GTID复制的MASTER开启主从复制
    技术分享图片
  8. 基于GTID复制的MASTER创建新表
    mysql> create table sbtest1_bak like sbtest1;
    mysql> insert into sbtest1_bak select id,k*10 from sbtest1;

    9.基于GTID复制的MASTER上面创建触发器

    [email protected] 15:39:  [remix_test]> delimiter ||
    [email protected] 15:41:  [remix_test]> create trigger tr2 after update on sbtest1
    -> for each row
    -> begin
    ->     update sbtest1_bak set k=new.k*10 where id=new.id;
    -> end||
    [email protected] 15:48:  [remix_test]> delimiter ||
    [email protected] 15:48:  [remix_test]> create trigger tr3 after delete on sbtest1
    -> for each row
    -> begin
    ->     delete from sbtest1_bak where id=old.id;
    -> end||
    Query OK, 0 rows affected (0.11 sec)
    [email protected] 15:49:  [remix_test]> delimiter ;
    [email protected] 15:06:  [remix_test]> create trigger tr1 after insert on sbtest1
    -> for each row
    -> begin
    ->     insert into sbtest1_bak(id,k) select id,k*10 from sbtest1 where id=new.id;
    -> end||
    Query OK, 0 rows affected (0.11 sec)
    [email protected] 15:08:  [remix_test]> delimiter ;

    技术分享图片

以上是关于20180402MySQL关于replication filter和trigger的一些应用的主要内容,如果未能解决你的问题,请参考以下文章

php 20180402常见问题

php 20180402ギャラリー(マリオット)

将具有特定名称的文件复制到相应的目录

Replication Lag 的mysql 如何分析

Mysql主从复制

MYSQL数据库高可用方案探究