mariadb 并行复制
Posted 小飞旅馆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mariadb 并行复制相关的知识,希望对你有一定的参考价值。
1. 并行复制简介
并行这个概念在oracle里面已经不陌生了,很多时候我们可以用parallel来优化数据库的一些操作,同样在mysql里也有相关的概念,这里我们来学习一下mariadb复制相关的并行。
MariaDB复制通常分为三个步骤:
IO线程从主机读取复制事件,并在中继日志中排队。
SQL线程从中继日志中一次一个地获取复制事件。
每个事件都应用于从站,以复制在主站上完成的所有更改。
在MariaDB 10之前,第三步也是由SQL线程执行的; 这意味着一次只能执行一个事件,复制本质上是单线程的。从MariaDB 10开始,第三步可以由一组独立的复制工作线程执行,从而可以通过并行应用多个事件来提高复制性能。
2. 并行复制开关
要启用,请在my.cnf文件中指定slave-parallel-threads=#作为mysql的参数。
通过将@@connection_name.slave-parallel-mode设置为“none”,可以在每个多源连接上禁用并行复制。
slave_parallel_threads的值(#)指定在用于为所有您的从属服务器并行应用事件的工作线程池中创建的线程数(包括多源复制)。如果值为零,则不会创建工作线程,并且在SQL线程内部应用事件的情况下使用旧式复制。通常,该值(如果非零)应至少是所使用的多源主连接数的两倍。将一个工作线程用于一个连接是没有意义的; 这将在SQL线程和工作线程之间的线程间通信中产生一些开销,但是只有一个工作线程事件无论如何都不能并行应用。
slave-parallel-threads=#是一个动态变量,可以在不重新启动mysqld的情况下进行更改。但是,在更改值时,必须停止所有从站连接。
3. 并行三种模式
并行复制可以是有序的也可以是无序的:
按顺序并行执行事务,但命令事务的提交步骤以与主服务器完全相同的顺序发生。事务仅在可以自动验证可以没有任何冲突的情况下并行执行。这意味着并行性的使用对应用程序是完全透明的。
乱序可以在从节点上以不同于主节点的顺序执行和提交事务。这意味着应用程序必须能够容忍看到更新以不同的顺序发生。应用程序还负责确保在无序复制的事务之间不存在冲突。乱序仅在GTID模式下使用,并且仅在应用程序明确启用时使用作为GTID一部分的复制域。
因此与并行复制相关的就有了三种模式:
有序并行复制的乐观模式
从MariaDB10.1.3开始提供乐观模式。此模式为从属并行应用提供了大量机会,同时仍
然从应用程序的角度保留了精确的事务语义。它使用配置选项--slave-parallel-mode= optimistic启用。
允许任何事务DML(INSERT /UPDATE / DELETE)并行运行,最高可达@@slave_domain_parallel_threads的限制。这可能会导致从站发生冲突,例如。如果两
个事务尝试修改同一行。检测到任何此类冲突,并且回滚两个事务中的后一个,允许前者继续。一旦前者完成,后一个事务将被重新尝试。
术语"乐观"用于此模式,因为服务器乐观地假设将发生很少的冲突,并且通过并行运行大多数事务的收益来证明回滚和重试冲突事务所花费的额外工作是合理的
尝试避免不必要的冲突有一些启发式方法。如果事务在主服务器上执行行锁等待,则它
不会在从服务器上并行运行。通过设置变量@@skip_parallel_replication,也可以在主服务器上明确标记事务可能存在冲突 。在以后的MariaDB版本中可能会添加更多此类启发式方法。还有一个名为“aggressive”的--slave-parallel-mode,这些启发式被禁用,允许更多的事务并行应用。
非事务性DML和DDL并不是乐观并行应用的安全因素,因为在发生冲突时无法回滚。
因此,在乐观模式下,非事务性(例如MyISAM)更新不会与早期事件并行应用(但是,可以将MyISAM更新与稍后的InnoDB更新并行应用)。DDL语句不会与之前或之后的任何其他事务并行应用。
可以在mysqlbinlog的输出中标识不同类型的事务 。例如:
#150324 13:06:26服务器ID 1 end_log_pos 6881 GTID 0-1-42 ddl
...
#150324 13:06:26服务器ID 1 end_log_pos 7816 GTID 0-1-47
...
#150324 13:06:26服务器ID 1 end_log_pos 8177 GTID 0-1-49 trans
/ *!100101 SET @@session.skip_parallel_replication = 1 * // *!* /;
...
#150324 13:06:26服务器ID 1 end_log_pos 9836 GTID 0-1-59 trans等待
GTID 0-1-42被标记为DDL。GTID 0-1-47被标记为非事务性DML,而GTID 0-1-49是事务性DML(在“trans”关键字上看到)。另外运行GTID 0-1-49并 在主站上设置@@skip_parallel_replication。GTID 0-1-59是事务DML,在主服务器上运行时具有行锁等待(“等待”关键字)。
保守模式的有序并行复制
保守模式是默认模式,也是10.0中唯一可用的模式。它使用--slave-parallel-mode=保守启用。
在保守模式下,并行复制使用主服务器上的组提交来实现在从服务器上并行应用事件的可能性。如果两个事务在主服务器上的组提交中一起提交,则它们将被写入具有相同提交ID的binlog中。此类事件肯定不会相互冲突,并且可以通过并行复制来调度它们以在不同的工作线程中运行。
在主服务器上单独提交的两个事务可能会发生冲突(例如,修改表的同一行)。因此,应用第二个事务的worker不会立即启动,而是等到第一个事务开始提交步骤; 此时,启动第二个事务是安全的,因为它不再能够破坏第一个事务的执行。
以下是mysqlbinlog的示例输出,它显示了如何使用commitid标记GTID事件。GTID 0-1-47没有提交ID,不能并行运行。GTID 0-1-48和0-1-49具有相同的提交ID 630,因此可以在从设备上彼此并行复制:
#150324 12:54:24服务器ID 1 end_log_pos 20052 GTID 0-1-47 trans
...
#150324 12:54:24服务器ID 1 end_log_pos 20212 GTID 0-1-48 cid = 630 trans
...
#150324 12:54:24服务器ID 1 end_log_pos 20372 GTID 0-1-49 cid = 630 trans
在任何一种情况下,当两个事务到达发生低级别提交并确定提交顺序的点时,两个提交按顺序排列,与主服务器上的顺序相同,因此该操作对应用程序是透明的。
如果在主服务器上的组提交中提交了更多事务,则可以大大增加从服务器上并行复制的机会。这可以使用binlog_commit_wait_count和 binlog_commit_wait_usec变量进行调整。例如,如果应用程序可以容忍主服务器上的事务最多50毫秒的额外延迟,则可以设置binlog_commit_wait_usec=50000并且 一次最多可以binlog_commit_wait_count=20并行复制20个事务。但是必须注意不要设置binlog_commit_wait_usec得太高,因为这可能导致一个接一个地连续运行大量小事务的应用程序显着减速。
请注意,即使主组提交没有可用的并行性,仍然有机会从有序并行复制加速,因为不同事务的实际提交步骤可以并行运行。这对于启用了binlog的从节库(log_slave_updates= 1)尤其有效,如果slave配置为崩溃安全(sync_binlog =1和innodb_flush_log_at_trx_commit= 1),则更为如此,因为这样可以在从库上进行组提交。
在--slave-parallel-mode= minimal模式下,只有事务的提交步骤并行应用; 所有其他事务复制都是串行发生的。
乱序并行复制
当使用具有不同复制域的GTID时,在使用GTID模式时(仅)发生无序并行复制。复制域由DBA /应用程序使用变量设置gtid_domain_id。
具有不同domain_id的GTID的两个事务通过并行复制被调度到不同的工作线程,并且被允许彼此完全独立地执行。应用程序的责任是仅为真正独立的事务设置不同的domain_id,并保证不会相互冲突。即使具有不同domain_id的事务被视为在从设备和主设备之间以及不同从设备之间以不同顺序提交,应用程序也必须能够正常工作。
无序并行复制可能比有序并行复制提供更多性能增益,因为应用程序可以显式提供更多机会来并行运行事务,而不是服务器自动确定的事务。
一个简单但有效的用法是在单独的复制域中运行长时间运行的语句,例如ALTER TABLE。这允许其他事务的复制不间断地继续:
SET SESSION gtid_domain_id = 1
ALTER TABLE t ADD INDEX myidx(b)
SET SESSION gtid_domain_id = 0
通常,长时间运行的ALTERTABLE或其他查询将hang信所有后续事务,从而导致从属服务器成为主服务器后面的时间至少与运行长时间运行的查询所花费的时间相同。通过设置复制域ID使用无序并行复制,可以避免这种情况。DBA /应用程序必须确保在ALTER TABLE运行时不会复制冲突的事务。
无序并行复制的另一个常见机会与多源复制有关。假设我们有两个不同的主设备M1和M2,我们使用多源复制将S1作为M1和M2的从设备。S1将从M1接收的事件与从M2接收的事件并行地应用事务。如果我们现在有一个从S1复制为主节点的第三级从属S2,我们希望S2也能够应用源自M1的事件与源自M2的事务并行。这可以通过gtid_domain_id在M1和M2上设置不同的无序并行复制来实现 。
请注意,对于可以使用乱序并行复制的操作没有特殊限制; 这样的操作可以在同一个数据库/模式上,甚至可以在同一个表上。唯一的限制是操作不得冲突,即它们必须能够以任何顺序应用,并且最终仍然会得到相同的结果。
使用无序并行复制时,主机binlog中的当前从站位置变为多维- 每个复制域在任何时候都可以到达主binlog中的不同点。从变量可以看出当前位置 gtid_slave_pos。当从站停止,重新启动或切换为使用CHANGE MASTER从其他主站复制时,MariaDB会自动处理在binlog中的适当位置重新启动每个复制域。
当--slave-parallel-mode= minimal(或none)时,将禁用乱序并行复制 。
4. 并行监测
工作线程将在SHOWPROCESSLIST中列为“系统用户”。他们的状态将显示他们当前正在处理的查询,或者它可以显示其中一个:
“等待主SQL线程的工作”。这意味着工作线程处于空闲状态,此时没有可用的工作。
“等待先前的事务在开始下一个事务之前开始提交”。这意味着必须首先完成在主母
版上一起提交的上一批事务。此工作线程正在等待它发生,然后才能开始处理以下批处理。
“等待先前的交易提交”。这意味着事务已由工作线程执行。为了确保按顺序提
交,工作线程正在等待提交,直到上一个事务准备好在它之前提交。
5. 并行复制性能优化总结
为了提高复制性能,减少从库的延时,我们一般会开启并行复制,即设置
slave-parallel-threads指定在一个工作线程池中创建多少个线程去并行的应用事务。而对于默认的--slave-parallel-mode,如果对于数据一致性没那么高的环境,我们也可以用binlog_commit_wait_usec和binlog_commit_wait_count来优化,例如,如果应用程序可以容忍主服务器上的事务最多50毫秒的额外延迟,则可以设置binlog_commit_wait_usec=50000并且一次最多可以binlog_commit_wait_count=20并行复制20个事务。
另外我们还可以设置slave-parallel-max-queued,该变量设置SQL线程在寻找此类机会的中继日志中用于预读的内存量的限制。限制是每个线程,因此readahead是此值的值乘以@@ slave_parallel_threads的值。合适的变量可以加快事务在从库上的应用速度。
关于slave-paralel-max-queued,官方有一段话:
使用并行复制时,SQL线程将在中继日志中预读,在内存中排队事件,同时寻找并行执行事件的机会。@@slave_parallel_max_queued变量设置SQL线程在寻找此类机会的中继日志中用于预读的内存量的限制。限制是每个线程,因此readahead是此值的值乘以@@ slave_parallel_threads的值。
如果此值设置得太高,并且主服务器后面的slave很远(例如,千兆字节的binlog),那么SQL线程可以快速读取所有这些并使用大量的binlog事件填充内存比工作线程更快消耗它们。
另一方面,如果设置得太低,SQL线程可能没有足够的空间来排队足够的事件来保持工作线程繁忙,这可能会降低性能。
请注意,@@slave_parallel_max_queued不是硬限制,因为当前正在执行的binlog事件总是需要保存在内存中。例如。无论slave_parallel_threads的值如何,每个工作线程至少有两个事件可以始终在内存中排队。
通常,slave_parallel_threads应该设置得足够大,以至于SQL线程能够在binlogs中提前读取足够远,以利用所有可能的并行性。在正常操作中,希望奴隶不会太落后,因此不需要在内存中排队很多数据。因此,slave_parallel_threads可以设置得相当高(例如几百千字节),以便不限制吞吐量。它应该设置得足够低,以使slave_parallel_threads *slave_parallel_max_queued的值不会导致服务器内存不足。
多源复制中可以通过设置slave_domain_parallel_threads来降低一个主源对线程的全占用
以上是关于mariadb 并行复制的主要内容,如果未能解决你的问题,请参考以下文章
[工作积累] UE4 并行渲染的同步 - Sync between FParallelCommandListSet & FRHICommandListImmediate calls(代码片段