MySQL Binlog 客户端配置
MySQL Binlog Client在ClickHouse中提供了一种机制,可以在多个MaterializedMySQL数据库之间共享来自MySQL实例的二进制日志。这样可以避免在复制多个模式/数据库时消耗不必要的带宽和CPU。
该实现具有对崩溃和磁盘问题的鲁棒性。仅在安全地持久化描述数据的数据之后,才会持久化binlog本身和消耗数据库的执行GTID集。该实现还容忍重新执行中止的操作(至少一次交付)。
use_binlog_client
强制重用现有的 MySQL binlog 连接,如果不存在则创建新连接。连接由 user:pass@host:port 定义。默认值:0
-- create MaterializedMySQL databases that read the events from the binlog client
CREATE DATABASE db1 ENGINE = MaterializedMySQL('host:port', 'db1', 'user', 'password') SETTINGS use_binlog_client=1
CREATE DATABASE db2 ENGINE = MaterializedMySQL('host:port', 'db2', 'user', 'password') SETTINGS use_binlog_client=1
CREATE DATABASE db3 ENGINE = MaterializedMySQL('host:port', 'db3', 'user2', 'password2') SETTINGS use_binlog_client=1
数据库 db1 和 db2 将使用相同的 binlog 连接,因为它们使用相同的 user:pass@host:port。数据库db3将使用单独的binlog连接。
max_bytes_in_binlog_queue
该参数定义了事件binlog队列中的字节数限制。如果队列中的字节数超过了此限制,它将停止从MySQL中读取新的事件,直到为新事件释放出空间。这引入了内存限制。非常高的值可能会消耗所有可用内存。非常低的值可能会导致数据库等待新的事件。
默认值:67108864
示例:
CREATE DATABASE db1 ENGINE = MaterializedMySQL('host:port', 'db1', 'user', 'password') SETTINGS use_binlog_client=1, max_bytes_in_binlog_queue=33554432
CREATE DATABASE db2 ENGINE = MaterializedMySQL('host:port', 'db2', 'user', 'password') SETTINGS use_binlog_client=1
如果数据库db1无法快速消费binlog事件,并且事件队列的大小超过了33554432字节,那么从MySQL中读取新事件将被推迟,直到db1消费了事件并释放了一些空间。
注意:这会影响到db2,它也会等待新的事件,因为它们共享同一个连接。
max_milliseconds_to_wait_in_binlog_queue
定义了当超过max_bytes_in_binlog_queue时要等待的最大毫秒数。之后,它将断开数据库与当前binlog连接的连接,并重试建立新连接,以防止其他数据库等待此数据库。
默认值:10000
示例:
CREATE DATABASE db1 ENGINE = MaterializedMySQL('host:port', 'db1', 'user', 'password') SETTINGS use_binlog_client=1, max_bytes_in_binlog_queue=33554432, max_milliseconds_to_wait_in_binlog_queue=1000
CREATE DATABASE db2 ENGINE = MaterializedMySQL('host:port', 'db2', 'user', 'password') SETTINGS use_binlog_client=1
如果数据库db1的事件队列已满,则binlog连接将在1000毫秒内等待,如果数据库无法消费事件,则将其从连接中分离以创建另一个连接。
注意:如果数据库db1已从共享连接中分离并创建了新连接,在db1和db2的binlog连接位置相同时,它们将合并为一个连接。然后db1和db2将再次使用同一个连接。
max_bytes_in_binlog_dispatcher_buffer
定义了在刷新到附加binlog之前,binlog调度程序缓冲区中的最大字节数。来自MySQL binlog连接的事件在发送到附加的数据库之前会被缓冲。这会增加从binlog到数据库的事件吞吐量。
默认值:1048576
max_flush_milliseconds_in_binlog_dispatcher
定义了在刷新到附加binlog之前,binlog调度程序缓冲区中等待的最大毫秒数。如果一段时间内没有从MySQL binlog连接接收到事件,那么一段时间后缓冲的事件应该被发送到附加的数据库。
默认值:1000
设计原理
Binlog事件调度程序
目前,每个MaterializedMySQL数据库都会打开自己的连接到MySQL以订阅binlog事件。我们需要只有一个连接,并将binlog事件分派到所有从同一个MySQL实例复制的数据库。
每个MaterializedMySQL数据库有自己的事件队列
为了防止其他实例减速,每个MaterializedMySQL数据库应该有一个事件队列,以独立于其他实例的速度处理事件。调度程序从binlog中读取事件,并将其发送给每个需要的MaterializedMySQL数据库。每个数据库在单独的线程中处理其事件。
追赶
如果几个数据库具有相同的binlog位置,则它们可以使用相同的调度程序。如果一个新创建的数据库(或者已经分离了一段时间的数据库)请求已经处理的事件,我们需要创建另一个与binlog通信的通道。我们通过为这样的数据库创建另一个临时调度程序来实现这一点。当新调度程序赶上旧调度程序时,新/临时调度程序不再需要,从这个调度程序获取事件的所有数据库都可以移动到旧调度程序。
内存限制
对于每个MySQL客户端,有一个内存限制来控制事件队列内存消耗。如果一个数据库无法快速处理事件,事件队列变满了,我们有以下选项:
调度程序被阻塞,直到最慢的数据库为新事件释放空间。其他所有数据库都在等待最慢的那个。(首选)
调度程序从不被阻塞,但是暂停了对慢数据库的增量同步,并继续向其他数据库发送事件。
性能
通过不在每个数据库中处理每个事件,可以节省大量的CPU。binlog包含所有数据库的事件,将行事件分发给它不会处理的数据库是浪费的,特别是如果有很多数据库。这需要某种按数据库分组的binlog过滤和缓冲。
目前所有事件都发送到所有MaterializedMySQL数据库,但解析事件(消耗CPU)由数据库处理。
详细设计
如果客户端(例如数据库)想要从MySQL binlog读取事件流,它会通过主机/用户/密码和执行的GTID设置参数创建到远程binlog的连接。
如果另一个客户端想要从binlog读取事件,但执行不同的GTID设置,则无法重用现有的MySQL连接,需要创建另一个连接到相同的远程binlog。(这是当前的实现方式)。
当这两个连接获取相同的binlog位置时,它们读取相同的事件。删除重复的连接并将所有用户移出是合理的。现在一个连接将binlog事件分发给多个客户端。显然,只有与相同binlog的连接应该被合并。
类
一个连接可以向多个客户端发送(或分派)事件,可能称为BinlogEventsDispatcher。
BinlogClient中的几个调度程序由user:password@host:port分组。由于它们指向相同的binlog。
客户端应仅与BinlogClient的公共API进行通信。使用BinlogClient的结果是实现IBinlog以从中读取事件的对象。该IBinlog的实现必须与旧的MySQLFlavor实现兼容 -> 当用新的实现替换旧的实现时,行为不得改变。
-- create MaterializedMySQL databases that read the events from the binlog client
CREATE DATABASE db1_client1 ENGINE = MaterializedMySQL('host:port', 'db', 'user', 'password') SETTINGS use_binlog_client=1, max_bytes_in_binlog_queue=1024;
CREATE DATABASE db2_client1 ENGINE = MaterializedMySQL('host:port', 'db', 'user', 'password') SETTINGS use_binlog_client=1;
CREATE DATABASE db3_client1 ENGINE = MaterializedMySQL('host:port', 'db2', 'user', 'password') SETTINGS use_binlog_client=1;
CREATE DATABASE db4_client2 ENGINE = MaterializedMySQL('host2:port', 'db', 'user', 'password') SETTINGS use_binlog_client=1;
CREATE DATABASE db5_client3 ENGINE = MaterializedMySQL('host:port', 'db', 'user1', 'password') SETTINGS use_binlog_client=1;
CREATE DATABASE db6_old ENGINE = MaterializedMySQL('host:port', 'db', 'user1', 'password') SETTINGS use_binlog_client=0;
数据库db1_client1、db2_client1和db3_client1共享一个BinlogClient实例,因为它们具有相同的参数。BinlogClient将创建3个连接到MySQL服务器,因此有3个BinlogEventsDispatcher实例,但如果这些连接具有相同的binlog位置,它们应该合并为一个连接。这意味着所有客户端将被移动到一个调度程序中,其他调度程序将被关闭。数据库db4_client2和db5_client3将使用2个独立的BinlogClient实例。数据库db6_old将使用旧的实现。注意:默认情况下,use_binlog_client是禁用的。通过设置max_bytes_in_binlog_queue定义binlog队列中允许的最大字节数。默认情况下,它是1073741824字节。如果字节数超过此限制,则分派将停止,直到为新事件释放空间。
Binlog表结构
要查看所有BinlogClient实例的状态,可以使用system.mysql_binlogs系统表。它显示了所有已创建和存活的IBinlog实例的列表,以及有关其BinlogEventsDispatcher和BinlogClient的信息。
本文暂时没有评论,来添加一个吧(●'◡'●)