动态复制过滤器——我们的轮子将是方形的!
这既滑稽又悲伤。新的 MySQL 5.7 里程碑版本推出了一项新特性——复制过滤器现在是动态的了。毫无疑问,这是一项很棒且期待已久的特性。
简而言之,多年来 MySQL 从库可以根据这些事件适用的数据库或表名来过滤传入的复制事件流。这些过滤器使用 my.cnf
文件(或命令行)进行配置,特别是使用以下变量:
replicate_do_db replicate_ignore_db replicate_do_table replicate_ignore_table replicate_wild_do_table replicate_wild_ignore_table
自然地,用户希望无需重启服务器即可更改这些选项的值。最终 Davi Arnaut 实现了它。MariaDB 在 5.5.22 版本中获得了这项贡献。从该版本起,MariaDB 中的这些选项已成为动态系统变量,可以随意更改。例如:
set global replicate_do_db = "mydb1,mydb2"; set global replicate_wild_ignore_table = "mydb1.local%";
现在,我明白有时我们可能会首先实现某个有用的特性。我也明白在这种情况下,Oracle 可能想要拥有它,同时又不希望看起来像在跟随 MariaDB。当然不是!这个特性必须完全原创。使用完全不兼容的语法。最近的例子包括 MySQL 5.7.2 中在 MariaDB 引入 SHOW EXPLAIN
大约一年后出现的 EXPLAIN FOR CONNECTION
,以及使用“通道”的多源复制,而 MariaDB 已经使用命名从库很长时间了。
但说实话,这其中应该有一些逻辑。诚然,EXPLAIN FOR CONNECTION
并不比 SHOW EXPLAIN
差。多源“通道”在语法上看也挺好。但是,如果有一个命令行选项,那么(几乎总是)会有一个对应的系统变量,可以在 SHOW VARIABLES
中看到。人们(几乎总是)通过为对应的变量赋予新值来改变选项的值。只有一种方法可以做到这一点。
唉,我们在 MariaDB 中走了这条路。因此,通过严格遵守NIH(非我所创)原则(而且,我怀疑,还有 Oracle 内部政策),MySQL 开发者不得不发明一种不同的方式来更改服务器选项。瞧,CHANGE REPLICATION FILTER
语句来了。示例如下:
change replication filter replicate_do_db=(mydb1,mydb2); change replication filter replicate_wild_ignore_table=('mydb1.local%');
干得好。常识?不,在这种情况下没有。
我看过这部电影了,而且我不太
喜欢它。那部电影叫“浏览器大战”。请 Oracle,不要把
数据库变成90年代的浏览器。战争从来都不是发生在两家公司之间——它总是针对用户。
谢谢 Sergei 指出这一点,非常有用。对于多源从库上的每个主库,您认为是否可以单独为不同的复制过滤器设置过滤器?
当然。在 MariaDB 中可以。语法和你预期的差不多(与命名键缓存的语法相同)
set @@connection_name.replication_do_table=…
以及从 my.cnf 或命令行设置。
在 MySQL 中似乎不行。诚然,我没有尝试过,但从源代码来看,我没看到它被实现。我猜他们最终会做类似的事情,比如
change replication filter for channel xxx replication_do_table=(…)
这会导致 MySQL 中数据不一致....
所以你认为 Oracle 看到了 MariaDB 的做法,然后说“我们来做点完全不同的?” 而不是直接使用 MariaDB 的代码,他们之前也做过(MariaDB 的补丁曾被采纳到 Oracle 的 MySQL 中)。
你的假设仅仅是假设。很可能更多地与复制过滤器不是常规变量这一事实有关。如果你想在 MySQL 中设置多个值,你必须在配置文件中设置多次。例如,要复制 foo 和 bar 数据库中的所有内容,可以这样写:
replicate_wild_do_table=foo.%
replicate_wild_do_table=bar.%
现在假设你想将其更改为复制 foo 和 baz 数据库。在 MariaDB 中,看起来你可以使用逗号。但在 MySQL 中不行。所以他们改变了这些变量的动态设置方式,以适应这是一个多值变量的事实——而不是修改 SET 命令来尝试解析所有逗号等。
至于 EXPLAIN FOR CONNECTION 与 SHOW EXPLAIN 的区别,对我来说显而易见。想想命令 “SHOW EXPLAIN FOR 1234;” 这是什么意思?显示一个数字的解释?“EXPLAIN FOR CONNECTION 1234;” 更清楚地表明它正在显示连接 1234 的某种信息。
我想这是一种双输局面——如果 Oracle 使用了 MariaDB 的补丁,人们会说“Oracle 没有任何原创的东西!” 在这种情况下,看起来他们正试图把事情做得更好、更有意义。如果你认为 Oracle 是一家市值数百万美元的公司是因为他们浪费时间试图刁难其他公司,那你就错了。如果 MariaDB 的代码很好,而且他们想要那个特性,他们就会使用它,就像他们对待其他特性一样。
不错的尝试 🙂
还有其他多值命令行选项,它们仍然是服务器变量(例如 @@debug)。
当然,我并不认为 Oracle 是一家市值数百万美元的公司,*是因为*他们浪费时间试图刁难其他公司。他们是一家市值数百万美元的公司有很多不同的原因。这仍然不意味着他们不会浪费时间试图刁难其他公司。
而且 Oracle *不能*使用 MariaDB 的代码——他们不能直接拿 GPLv2 代码放到 MySQL 里,必须先签署贡献者协议。你知道这一点。
一旦它是 GPLv2,他们就可以拿来用。贡献者协议的目的是赋予 Oracle 分发它的权利,而 GPLv2 已经赋予了这个权利。
MySQL 和 MariaDB 中的复制选项不完全相同。在 MariaDB 中,它们是真正的服务器变量,但在 MySQL 中不是。例如:
MariaDB [(none)]> select @@version; show variables like ‘replicate_wild%’;
+——————–+
| @@version |
+——————–+
| 5.5.29-MariaDB-log |
+——————–+
1 行数据 (0.00 sec)
+—————————–+——-+
| Variable_name | Value |
+—————————–+——-+
| replicate_wild_do_table | |
| replicate_wild_ignore_table | |
+—————————–+——-+
2 行数据 (0.00 sec)
正如预期的那样,它们显示为真正的服务器变量。现在我们来看看 MySQL 5.6(尽管 MySQL 5.1 和 5.5 的表现相同)
mysql> select @@version; show variables like ‘replicate_wild%’;
+————+
| @@version |
+————+
| 5.6.12-log |
+————+
1 行数据 (0.00 sec)
空集 (0.01 sec)
mysql>
——–
所以你看,在 MySQL 中是不同的。并不是为了刁难 MariaDB,仅仅是因为它实际上就是不同的。