Logo
读写分离

读写分离 #

面对日益增加的系统访问量,数据库的吞吐能力面临着极大的挑战。 对于瞬时有大量并发读操作和较少写操作类型的应用系统来说,可将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的或者按照权重分散到多个数据副本,能够进一步的提升系统的处理能力,同时也提升了从库资源的利用率。

概述 #

读写分离是一种数据库性能优化技术,在读请求明显多于写请求的业务场景中,使用读写分离技术可大幅度提升系统吞吐能力,即主库负责处理事务性的增删改请求,从库只负责处理查询请求。

读写分离是 SphereEx-DBPlusEngine 插件之一,可以对进入 SphereEx-DBPlusEngine 的业务流量做数据库层的读写分离处理,可支持配置动态读写分离和静态读写分离。

读写分离架构图

同时,SphereEx-DBPlusEngine 内置了多种读库负载均衡算法,包括轮询算法、随机访问算法和权重访问算法,能够满足用户绝大多数业务场景的需要,所支持的读库负载均衡算法参考负载均衡算法

SphereEx-DBPlusEngine 读写分离所支持的数据库架构如下表。

MySQLPostgreSQLopenGaussGuassDBAuroraDB
静态规则支持支持支持支持支持
动态规则支持 MGR,MHA不支持支持支持支持

SphereEx-DBPlusEngine 读写分离动态和静态读写分离规则所支持的功能如下表。

动态读写分离规则静态读写分离规则
数据库拓扑探测支持不支持
主从延迟判断支持(MHA)不支持
从库负载均衡支持支持

基本概念 #

  • 主库

在读写分离场景中负责处理 INSERTUPDATE 以及 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 识别到 INSERTDELETEUPDATE 请求和 SELECT 请求,将 SQL 分别路由至不同的数据源中,如下图所示。

读写分离原理图

  • 基于 SQL Hint

基于 SQL Hint 的读写分离场景,SphereEx-DBPlusEngine 可根据 SQL Hint 信息指定 SQL 配置读写规则,如指定某查询 SQL 必须检索主库数据,可满足对数据一致性有要求的业务场景。

使用指南 #

关于动态读写分离和静态读写分离的说明如下:

  • 动态读写分离:SphereEx-DBPlusEngine 自动探测(依赖于数据库发现规则)数据库集群的主从角色,当数据库节点的角色发生变化时,读写分离的配置会自动调整,可支持 MGR、MHA 的高可用方案;
  • 静态读写分离:在 SphereEx-DBPlusEngine 中固定主库和从库的配置,它不会动态感知主从角色变化。当出现角色变更时,需人工介入对读写分离做相应调整,可支持多种高可用方案。
  1. 环境确认

在使用 SphereEx-DBPlusEngine 读写分离插件前,需要对当前环境做较全面的确认,如数据库的主从架构信息、主从所有节点的硬件配置信息以及主从节点间网络的延迟等信息。

  1. 规则确认
  • 动静规则

SphereEx-DBPlusEngine 提供了动态和静态读写分离配置规则。

对于 MGR 和 MHA 架构,建议使用动态读写分离规则,SphereEx-DBPlusEngine 会自动识别节点的角色,即可自适应主从角色的变化,无需人工介入调整读写分离策略。

对于使用了域名、VIP 的数据库集群,或 1 主 1 从最简架构,建议使用静态读写分离规则。

  • 负载均衡

对于存在多个从节点的环境,一般场景里可考虑使用轮询负载。如从库的主机资源存在差异,可以考虑配置权重比例。

  1. 数据源确认及注册

依次确认所有数据源的连通性,可在 SphereEx-DBPlusEngine 所在节点进行访确认。

在 DBPlusEngine 中,通过 REGISTER STORAGE UNIT 命令对数据源进行注册。

  1. 创建数据库发现规则(可选)

如果选择使用动态读写分离规则,则需提前配置好数据库发现规则,如业务明确的主从延迟要求,需在该步骤进行配置。

  1. 创建读写分离规则

创建读写分离规则时,根据第二步所规划的规则进行配置,包括动静规则、负载均衡规则以及对应比例。

  1. 配置验证

创建测试表,使用 PREVIEW SQL 命令验证增删改查的路由情况,SELECT 语句的路由应指向从节点。

操作指南 #

动态读写分离的配置需要依赖于数据库发现规则,SphereEx-DBPlusEngine 可在数据库集群角色发生变化时动态、实时调整读写分离策略。由于本章节为读写分离插件介绍,因此关于数据库发现能力更详细说明,请参考数据库发现,操作步骤如下。

  1. 在 MGR 中创建数据库,准备好数据源

  2. 在 SphereEx-DBPlusEngine 中完成逻辑库的创建

  3. 添加数据源,完成集群构建

  4. 创建数据库发现规则

  5. 创建动态读写分离规则

  6. 创建测试表并插入测试数据

  7. 依次验证读/写请求的执行路径

对于静态读写分离,配置读写数据源信息即可,无需关注数据库发现规则。

操作示例 #

SphereEx-DBPlusEngine 的读写分离配置相对简单,下面通过两个常见的场景来快速了解 SphereEx-DBPlusEngine 动态和静态读写分离能力。

动态读写分离配置 #

环境说明 #

本场景基于 MGR 架构配置动态读写分离,使用 4 台测试机,其中 1 台用来部署 SphereEx-DBPlusEngine,另外 3 台为 MGR 一主两从。因该场为功能演示,因此测试机采用相对基本的配置(1c/2g)即可。

实例IP 地址服务端口主机名备注
1DBPlusEngine 1.2.0192.168.xx.1023307dbplusengine
2MySQL 8.0.28192.168.xx.1033306db_1MGR Primary
3MySQL 8.0.28192.168.xx.1043306db_2MGR Replica
4MySQL 8.0.28192.168.xx.1053306db_3MGR Replica

拓扑图 #

动态读写分离

配置过程 #

  1. 在 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)
  1. 使用 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)
  1. 添加数据源,完成集群构建。

在 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
  1. 创建数据库发现规则。

动态读写分离的配置需要依赖于数据库发现规则,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 秒探测一次拓扑结构及各个数据源的角色。

  1. 创建动态读写分离规则。

基于上一步配置的数据库拓扑发现规则来创建动态的读写分离规则。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)
  1. 创建测试表,并插入若干条记录。
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)
  1. 验证写请求的执行路径。

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 的主库,结果符合预期。

  1. 验证读请求的执行路径。

接下来通过 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 一主两从的动态读写分离场景的配置。

静态读写分离配置 #

相比动态读写分离,由于没有数据库拓扑发现的配置,静态的配置会更简单一些,准备好数据源之后,直接配置规则即可。同时,该示例中加入了权重的配置参考。

  1. 在主从集群中创建数据库,准备好数据源

  2. 在 SphereEx-DBPlusEngine 中完成逻辑库的创建

  3. 添加数据源,完成集群构建

  4. 创建静态读写分离规则

  5. 创建测试表并插入测试数据

  6. 依次验证读/写请求的执行路径

环境说明 #

实例IP 地址服务端口主机名备注
1DBPlusEngine 1.2.0192.168.xx.1023307dbplusengine
2MySQL 8.0.28192.168.xx.1033306db_1MGR Primary
3MySQL 8.0.28192.168.xx.1043306db_2MGR Replica
4MySQL 8.0.28192.168.xx.1053306db_3MGR Replica

拓扑图 #

静态读写分离

配置过程 #

读写分离全量的 DistSQL请参考

  1. 在主从集群中创建数据库,为后续构建集准备好数据源。
# 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)
  1. 使用 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)
  1. 添加数据源,完成集群构建。
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
  1. 创建静态读写分离规则。

在创建静态读写分离的过程中,需要在指定资源的位置配置所有的数据源名称。

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 从架构的静态读写分离规则。

  1. 创建测试表,并插入若干条记录。
--在 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)
  1. 验证写请求的执行路径。

通过 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 当中,即写入请求路到了主库,结果符合预期。

  1. 验证读请求的执行路径。

在规则中配置了读库权重信息,下面验证随机读是否生效。

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 请求路由到主库。

使用 Hint

具体的使用方式是在 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. 当主库(或从库)出现宕机故障后,读写分离的规则是否需要做调整?

如果配置的是动态读写分离规则,主库(或从库)宕机后不需要调整规则。

如果配置的是静态读写分离规则,则需运维人员介入,结合实际情况修改规则中的资源配置。

  1. 数据库集群添加新的从库后,如 1 主 2 从变为 1 主 3 从,读写分离的规则需要如何调整?

首先在数据库集群中添加从节点,确认数据已经完成同步。然后使用 DistSQL 将新的从节点信息配置到读写分离规则当中,配置完成后立即生效。

  1. 当数据库集群主从角色发生切换后,对动、静态读写分离的影响有哪些?

对动态读写分离规则无影响,动态读写分离基于数据库发现规则,读写流量会根据最新角色关系做数据路由。

对静态读写分离规则有影响,发生角色切换后,需运维人员及时变更读写分离策略。

  1. 当从库出现网络闪断时,业务的读请求会被如何处理?

基于动态规则:业务无影响,读请求只会路由到网正常的节点;

基于静态规则:业务受影响,读请会根据静态规则继续路由读请求,在网络闪断期间,业务会出现超时情况。需运维人员介入,及时禁用该节点,待网络恢复正常后再启用。