读写分离 #
面对日益增加的系统访问量,数据库的吞吐能力面临着极大的挑战。 对于瞬时有大量并发读操作和较少写操作类型的应用系统来说,可将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
通过一主多从的配置方式,可以将查询请求均匀的或者按照权重分散到多个数据副本,能够进一步的提升系统的处理能力,同时也提升了从库资源的利用率。
概述 #
读写分离是一种数据库性能优化技术,在读请求明显多于写请求的业务场景中,使用读写分离技术可大幅度提升系统吞吐能力,即主库负责处理事务性的增删改请求,从库只负责处理查询请求。
读写分离是 SphereEx-DBPlusEngine 插件之一,可以对进入 SphereEx-DBPlusEngine 的业务流量做数据库层的读写分离处理,可支持配置动态读写分离和静态读写分离。
同时,SphereEx-DBPlusEngine 内置了多种读库负载均衡算法,包括轮询算法、随机访问算法和权重访问算法,能够满足用户绝大多数业务场景的需要,所支持的读库负载均衡算法参考负载均衡算法。
SphereEx-DBPlusEngine 读写分离所支持的数据库架构如下表。
MySQL | PostgreSQL | openGauss | GuassDB | AuroraDB | |
---|---|---|---|---|---|
静态规则 | 支持 | 支持 | 支持 | 支持 | 支持 |
动态规则 | 支持 MGR,MHA | 不支持 | 支持 | 支持 | 支持 |
SphereEx-DBPlusEngine 读写分离动态和静态读写分离规则所支持的功能如下表。
动态读写分离规则 | 静态读写分离规则 | |
---|---|---|
数据库拓扑探测 | 支持 | 不支持 |
主从延迟判断 | 支持(MHA) | 不支持 |
从库负载均衡 | 支持 | 支持 |
基本概念 #
- 主库
在读写分离场景中负责处理 INSERT
、UPDATE
以及 DELETE
请求的数据库。
- 从库
在读写分离场景中负责处理 SELECT
请求的数据库。
- 从库负载均衡
指在具有多个从库的集群环境中,可通过指定负载均衡策略对 SELECT
请求进行路由。
适用场景 #
- 读请求明显多于写请求的场景;
- 系统并发量大,连接数不足的场景;
- 对于数据查询实时性不敏感的场景。
使用前提 #
- 服务器中已安装 SphereEx-DBPlusEngine 和数据库集群,且服务运行正常;
- 如需使用动态读写分离规则,需要与数据库的发现规则搭配使用。
使用规范 #
支持项 #
- 提供一主多从的读写分离配置,可独立使用,也可配合数据分片使用;
- 事务中的数据读写均用主库;
- 基于 Hint 的强制主库路由;
- 从库全部宕机主库提供读流量。
不支持项 #
- 主库和从库的数据同步;
- 主库和从库的数据同步延迟导致的数据不一致;
- 主库多写;
- 主从库间的事务一致性。主从模型中,事务中的数据读写均用主库。
注意事项 #
由于主库和从库间的数据通常是以异步模式进行传输的,主库和从库数据会存在短暂不一致的情况,具体延时取决于部署环境。
在架构规划阶段,需考虑业务查询请求对数据时延的接受范围,通过在 SphereEx-DBPlusEngine 中配置主从延迟阈值(仅基于 MHA 的动态规则支持),来满足业务对延迟的要求。
原理介绍 #
SphereEx-DBPlusEngine 的读写分离主要依赖内核的相关功能,包括解析引擎和路由引擎。
SphereEx-DBPlusEngine 对 SQL 语义进行分析,读写分离模块将读操作和写操作分别路由至主库与从库,即解析引擎将用户的 SQL 转化为 SphereEx-DBPlusEngine 可以识别的 Statement 信息,路由引擎根据 SQL 的读写类型以及事务的状态来做 SQL 的路由。
在多从库的环境中,SphereEx-DBPlusEngine 支持配置多种负载均衡算法,包括轮询算法、随机访问算法和权重访问算法等,可参考概述中对负载均衡算法的描述。
SphereEx-DBPlusEngine 针对动态读写分离规则,提供了主从节点延迟校验机制,底层调用了 MySQL SHOW SLAVE STATUS
命令。当主从延迟超过设定阈值时,该从库会被禁用,不再提供查询服务,如果所有从节点的延迟都超过了设定阈值,可由主库承担读请求。当延迟恢复到低于阈值以内时,从库将重新提供读服务。该校验机制满足了不同业务场景对主从延迟要求的需求。配置方法参考数据库发现中关于 delay-milliseconds-threshold
参数的说明。
同时,通过 SphereEx-DBPlusEngine 的熔断能力可手动禁用和启用从读节点,用来应对如硬件、软件升级、网络维护等情况。
在读写分离的类别方面,SphereEx-DBPlusEngine 支持基于数据源的读写分离和基于 SQL Hint 的读写分离。
- 基于数据源
基于数据源的读写分离场景,SphereEx-DBPlusEngine 识别到 INSERT
、DELETE
、UPDATE
请求和 SELECT
请求,将 SQL 分别路由至不同的数据源中,如下图所示。
- 基于 SQL Hint
基于 SQL Hint 的读写分离场景,SphereEx-DBPlusEngine 可根据 SQL Hint 信息指定 SQL 配置读写规则,如指定某查询 SQL 必须检索主库数据,可满足对数据一致性有要求的业务场景。
使用指南 #
关于动态读写分离和静态读写分离的说明如下:
- 动态读写分离:SphereEx-DBPlusEngine 自动探测(依赖于数据库发现规则)数据库集群的主从角色,当数据库节点的角色发生变化时,读写分离的配置会自动调整,可支持 MGR、MHA 的高可用方案;
- 静态读写分离:在 SphereEx-DBPlusEngine 中固定主库和从库的配置,它不会动态感知主从角色变化。当出现角色变更时,需人工介入对读写分离做相应调整,可支持多种高可用方案。
- 环境确认
在使用 SphereEx-DBPlusEngine 读写分离插件前,需要对当前环境做较全面的确认,如数据库的主从架构信息、主从所有节点的硬件配置信息以及主从节点间网络的延迟等信息。
- 规则确认
- 动静规则
SphereEx-DBPlusEngine 提供了动态和静态读写分离配置规则。
对于 MGR 和 MHA 架构,建议使用动态读写分离规则,SphereEx-DBPlusEngine 会自动识别节点的角色,即可自适应主从角色的变化,无需人工介入调整读写分离策略。
对于使用了域名、VIP 的数据库集群,或 1 主 1 从最简架构,建议使用静态读写分离规则。
- 负载均衡
对于存在多个从节点的环境,一般场景里可考虑使用轮询负载。如从库的主机资源存在差异,可以考虑配置权重比例。
- 数据源确认及注册
依次确认所有数据源的连通性,可在 SphereEx-DBPlusEngine 所在节点进行访确认。
在 DBPlusEngine 中,通过 REGISTER STORAGE UNIT
命令对数据源进行注册。
- 创建数据库发现规则(可选)
如果选择使用动态读写分离规则,则需提前配置好数据库发现规则,如业务明确的主从延迟要求,需在该步骤进行配置。
- 创建读写分离规则
创建读写分离规则时,根据第二步所规划的规则进行配置,包括动静规则、负载均衡规则以及对应比例。
- 配置验证
创建测试表,使用 PREVIEW SQL
命令验证增删改查的路由情况,SELECT 语句的路由应指向从节点。
操作指南 #
动态读写分离的配置需要依赖于数据库发现规则,SphereEx-DBPlusEngine 可在数据库集群角色发生变化时动态、实时调整读写分离策略。由于本章节为读写分离插件介绍,因此关于数据库发现能力更详细说明,请参考数据库发现,操作步骤如下。
在 MGR 中创建数据库,准备好数据源
在 SphereEx-DBPlusEngine 中完成逻辑库的创建
添加数据源,完成集群构建
创建数据库发现规则
创建动态读写分离规则
创建测试表并插入测试数据
依次验证读/写请求的执行路径
对于静态读写分离,配置读写数据源信息即可,无需关注数据库发现规则。
操作示例 #
SphereEx-DBPlusEngine 的读写分离配置相对简单,下面通过两个常见的场景来快速了解 SphereEx-DBPlusEngine 动态和静态读写分离能力。
动态读写分离配置 #
环境说明 #
本场景基于 MGR 架构配置动态读写分离,使用 4 台测试机,其中 1 台用来部署 SphereEx-DBPlusEngine,另外 3 台为 MGR 一主两从。因该场为功能演示,因此测试机采用相对基本的配置(1c/2g)即可。
实例 | IP 地址 | 服务端口 | 主机名 | 备注 | |
---|---|---|---|---|---|
1 | DBPlusEngine 1.2.0 | 192.168.xx.102 | 3307 | dbplusengine | |
2 | MySQL 8.0.28 | 192.168.xx.103 | 3306 | db_1 | MGR Primary |
3 | MySQL 8.0.28 | 192.168.xx.104 | 3306 | db_2 | MGR Replica |
4 | MySQL 8.0.28 | 192.168.xx.105 | 3306 | db_3 | MGR Replica |
拓扑图 #
配置过程 #
- 在 MGR 中创建数据库,为后续构建集准备好数据源。
--登陆 MySQL 实例,创建名为 test 的数据库
# mysql -uroot -p -h192.168.xx.103 -P3306
mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.05 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
- 使用 MySQL 客户端登陆 SphereEx-DBPlusEngine,创建逻辑库。
--访问 DBPlusEngine 实例
# mysql -uroot -p -P3307 -h192.168.xx.102
mysql> SHOW DATABASES;
+--------------------+
| schema_name |
+--------------------+
| mysql |
| information_schema |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.06 sec)
mysql> CREATE DATABASE testdb;
Query OK, 0 rows affected (0.05 sec)
mysql> SHOW DATABASES;
+--------------------+
| schema_name |
+--------------------+
| mysql |
| information_schema |
| performance_schema |
| sys |
| testdb |
+--------------------+
5 rows in set (0.06 sec)
- 添加数据源,完成集群构建。
在 SphereEx-DBPlusEngine 注册 MGR 的各个节点。以下所添加资源为 Schema 级别,相比实例级别粒度更细。
mysql> USE testdb;
Database changed
mysql> REGISTER STORAGE UNIT ds_0 (
URL="jdbc:mysql://192.168.xx.103:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
), ds_1 (
URL="jdbc:mysql://192.168.xx.104:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
), ds_2 (
URL="jdbc:mysql://192.168.xx.105:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
);
Query OK, 0 rows affected (0.67 sec)
mysql> SHOW STORAGE UNITS\G
- 创建数据库发现规则。
动态读写分离的配置需要依赖于数据库发现规则,SphereEx-DBPlusEngine 即可在数据库集群角色发生变化时动态、实时调整读写分离策略。本章节为读写分离插件介绍,因此关于数据库发现能力更详细说明,请参考数据库发现”。
--创建数据库拓扑发现规则
mysql> CREATE DB_DISCOVERY RULE primary_replica_rule (
STORAGE_UNITS(ds_0,ds_1,ds_2),
TYPE(NAME='MySQL.MGR',PROPERTIES('group-name'='b309fcc3-93e8-11ec-b5bd-080027c850b1')),
HEARTBEAT(PROPERTIES('keep-alive-cron'='0/5 * * * * ?'))
);
Query OK, 0 rows affected (0.85 sec)
mysql> SHOW DB_DISCOVERY RULE primary_replica_rule\G
*************************** 1. row ***************************
group_name: primary_replica_rule
data_source_names: ds_0,ds_1,ds_2
primary_data_source_name: ds_0
discovery_type: {name=primary_replica_ds1_MySQL.MGR, type=MySQL.MGR, props={group-name=b309fcc3-93e8-11ec-b5bd-080027c850b1}}
discovery_heartbeat: {name=primary_replica_rule_heartbeat}
1 rows in set (0.01 sec)
该步骤创建了一个数据库的发现规则,发现的数据源范围是 ds_0、ds_1 和 ds_2,并标注数据库集群类型为 MGR,SphereEx-DBPlusEngine 每 5 秒探测一次拓扑结构及各个数据源的角色。
- 创建动态读写分离规则。
基于上一步配置的数据库拓扑发现规则来创建动态的读写分离规则。AUTO_AWARE_RESOURCE 对应着数据库拓扑发现规则的名称。
mysql> CREATE READWRITE_SPLITTING RULE dynamic_readwrite_rule (
AUTO_AWARE_RESOURCE=primary_replica_rule
);
Query OK, 0 rows affected (0.06 sec)
mysql> SHOW READWRITE_SPLITTING RULES;
+------------------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| name | auto_aware_data_source_name | write_data_source_name | read_data_source_names | load_balancer_type | load_balancer_props |
+------------------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
| dynamic_readwrite_rule | primary_replica_rule | ds_0 | ds_1,ds_2 | | |
+------------------------+-----------------------------+------------------------+------------------------+--------------------+---------------------+
1 row in set (0.05 sec)
- 创建测试表,并插入若干条记录。
mysql> DROP TABLE IF EXISTS t_user;
Query OK, 0 rows affected (1.16 sec)
mysql> CREATE TABLE `t_user` (
`id` int(8) not null,
`mobile` char(20) NOT NULL,
`id_card_no` varchar(18) NOT NULL,
PRIMARY KEY (`id`)
);
Query OK, 0 rows affected (1.20 sec)
mysql> INSERT INTO t_user (id, mobile, id_card_no) VALUES
(1,18236483857, 220605194709308170),
(2,15686689114, 360222198806088804),
(3,14523360225, 411601198601098107),
(4,18143924353, 540228199804231247),
(5,15523349333, 360924195311103360);
Query OK, 5 rows affected (0.40 sec)
- 验证写请求的执行路径。
PREVIEW 是 DBPlusEngine 用来确认 SQL 执行路由的命令,当命令执行后,只输出执行路径、不会真实被执行。
mysql> PREVIEW INSERT INTO t_user (id, mobile, id_card_no) VALUES (6,13261527931, 513229195302236086);
+------------------+----------------------------------------------------------------------------------------+
| data_source_name | actual_sql |
+------------------+----------------------------------------------------------------------------------------+
| ds_0 | INSERT INTO t_user (id, mobile, id_card_no) VALUES (6,13261527931, 513229195302236086) |
+------------------+----------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mysql> PREVIEW INSERT INTO t_user (id, mobile, id_card_no) VALUES (7,13921892133, 500108194806107214);
+------------------+----------------------------------------------------------------------------------------+
| data_source_name | actual_sql |
+------------------+----------------------------------------------------------------------------------------+
| ds_0 | INSERT INTO t_user (id, mobile, id_card_no) VALUES (7,13921892133, 500108194806107214) |
+------------------+----------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
通过以上输出信息确认,不同的 INSERT
请求均被 SphereEx-DBPlusEngine 路由到了 ds_0 当中,即 MGR 的主库,结果符合预期。
- 验证读请求的执行路径。
接下来通过 PREVIEW 命令验证查询操作的路由,根据读写分离的配置规则,返回结果应为 ds_1 或 ds_2。
mysql> PREVIEW SELECT * FROM t_user WHERE id=1;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_1 | SELECT * FROM t_user WHERE id=1 |
+------------------+---------------------------------+
1 row in set (0.05 sec)
mysql> PREVIEW SELECT * FROM t_user WHERE id=1;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_2 | SELECT * FROM t_user WHERE id=1 |
+------------------+---------------------------------+
1 row in set (0.06 sec)
mysql> PREVIEW SELECT * FROM t_user WHERE id=2;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_1 | SELECT * FROM t_user WHERE id=2 |
+------------------+---------------------------------+
1 row in set (0.01 sec)
mysql> PREVIEW SELECT * FROM t_user WHERE id=2;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_2 | SELECT * FROM t_user WHERE id=2 |
+------------------+---------------------------------+
1 row in set (0.05 sec)
通过以上输出信息确认,SELECT 请求被 SphereEx-DBPlusEngine 路由到了 ds_1 和 ds_2 中,同时以轮询方式进行查询,结果符合预期。
到这里,通过 SphereEx-DBPlusEngine 完成了基于 MGR 一主两从的动态读写分离场景的配置。
静态读写分离配置 #
相比动态读写分离,由于没有数据库拓扑发现的配置,静态的配置会更简单一些,准备好数据源之后,直接配置规则即可。同时,该示例中加入了权重的配置参考。
在主从集群中创建数据库,准备好数据源
在 SphereEx-DBPlusEngine 中完成逻辑库的创建
添加数据源,完成集群构建
创建静态读写分离规则
创建测试表并插入测试数据
依次验证读/写请求的执行路径
环境说明 #
实例 | IP 地址 | 服务端口 | 主机名 | 备注 | |
---|---|---|---|---|---|
1 | DBPlusEngine 1.2.0 | 192.168.xx.102 | 3307 | dbplusengine | |
2 | MySQL 8.0.28 | 192.168.xx.103 | 3306 | db_1 | MGR Primary |
3 | MySQL 8.0.28 | 192.168.xx.104 | 3306 | db_2 | MGR Replica |
4 | MySQL 8.0.28 | 192.168.xx.105 | 3306 | db_3 | MGR Replica |
拓扑图 #
配置过程 #
读写分离全量的 DistSQL请参考。
- 在主从集群中创建数据库,为后续构建集准备好数据源。
# mysql -uroot -p -h192.168.xx.103 -P3306
mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.05 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
- 使用 MySQL 客户端登陆 SphereEx-DBPlusEngine,创建逻辑库。
# mysql -uroot -p -P3307 -h192.168.xx.102
mysql> SHOW DATABASES;
+--------------------+
| schema_name |
+--------------------+
| mysql |
| information_schema |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
mysql> CREATE DATABASE testdb;
Query OK, 0 rows affected (0.05 sec)
mysql> SHOW DATABASES;
+--------------------+
| schema_name |
+--------------------+
| mysql |
| information_schema |
| performance_schema |
| sys |
| testdb |
+--------------------+
5 rows in set (0.05 sec)
- 添加数据源,完成集群构建。
mysql> USE testdb;
Database changed
mysql> REGISTER STORAGE UNIT ds_0 (
URL="jdbc:mysql://192.168.xx.103:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
), ds_1 (
URL="jdbc:mysql://192.168.xx.104:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
), ds_2 (
URL="jdbc:mysql://192.168.xx.105:3306/test?serverTimezone=UTC&useSSL=false",
USER="test",
PASSWORD="Test@123"
);
Query OK, 0 rows affected (0.62 sec)
mysql> SHOW STORAGE UNITS\G
- 创建静态读写分离规则。
在创建静态读写分离的过程中,需要在指定资源的位置配置所有的数据源名称。
mysql> CREATE READWRITE_SPLITTING RULE ms_group_0 (
WRITE_STORAGE_UNIT=ds_0,
READ_STORAGE_UNITS(ds_1,ds_2),
TYPE(NAME="random")
);
Query OK, 0 rows affected (0.26 sec)
mmysql> SHOW READWRITE_SPLITTING RULES;
+------------+-----------------------------+---------------------------------+-------------------------+-------------------------+--------------------+---------------------+
| name | auto_aware_data_source_name | write_data_source_query_enabled | write_storage_unit_name | read_storage_unit_names | load_balancer_type | load_balancer_props |
+------------+-----------------------------+---------------------------------+-------------------------+-------------------------+--------------------+---------------------+
| ms_group_0 | | | ds_0 | ds_1,ds_2 | random | |
+------------+-----------------------------+---------------------------------+-------------------------+-------------------------+--------------------+---------------------+
1 row in set (0.00 sec)
如上,即创建好了基于 1 主 2 从架构的静态读写分离规则。
- 创建测试表,并插入若干条记录。
--在 SphereEx-DBPlusEngine 中执行以下命令
mysql> DROP TABLE IF EXISTS t_user;
Query OK, 0 rows affected (0.05 sec)
mysql> CREATE TABLE `t_user` (
`id` int(8) not null,
`mobile` char(20) NOT NULL,
`id_card_no` varchar(18) NOT NULL,
PRIMARY KEY (`id`)
);
Query OK, 0 rows affected (1.15 sec)
mysql> INSERT INTO t_user (id, mobile, id_card_no) VALUES
(1,18236483857, 220605194709308170),
(2,15686689114, 360222198806088804),
(3,14523360225, 411601198601098107),
(4,18143924353, 540228199804231247),
(5,15523349333, 360924195311103360);
Query OK, 5 rows affected (0.16 sec)
- 验证写请求的执行路径。
通过 PREVIEW
命令确认 INSERT
语句的路由。
mysql> PREVIEW INSERT INTO t_user (id, mobile, id_card_no) VALUES (6,13261527931, 513229195302236086);
+------------------+----------------------------------------------------------------------------------------+
| data_source_name | actual_sql |
+------------------+----------------------------------------------------------------------------------------+
| ds_0 | INSERT INTO t_user (id, mobile, id_card_no) VALUES (6,13261527931, 513229195302236086) |
+------------------+----------------------------------------------------------------------------------------+
1 row in set (0.15 sec)
mysql> PREVIEW INSERT INTO t_user (id, mobile, id_card_no) VALUES (7,13921892133, 500108194806107214);
+------------------+----------------------------------------------------------------------------------------+
| data_source_name | actual_sql |
+------------------+----------------------------------------------------------------------------------------+
| ds_0 | INSERT INTO t_user (id, mobile, id_card_no) VALUES (7,13921892133, 500108194806107214) |
+------------------+----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
通过以上输出信息确认,不同的 INSERT
请求均被 SphereEx-DBPlusEngine 路由到了 ds_0 当中,即写入请求路到了主库,结果符合预期。
- 验证读请求的执行路径。
在规则中配置了读库权重信息,下面验证随机读是否生效。
mysql> PREVIEW SELECT * FROM t_user WHERE id=1;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_1 | SELECT * FROM t_user WHERE id=1 |
+------------------+---------------------------------+
1 row in set (0.10 sec)
mysql> PREVIEW SELECT * FROM t_user WHERE id=1;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_1 | SELECT * FROM t_user WHERE id=1 |
+------------------+---------------------------------+
1 row in set (0.00 sec)
mysql> PREVIEW SELECT * FROM t_user WHERE id=1;
+------------------+---------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------+
| ds_2 | SELECT * FROM t_user WHERE id=1 |
+------------------+---------------------------------+
1 row in set (0.04 sec)
通过以上输出信息确认,SELECT
请求被 SphereEx-DBPlusEngine 路由到了 ds_1 和 ds_2 中,从输出比例来看为 2:1 权重,结果符合预期。
到这里,通过 SphereEx-DBPlusEngine 完成了基于 1 主 2 从架构的静态读写分离场景的配置。
基于 SQL Hint #
SQL Hint 可将指定 SQL 路由到任意数据源,因此在读写分离的场景中,可通过 SQL Hint 对指定 SQL 做更灵活的配置。如某 SQL 必须检索主库数据的场景,可以使用 SQL Hint 的方式满足对数据一致性有要求的业务场景。
基于上一个场景的环境,下面验证下使用 SQL Hint 进行查询,通过 Hint 的方式将 SELECT * FROM t_user
请求路由到主库。
具体的使用方式是在 SQL 头部加上 /* SPHEREEX_HINT: WRITE_ROUTE_ONLY=true */
这样的注释信息即可。
为了验证 Hint 的干预结果,再次使用 PREVIEW 命令来验证 SQL 的执行路径,操作如下。
# mysql -uroot -p -h192.168.xx.102 -P3307 -c
-- 如果使用 MySQL 客户端进行验证,请务必加上 '-c' 参数,否则 hint 信息将无法生效
mysql> USE testdb;
mysql> PREVIEW SELECT * FROM t_user;
+------------------+----------------------+
| data_source_name | actual_sql |
+------------------+----------------------+
| ds_1 | SELECT * FROM t_user |
+------------------+----------------------+
1 row in set (0.04 sec)
mysql> /* SPHEREEX_HINT: WRITE_ROUTE_ONLY=true */ PREVIEW SELECT * FROM t_user;
+------------------+---------------------------------------------------------------------+
| data_source_name | actual_sql |
+------------------+---------------------------------------------------------------------+
| ds_0 | /* SPHEREEX_HINT: WRITE_ROUTE_ONLY=true */SELECT * FROM t_user|
+------------------+---------------------------------------------------------------------+
1 row in set (0.00 sec)
-- 在执行时,请确保 /* SPHEREEX_HINT: WRITE_ROUTE_ONLY=true */ 前没有空格
通过以上输出可见,当使用 Hint 进行干预时,指定的读请求语句已经被路由到了主库,符合预期。
参数 #
- delay-milliseconds-threshold
使用方式:delay-milliseconds-threshold: 时长(ms)
参数说明:该参数用来配置动态读写分离规则对主从延迟的限制,单位为 ms,取值范围为正整数。当超过设定阈值时,该从库将被禁用掉,当所有从库都超过设定阈值时,主库负责读和写。该参数需要在数据库发现规则中进行配置,请参考数据库发现内置算法说明。
- writeDataSourceQueryEnabled
参数说明:从库全部宕机时,该参数决定主库是否提供查询服务,支持动态及静态读写分离配置,默认值为 true
静态读写分离示例配置:
rules:
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
writeDataSourceName: write_ds
readDataSourceNames:
- read_ds_0
- read_ds_1
loadBalancerName: random
writeDataSourceQueryEnabled: true
loadBalancers:
random:
type: RANDOM
动态读写分离示例配置:
rules:
- !READWRITE_SPLITTING
dataSources:
replica_ds:
autoAwareDataSourceName: readwrite_ds
writeDataSourceQueryEnabled: true
- transactionalReadQueryStrategy
参数说明:事务内读请求的路由策略,可选值:PRIMARY(路由至主库)、FIXED(同一事务内路由至固定数据源)、DYNAMIC(同一事务内路由至非固定数据源),默认值:DYNAMIC
示例配置:
rules:
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
writeDataSourceName: write_ds
readDataSourceNames:
- read_ds_0
- read_ds_1
transactionalReadQueryStrategy: PRIMARY
loadBalancerName: random
loadBalancers:
random:
type: RANDOM
FAQ #
- 当主库(或从库)出现宕机故障后,读写分离的规则是否需要做调整?
如果配置的是动态读写分离规则,主库(或从库)宕机后不需要调整规则。
如果配置的是静态读写分离规则,则需运维人员介入,结合实际情况修改规则中的资源配置。
- 数据库集群添加新的从库后,如 1 主 2 从变为 1 主 3 从,读写分离的规则需要如何调整?
首先在数据库集群中添加从节点,确认数据已经完成同步。然后使用 DistSQL 将新的从节点信息配置到读写分离规则当中,配置完成后立即生效。
- 当数据库集群主从角色发生切换后,对动、静态读写分离的影响有哪些?
对动态读写分离规则无影响,动态读写分离基于数据库发现规则,读写流量会根据最新角色关系做数据路由。
对静态读写分离规则有影响,发生角色切换后,需运维人员及时变更读写分离策略。
- 当从库出现网络闪断时,业务的读请求会被如何处理?
基于动态规则:业务无影响,读请求只会路由到网正常的节点;
基于静态规则:业务受影响,读请会根据静态规则继续路由读请求,在网络闪断期间,业务会出现超时情况。需运维人员介入,及时禁用该节点,待网络恢复正常后再启用。