官方文档: https://mariadb.com/kb/en/mariadb/parallel-replicationhtml
从10.0.5版本开始,MariaDB开始支持并行复制mysql
MariaDB10.0的从服务器能并行的执行查询和复制操做,这篇文章将会解释是如何实现的和你能够作的调优。sql
注意:主从服务器上的 MariaDB 的版本必须是10.0.5和10.0.5的之后的版本,才能启用并行复制安全
Parallel replication overview -- 并行复制概述服务器
MariaDB 的复制经过三步完成:session
1.从服务的IO线程去主库上读取变动事件,并把读取的事件顺序放到relay log中app
2.从服务器的SQL线程一次读取relay log中的一个事件dom
3.SQL线程依次应用relay log中的事件ide
MariaDB 10以前的版本中,第三步是经过SQL线程来执行的,这意味着,一次只能执行一个事件,复制本质上是单线程的。性能
MariaDB 10以后的版本中,第三步能够经过一组相互独立的复制线程,由于能够一次并行复制多个事件,提高了复制性能。
How to enable parallel slave -- 如何开启并行复制
在 my.cnf 指定 slave-parallel-threads = n 做为参数传递给MySQL.
并行复制也能够用于多源复制链接设置 "@@connection_name.slave-parallel-mode" 设置为 none, 即 set @@connection_name.slave-parallel-mode = none
slave_parallel_threads 的值决定了池中会有多少个工做线程会被建立用来在从服务器上执行并行复制事件
若是值为0,默认采用旧的复制方式(即slave的SQL线程来重放event事件)
一般来说,若是值为非0,应该设置为多源主服务器链接数的至少两倍。一个链接用一个工做线程的意义不大,由于这不但会增长内部线程通信(即SQL线程和工做线程之间的通信)的负担,并且一个链接使用一个工做线程的时候,事件不能被并行复制。
slave_parallel_threads 的值可进行动态调整,便可在不重启MySQL的状况下,进行更改,可是更改的时候,全部的从库链接都要被中止。
What can be run in parallel -- 如何运行并行复制
并行复制的方式有哪些?
in-order 有序 和 out-of-order 无序两种方式
有序方式
并行执行事务,可是对commit顺序进行排序,以确保从库上事务提交和主库上事务提交顺序一致。只有那些被自动确认为不会引发冲突的事务才会被并行执行,也就是说,并行复制对应用来讲,是彻底透明的。
无序方式
无序意味着在从库上执行和提交事务的顺序跟主库可能不一致,也就是说,应用必需要具有容忍主从服务器上数据更新顺序不一致的问题,同时这种方式要求应用来确保事务之间的没有冲突。无序方式只在GTID模式和应用明确指定使用无序的时候才会被使用, 复制域属于gtid的一部分。
Conservative mode of in-order parallel -- 乐观并行复制模式(optimistic)
Optimistic模式,从MariaDB 10.1.3版本开始支持。
这种模式提供了大量的并行应用slave,同时从应用程序的角度来看,仍然保留精确的事务语义。
开启使用配置选项 --slave-parallel-mode=optimistic.
任何事务DML(插入/更新/删除)能够并行运行,达到限制@@slave_domain_parallel_threads。这可能在slave致使冲突,若是两个事务试图修改同一行,检测到任何这样的冲突,而且两个事务的后者被回滚,容许前者继续, 一旦前者已经完成,后者的事务从新尝试。
Optimistic模式适用于这种方式,由于服务器会发生一些冲突乐观的假定,这额外的工做花了回滚后从新事务冲突时从运行大部分事务得到合理的并行。
有一些启发,试图避免没必要要的冲突,若是在master上一个事务执行了一个行锁等待。它不会再并行运行slave,
事务也能够明确在master上标识为潜在的冲突,经过设置变量@@skip_parallel_replication。这种启发式可能在之后加入MariaDB版本(如今还不支持)
这是接下来的选项--slave-parallel-mode 叫 侵略性"aggressive"模式。当这些启发式呗禁用,容许更多的事务将被应用在并行。
非事务DML和DDL不安全的乐观应用并行,由于它不能再冲突的状况下,回滚。所以,在乐观的模式下,非事务性的(如MyISAM)更新不适用于并行或者早期的事件。(不过,可能适用于并联一个MyISAM更新后会更新),DDL语句不适用于任何其余事务,或早或晚。
不一样的事务类型能够在mysqlbinlog输出肯定,例如:
#150324 13:06:26 server id 1 end_log_pos 6881 GTID 0-1-42 ddl
...
#150324 13:06:26 server id 1 end_log_pos 7816 GTID 0-1-47
...
#150324 13:06:26 server id 1 end_log_pos 8177 GTID 0-1-49 trans
/*!100101 SET @@session.skip_parallel_replication=1*//*!*/;
...
#150324 13:06:26 server id 1 end_log_pos 9836 GTID 0-1-59 trans waited
gtid 0-1-42标明DDL。gtid 0-1-47被标记为非事务DML。而gtid 0-1-49是事务性的DML("trans" 关键字),另外,gtid 0-1-49在master上运行@@ skip_parallel_replication,gtid 0-1-59是事务型的,在master上有一排等待DML锁。("waited" 关键字)。
Conservative mode of in-order parallel -- 保守并行复制(conservative)模式
默认是conservative模式,在10.0版本中惟一可用的模式,可使用 --slave-parallel-mode=conservative 开启。
在conservative模式中,并行复制在master上使用"组提交“,以发现潜在的并行应用事件的slave,
在mater上若是两个事物提交在一组,他们都写进同一个commit id,此类事件的binlog必定不会互相冲突,他们能够计划安排由复制到运行在不一样的线程中。
两个在主上单独提交的事务可能会发生冲突(如,修改同一个表的一行)。所以,应用第二个事务的worker不会当即开始。
可是等到第一个事务开始提交步骤以后,在这一点上,启动第二个事务是安全的,由于它不能再扰乱第一个的执行。
这是mysqlbinlog输出的一个例子,显示gtid events都标有commit id,gtid 0-1-47 没有提交ID,不能并行运行,
gtid 0-1-48和0-1-49有相同的commit id 630,能够在另外一个slave上并行复制。
binlog信息以下:
#150324 12:54:24 server id 1 end_log_pos 20052 GTID 0-1-47 trans
...
#150324 12:54:24 server id 1 end_log_pos 20212 GTID 0-1-48 cid=630 trans
...
#150324 12:54:24 server id 1 end_log_pos 20372 GTID 0-1-49 cid=630 trans
在任何一种状况下,当两个事务到达低级别提交的点,并肯定提交顺序时,这两个提交以相同的顺序发生在mater上,这样操做对应用程序是透明的。
若是在一个组提交中提交了更多的事务,则能够高度地增长对slave的并行复制的机会。
这个能够调整使用binlog_commit_wait_count和binlog_commit_wait_usec变量,例如,若是应用程序在master能够容忍额外延迟50毫秒,你能够设置binlog_commit_wait_usec = 50000和binlog_commit_wait_count = 20,在一个可用的时间,并行复制可得到高达20的事务处理。
不太小心不要设置binlog_commit_wait_usec过高,由于这可能致使应用程序会放缓,运行大量的串行小事务一个接一个的。
请注意:在master上即便没有组提交的并行性,仍然有个机会,提高并行速度。
因为不一样事务的实际提交步骤能够运行。在slave上特别有效,binlog开启(log_slave_updates=1)
甚至若是slave配置崩溃修复安全(sync_binlog=1 and innodb_flush_log_at_trx_commit=1),这种组提交可能在slave上
在--slave-parallel-mode=minimal模式下,仅仅事务提交步骤被并行应用。全部其余事务复制都是连续发生的。
Out-of-order parallel -- 无序并行复制
无序并行复制只使用在GTID模式下,当使用不一样的复制域GTID时,复制域是有DBA/应用程序中使用的变量gtid_domain_id.
在并行复制中有两个事务gtids,不一样domain_id定于不一样的线程,并容许执行彻底独立于此,它是应用程序的责任,只为那些真正独立的事务设置不一样的domain_ids,
并保证不会相互冲突,应用程序还必须正常工做,即便事务中有不一样的domain_id,被视为不一样的顺序呢,在slave和master之间,或者在不一样的slave中。
因为应用程序能够显式地提供更多并行运行事务的机会。而不是服务器能够自动肯定的,出于事务并行复制的顺序并行复制可能自动本身肯定本身
一个简单但有效的用法是运行单独的复制域中的长时间运行的语句,如“更改表”。这容许复制其余事务继续进行不间断:
SET SESSION gtid_domain_id=1
ALTER TABLE t ADD INDEX myidx(b)
SET SESSION gtid_domain_id=0
一般,一个长时间运行的ALTER TABLE语句或者 其余查询,将会中止全部后面的事务。会引起slave落后于master至少须要很长的时间去执行这个运行时间很长的查询。
经过无序并行复制,设置复制domain id。是能够避免的。当运行ALTER TABLE时,DBA/应用程序必须确保没有冲突的事务将被复制。
出于无序并行复制的另外一个常见的条件,是于多源复制有关的。假设咱们有两个不一样的master M1 M2,咱们利用多源复制S1做为一个M1和M2的slave,S1将收到从M2事件并行M1接收事件。
若是咱们如今有三分之一级的奴隶,从S1 S2复制master,咱们但愿S2也可以应用事件起源于M1与M2平行事件起源于。这能够从顺序并行复制来实现,经过设置在M1和M2 gtid_domain_id不一样。
请注意,没有什么特殊限制,可使用无序的并行复制,这样的操做能够在同一个database/schema,甚至在同一个table中,惟一的限制是,操做必须不冲突,这是他们必须可以以任何顺序应用,并最终得到相同的结果。
当使用了无序并行复制时,
当前slave position就是 master 位置
在master binlog在任何一个时间,成为多维 - 每一个复制域能够达到一个不一样的点,
当前的position能够在gtid_slave_pos变量看到。当slave被中止、重启、或者切换复制从不一样master 使用CHANGE MASTER时,MariaDB自动处理重启每一个复制域在binlog适当点。
当--slave-parallel-mode=minimal(或none)模式,无序并行复制是关闭的。
Checking worker thread status in SHOW PROCESSLIST -- 检查显示列表的线程状态
在show processlist中,工做线程将会列出"system user",他们的状态将显示他们目前正在进行的查询,或者它能够显示其中一个:
"Waiting for work from main SQL threads". "等待工做从主要的SQL线程"。
这意味着工做线程空闲,没有工做可用于它的时刻。
"Waiting for prior transaction to start commit before starting next transaction". "等待以前的事务开始下一次事务开始以前提交"。
这意味着,前一批提交的事务在主必须完成第一个。这个工做线程在等待它发生以前,它能够开始工做在下面的一批。
This worker thread is waiting for that to happen before it can start working on the following batch.
"Waiting for prior transaction to commit". ”等待优先事务提交“。
这意味着事务已被工做线程执行了,为了确保订单提交,工做线程等待提交,知道上一次事务准备在它以前提交为止。
Expected performance gain -- 性能预期测试的文章
这里有一篇关于使用并行复制时,改进后高达10倍的性能文章
文章地址: http://kristiannielsen.livejournal.com/18435.html。
slave-parallel-max-queued配置参数:
变量slave_parallel_max_queued是惟一有意义的,前提并行复制技术被使用(slave_parallel_threads参数大于0时),当并行复制被使用时, SQL线程会预读relay-log中的event,队列时间放在内存中,在并行复制中,同时寻找并行执行事件的机会。@@slave_parallel_max_queued变量设置为SQL 线程将在预读多少内存限制的日志,寻找这样的机会。每一个线程是有限制的,所以,此次预读的值是设置@@slave_parallel_threads变量值得来的
若是这个值设置的过高,而且slave落后于master太远(如千兆字节的binlog),而后SQL线程能够快速读,填补大量内存的binlog事件比工做线程消耗的更快
另外一方面,若是值定的过低,SQL线程可能没有足够的空间来保持足够的事件队列忙的线程,这可能下降性能。
注意,@@slave_parallel_max_queued不是硬性限制,由于binlog事件当前执行老是须要保存在内存中,
例如,每一个工做者线程至少有两个事件老是能够在内存中排队,无论slave_parallel_threads是多
一般,slave_parallel_threads应该设置的足够大,SQL线程利用全部可能的并行性能够预读的足够远的binlog,在正常操做中,slave将不但愿落后太远,所以不会将大量数据队列有必要的放在内存中的。因此slave_parallel_threads可能设置的至关高(如几百KB)不限制吞吐量。它应该被设置的足够低,slave_parallel_threads * slave_parallel_max_queued 不会形成服务器内存不足。
slave_domain_parallel_threads配置参数:
在全部多源主链接中共享复制工做线程池,在全部能够在并行使用顺序复制的复制域中。
若是一个主链接或者一个复制域 当前正在执行处理一个长时间的查询,可能它将分配在池中的全部工做线程,只能等待让他们长时间运行的查询完成。
拖延任何master主库链接或者复制域,这将不得不等待复制域工做线程变得空闲。
能够经过slave_domain_parallel_threads变量设置的值避免低于slave_parallel_threads设置的值,
当设置不等于0时,一个主链接中的每一个复制域均可以保留至多一个时间段的多个线程,
其他的,达到slave_parallel_threads参数的值,在并行复制中无其余主链接或者复制域去使用。
slave_domain_parallel_threads变量是能够动态修改的,能够在不重启服务的状况下更改。全部的slave必须中止掉更改。