PolarDB MySQL版多主集群(库表)实现从一写多读架构到多写多读多主架构的升级;支持不同数据库或不同数据对象在不同计算节点并发写入;支持数据库和数据对象跨节点动态调度,秒级完成切换,极大提升实例整体并发读写能力。数据对象目前包括如下对象:表(Table)、视图(View)、触发器(Trigger)、定时任务(Event)、存储过程(Procedure)、自定义函数(Function)。本文介绍多主集群(库表)的使用说明。
前提条件
使用限制
每个数据库或数据对象的数据只能通过一个节点写入。没有分配数据库或数据对象的节点,不能进行读写操作。默认情况下,按照数据库的维度进行操作,如果需要按照数据对象的维度进行操作,需要使用指定的语法切换。
不支持跨RW节点的数据查询。如果一个查询SQL中包含多个RW节点上的数据库或数据对象,系统则会报错。建议您先把所有数据库或数据对象的访问点调整到其中一个RW节点上,再进行查询操作。
仅提供集群地址,不支持主地址。
数据库访问点切换支持以下模式:
如果使用数据库隔离级别,则需要切换数据库访问点。
如果使用数据对象隔离级别,则需要切换数据对象访问点。
创建数据库时指定RW节点
在指定的RW节点上创建数据库。语法结构如下:
CREATE DATABASE name [POLARDB_WRITE_NODE master_id];
在数据库隔离级别维度的操作模式下,每个数据库的数据只能通过一个节点写入。
如果上述语法中省略了
[POLARDB_WRITE_NODE master_id]
,那么创建数据库时就会参考loose_innodb_mm_default_master_id参数的值来指定创建数据库的RW节点。如果loose_innodb_mm_default_master_id参数的值为0,系统则随机指定一个RW节点来创建数据库。
示例:在RW1上创建一个数据库db1
。
CREATE DATABASE db1 POLARDB_WRITE_NODE 1;
如果需要在RW2上创建数据库db1
,把上述示例中的1换成2即可。
删除在指定RW节点上创建的数据库
删除在指定RW节点上创建的数据库。语法结构如下:
DROP DATABASE name;
示例:删除在RW1节点上创建的数据库db1
。
DROP DATABASE db1;
删除数据库时,无需指定POLARDB_WRITE_NODE。
数据库访问点切换
把数据库的访问点切换到其他RW节点上。语法结构如下:
ALTER DATABASE name POLARDB_WRITE_NODE master_id;
示例:把数据库db1
切换到RW2上。
ALTER DATABASE db1 POLARDB_WRITE_NODE 2;
正常情况下,访问点切换是一个耗时的操作。具体执行时间取决于以下两个因素:
数据库下表的个数。数量越多,切换速度越慢。
切换时数据库的DML压力。压力越大,切换速度越慢。
数据库隔离级别切换为数据对象隔离级别
默认情况下,多主集群隔离级别是数据库级别,即同一个数据库下的所有数据对象只能在一个RW节点上访问。如果想让同一个数据库下的所有数据对象通过多个RW访问,那么就需要把数据库隔离级别修改成数据对象隔离级别。语法结构如下:
ALTER DATABASE name TO TABLE_LOCK POLARDB_WRITE_NODE master_id;
其中name为数据库的名称。master_id为数据对象的访问点。
示例:把数据库db1
的数据对象隔离级别改为数据库隔离级别,并且设置访问点为RW2。
ALTER DATABASE db1 TO TABLE_LOCK POLARDB_WRITE_NODE 2;
正常情况下,隔离级别切换是一个耗时的操作。具体执行时间取决于以下两个因素:
数据库下的所有对象的个数。数量越多,切换速度越慢。
切换时数据库的DML压力。压力越大,切换速度越慢。
数据对象隔离级别切换为数据库隔离级别
如果将一个数据库的最小粒度改为数据对象级别后,再恢复成数据库隔离级别以方便管理,可以使用如下的切换语句:
ALTER DATABASE name TO DB_LOCK POLARDB_WRITE_NODE master_id;
其中name为数据库的名称。master_id为数据库的访问点。
示例:把数据库db1
的数据对象隔离级别改为数据库隔离级别,并且设置访问点是RW1。
ALTER DATABASE db1 TO DB_LOCK POLARDB_WRITE_NODE 1;
正常情况下,隔离级别切换是一个耗时的操作。具体执行时间取决于以下两个因素:
数据库下的所有对象的个数。数量越多,切换速度越慢。
切换时数据库的DML压力。压力越大,切换速度越慢。
数据对象访问点切换
多主集群的隔离级别调整为数据对象级别后,同一个数据库下,可能会有多个对象类型,包括TABLE、VIEW、TRIGGER、FUNCTION、PROCEDURE、EVENT。如果需要切换这些对象的访问点,可以使用如下的切换语句:
ALTER obj_type name POLARDB_WRITE_NODE master_id;
其中obj_type可选的值分别为:TABLE、VIEW、TRIGGER、FUNCTION、PROCEDURE、EVENT。name为数据对象的名称。
示例1:把数据库db1
下的t1表的访问点切换到RW3。
ALTER TABLE db1.t1 POLARDB_WRITE_NODE 3;
示例2:把当前数据库下的t2 VIEW的访问点切换到RW2。
ALTER VIEW t2 POLARDB_WRITE_NODE 2;
示例3:把数据库db2
下的function f1和function f2的访问点切换到RW1。
ALTER FUNCTION db2.f1, db2.f2 POLARDB_WRITE_NODE 1;
正常情况下,访问点切换是一个耗时的操作。具体执行时间取决于以下因素:
切换时数据对象的DML压力。压力越大,切换速度越慢。
对象之间可能会有关联,如果关联对象的访问点没有在同一个RW上,可能会导致对象失效。
例如,视图VIEW1底层依赖表t1,但是视图VIEW1的访问点在RW1,而表t1的访问点在RW2。那么我们在RW1上访问视图VIEW1时会访问出错。同理,如果FUNCTION、PROCEDURE、EVENT引用的对象没有正确的访问点,也会导致执行失败。TRIGGER和TABLE的访问点不在一起,也会导致TABLE无法修改数据。
如果表t1和t2之间有外键约束关系,那么修改任意一个表的访问点,会自动修改另外一个表的访问点。
指定SQL语句执行的RW节点
该功能仅适用于非数据查询的语句,例如查询information_schema、查询status变量等。如果需要查询数据,例如查询语句SELECT * FROM table1
,不需要指定RW节点,数据库代理会自动选择正确的RW节点执行查询。
如果需要把某条SQL语句发送到指定的RW节点,则需要执行以下SQL语句锁定某个RW节点:
ALTER SESSION POLARDB_WRITE_NODE master_id;
示例:查询RW1节点上innodb_buffer_pool_size
这个变量的值。
ALTER SESSION POLARDB_WRITE_NODE 1; #把SQL语句发送到RW1节点。
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; #查询RW1节点上innodb_buffer_pool_size的值。
如果在执行某条SQL语句时不指定RW节点,那么数据库代理会随机选择一个RW节点执行该SQL语句。
执行以下命令可以解锁指定执行SQL语句的RW节点:
RESET SESSION POLARDB_WRITE_NODE;
查询节点信息
执行以下命令可以查询某个RW节点上的数据库分布情况:
ALTER SESSION POLARDB_WRITE_NODE master_id; SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
示例:查询RW1节点上的数据库分布情况。
ALTER SESSION POLARDB_WRITE_NODE 1; SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
查询结果如下:
SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X'; +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ | table_name | table_id | space_id | s_lock_count | lock_mode | object | current_lsn | hold_thread | hold_start_time | hold_total_time | +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ | test3/f1 | 9149389368458135753 | 0 | 0 | SLS_X | function | 28076635 | 17 | 2024-07-10 21:35:20 | 214 | | test3/e1 | 9149389368458332874 | 0 | 0 | SLS_X | event | 28077248 | 17 | 2024-07-10 21:35:30 | 204 | | test3/v1 | 9149389368457234649 | 0 | 0 | SLS_X | view | 28075972 | 17 | 2024-07-10 21:35:08 | 226 | | sbtest | 2107518311328629409 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-07 23:04:41 | 254053 | | test | 7190879906290573778 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-10 11:20:57 | 37077 | | test2 | 3381728963524265351 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-10 11:13:09 | 37545 | +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ 6 rows in set (0.00 sec)
上述查询结果中的每一行都是一个数据库或数据对象的信息(虽然列名是table_name)。上图中,
sbtest
、test
、test2
分别是数据库的隔离级别,function test3.f1
是数据对象隔离级别,event test3.e1
是数据对象隔离级别,view test3.v1
也是数据对象隔离级别。此外,可能会查询出名称为mysql/global_ddl_lock且object类型为Table的信息,这个是内部使用的信息,您无需关注。执行以下命令可以查询整个集群上所有数据库的分布情况:
说明仅支持通过高权限账号查询,您不能通过新建的账号进行查询。
SELECT * FROM INFORMATION_SCHEMA.INNODB_CC_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
查询结果如下:
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_CC_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X'; +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ | master_id | table_name | table_id | lock_mode | object | current_lsn | hold_start_time | hold_total_time | +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ | 1 | test3/v1 | 9149389368457234649 | SLS_X | view | 28075972 | 2024-07-10 21:35:08 | 754 | | 2 | test5/t1 | 9149389447232697561 | SLS_X | table | 7256175 | 2024-07-10 21:46:36 | 66 | | 1 | test2 | 3381728963524265351 | SLS_X | db | 28034927 | 2024-07-10 11:13:09 | 38073 | | 2 | test4 | 3381728963524272009 | SLS_X | db | 7255352 | 2024-07-10 21:46:27 | 75 | | 1 | test3/f1 | 9149389368458135753 | SLS_X | function | 28076635 | 2024-07-10 21:35:20 | 742 | | 1 | test3/e1 | 9149389368458332874 | SLS_X | event | 28077248 | 2024-07-10 21:35:30 | 732 | | 1 | test | 7190879906290573778 | SLS_X | db | 28034927 | 2024-07-10 11:20:57 | 37605 | | 2 | test5/p1 | 9149389447233473757 | SLS_X | procedure | 7257051 | 2024-07-10 21:46:45 | 57 | | 1 | sbtest | 2107518311328629409 | SLS_X | db | 28034927 | 2024-07-07 23:04:41 | 254581 | +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ 9 rows in set (0.00 sec)
上述查询结果中的每一行就是一个数据库或数据对象的信息(虽然列名是table_name),表示这个数据库或数据对象是在对应的RW上。此外,可能会查询出名称为mysql/global_ddl_lock且object类型为Table的信息,这个是内部使用的信息,您无需关注。
如何设置Binlog
多主集群(库表)100%兼容MySQL的Binlog,它整合集群中所有RW节点上的操作日志,产生出全局统一、逻辑有序的Binlog日志。
您可以通过loose_polar_log_bin来开启多主集群(库表)的Binlog功能,通过binlog_expire_logs_seconds来设置多主集群(库表)Binlog的保存时长。详细信息请参见开启Binlog。
多主集群(库表)可以作为数据传输服务DTS的源端和目的端,来进行数据的单向或双向同步。