Logo
影子库压测

影子库压测 #

在基于微服务的分布式应用架构下,业务需要多个服务是通过一系列的服务、中间件的调用来完成,所以单个服务的压力测试已无法代表真实场景。 在测试环境中,如果重新搭建一整套与生产环境类似的压测环境,成本过高,并且往往无法模拟线上环境的复杂度以及流量。 因此,业内通常选择全链路压测的方式,即在生产环境进行压测,这样所获得的测试结果能够准确地反应系统真实容量和性能水平。

概述 #

基于内核的 SQL 解析能力以及可插拔平台架构,可实现压测数据与生产数据的隔离,帮助应用自动路由,支持全链路压测。帮助用户实现在生产环境进行压测,来获得较为准确的系统真实容量水平和性能测试结果。

SphereEx-DBPlusEngine 关注于全链路压测场景下数据库层面的解决方案,将压测数据自动路由至用户指定的数据库,是 SphereEx-DBPlusEngine 影子库插件的主要设计目标。

全链路压测是一项复杂而庞大的工作。 需要各个微服务、中间件之间配合与调整,以应对不同流量以及压测标识的透传。 通常会搭建一整套压测平台以适用不同测试计划。 在数据库层面需要做好数据隔离,为了保证生产数据的可靠性与完整性,需要将压测产生的数据路由到压测环境数据库,防止压测数据对生产数据库中真实数据造成污染。 这就要求业务应用在执行 SQL 前,能够根据透传的压测标识,做好数据分类,将相应的 SQL 路由到与之对应的数据源。

影子库

核心概念 #

  • 生产库

生产环境使用的数据库。

  • 影子库

压测中用来存储压测数据的数据库,应与生产数据库使用相同的配置。

适用场景 #

在基于微服务的分布式应用架构下,为了提升系统压力测试的准确性、降低测试成本,通常选择在生产环境进行压力测试,测试中风险也会大大提高。 通过 SphereEx-DBPlusEngine 影子库插件能力,结合影子算法灵活的配置,可以获取系统真实的吞吐能力,同时可避免数据污染,满足复杂业务场景的在线压力测试需求。

使用前提 #

  • 服务器中已安装 SphereEx-DBPlusEngine 和数据库集群,且服务运行正常;
  • 已完成 SphereEx-Console 安装部署,在压测中实时掌握 SphereEx-DBPlusEngine 负载情况;(可选)
  • 对于需要人为触发 Hint 的压测场景,MySQL 客户端需要使用 -c 参数,开启注释功能。

使用限制 #

基于 Hint 的影子算法

  • 无。

基于列的影子算法

  • 不支持情况:

    • 不支持 DDL。

    • 不支持范围、分组和子查询,如:BETWEENGROUP BY … HAVING 等。

  • 支持情况:

    • INSERT
    SQL是否支持
    1INSERT INTO table (column,…) VALUES (value,…)支持
    2INSERT INTO table (column,…) VALUES (value,…),(value,…),…支持
    3INSERT INTO table (column,…) SELECT column1 from table1 where column1 = value1不支持
    • SELECT/UPDATE/DELETE
    条件类型
    SQL是否支持
    1=SELECT/UPDATE/DELETE … WHERE column = value支持
    2LIKE/NOT LIKESELECT/UPDATE/DELETE … WHERE column LIKE/NOT LIKE value支持
    3IN/NOT INSELECT/UPDATE/DELETE … WHERE column IN/NOT IN (value1,value2,…)支持
    4BETWEENSELECT/UPDATE/DELETE … WHERE column BETWEEN value1 AND value2不支持
    5GROUP BY … HAVING…SELECT/UPDATE/DELETE … WHERE … GROUP BY column HAVING column > value不支持
    6子查询SELECT/UPDATE/DELETE … WHERE column = (SELECT column FROM table WHERE column = value)不支持

注意事项 #

使用影子库压测方案时,需充分考虑业务系统的高可用问题,因此建议部署多个 SphereEx-DBPlusEngine 节点进行压测,避免发生单点故障。关于应用接入方案,可选择使用连接池配置多个 SphereEx-DBPlusEngine 地址,或采用其他成熟的负载均衡方案均可。

原理介绍 #

SphereEx-DBPlusEngine 通过解析 SQL,对传入的 SQL 进行影子判定,根据配置文件中用户设置的影子规则,将请求路由到生产库或者影子库。

影子库原理

影子算法和业务实现紧密相关,目前提供基于列和基于 Hint 共两种类型影子算法。

  • 基于列的影子算法:通过识别 SQL 中的数据,匹配路由至影子库的场景。 适用于由压测数据名单驱动的压测场景,支持精准匹配字段值和正则匹配字段值。

  • 基于 Hint 的影子算法:通过识别 SQL 中的「注释」,匹配路由至影子库的场景。 适用于由上游系统透传标识驱动的压测场景。

以 INSERT 语句为例,在写入数据时,SphereEx-DBPlusEngine 会对 SQL 进行解析,再根据配置文件中的规则,构造一条路由链。 在当前版本的功能中,影子功能处于路由链中的最后一个执行单元,即如果有其他需要路由的规则存在,如分片场景,SphereEx-DBPlusEngine 会首先根据分片规则,路由到某一个数据库,再执行影子路由判定流程,判定执行SQL满足影子规则的配置,数据路由到与之对应的影子库,生产数据则维持不变。

关于 DML 语句,SphereEx-DBPlusEngine 支持基于列和基于 Hint 两种影子库算法。

影子判定会首先判断执行 SQL 相关表与配置的影子表是否有交集。如果有交集,依次判定交集部分影子表关联的影子算法,有任何一个判定成功。SQL 语句路由到影子库。 影子表没有交集或者影子算法判定不成功,SQL 语句路由到生产库。

关于 DDL 语句,SphereEx-DBPlusEngine 仅支持 Hint 影子算法。在压测场景下,DDL 语句一般不需要测试。主要在初始化或者修改影子库中影子表时使用。 影子判定会首先判断执行 SQL 是否包含注解。如果包含注解,影子规则中配置的 HINT 影子算法依次判定。有任何一个判定成功,SQL 语句路由到影子库。 执行 SQL 不包含注解或者 HINT 影子算法判定不成功,SQL 语句路由到生产库。

使用指南 #

基于生产环境,需要部署数个 SphereEx-DBPlusEngine 来承载业务流量,具体配置及数量视压测规模而定。还需要部署一套与生产库配置、架构一致的影子库来承载压测数据。

  1. 环境确认

在使用 SphereEx-DBPlusEngine 读写分离插件前,需要对当前环境做较全面的确认,如生产库和影子库的配置信息、数据库软件版本信息,以及应用服务器到生产库和影子库的网络延迟等信息。

  1. 规则确认

根据压测内容,参考影子库使用限制选择合适的基于列或者基于 Hint 算法,也可同时配置两种算法。

  1. 数据源确认及注册

依次确认所有生产、影子数据源的连通性,可在 SphereEx-DBPlusEngine 所在节点进行访确认。 在 SphereEx-DBPlusEngine 中,通过 REGISTER STORAGE UNIT 命令对数据源进行注册。

  1. 创建影子库规则

创建影子库规则时,根据第二步所规划的规则进行配置,选择合适的影子库算法,或混合使用两种影子库算法。

  1. 影子配置验证

使用 PREVIEW SQL 命令验证 SQL 路由情况,该命令不会真实执行 SQL,仅仅确认执行路径。如果影子库规则未生效,请再次确认影子库规则配置详情以及压测 SQL 特征。 请务必确认影子规则准确无误后,再进入全链路压测流程。

  1. 修改应用程序 url

将应用程序中数据库的访问信息修改为 SphereEx-DBPlusEngine 的访问地址,可通过连接池配置或其他负载均衡方案完成应用程序接入。

  1. 进入压测流程

在合适的压测时间段,使用压测工具开始对系统进行全链路压测,压测过程需要通过 SphereEx-Console 实时观察 SphereEx-DBPlusEngine 负载情况。

  1. 再次修改应用程序 url

全链路压测完成后,可将应用程序中数据库访问信息修改回数据库的地址,恢复系统拓扑。

  1. 影子库处理

最后,根据使用需求,可对影子库中的测试数据保留或清理。如需清理,清理前请务必确保访问的数据库是影子库,避免对生产库误操作带来损失。

操作指南 #

  1. 准备一个 SphereEx-DBPlusEngine 实例,部署操作将不再演示,准备影子库
  2. 在 SphereEx-DBPlusEngine 中完成逻辑库的创建
  3. 添加数据源,完成集群构建
  4. 创建影子库规则及创建影子表
  5. 验证影子规则生效情况

配置示例 #

环境说明 #

本示例中,需使用 3 台测试机,分别部署 1 个 SphereEx-DBPlusEngine 实例和 2 个 MySQL 实例。

实例IP 地址服务端口主机名备注
1DBPlusEngine 1.2.0192.168.xx.1023307dbplusengine
2MySQL 8.0.28192.168.xx.1033306ds_0生产库
3MySQL 8.0.28192.168.xx.1043306ds_1影子库

拓扑图 #

拓扑图

配置过程 #

  1. 准备生产库、影子库数据源

创建 ds_product 数据源,模拟生产库,同时创建 t_user 表并插入若干条记录。

mysql -uroot -p -h192.168.xx.103 -P3306

CREATE DATABASE IF NOT EXISTS ds_product;
Query OK, 1 row affected (0.01 sec)

USE ds_product;
Database changed

CREATE TABLE t_user
(
    mobile char(11) PRIMARY KEY,
    status varchar(18)  NOT NULL,
    type   varchar(255) NOT NULL
);
Query OK, 0 rows affected (0.11 sec)

SHOW TABLES;
+----------------------+
| Tables_in_ds_product |
+----------------------+
| t_user               |
+----------------------+
1 row in set (0.00 sec)

INSERT INTO t_user (mobile, status, type)
VALUES (18099515621, 1, 'ds_product'),
       (15639784703, 1, 'ds_product'),
       (15716172114, 1, 'ds_product'),
       (18766747515, 1, 'ds_product'),
       (18099515602, 1, 'ds_product'),
       (15639784713, 1, 'ds_product'),
       (18099515622, 1, 'ds_product'),
       (15639784513, 1, 'ds_product'),
       (15716173114, 1, 'ds_product'),
       (18766746515, 1, 'ds_product');
Query OK, 10 rows affected (0.06 sec)
Records: 10  Duplicates: 0  Warnings: 0

SELECT * FROM t_user;
+-------------+--------+------------+
| mobile      | status | type       |
+-------------+--------+------------+
| 15639784513 | 1      | ds_product |
| 15639784703 | 1      | ds_product |
| 15639784713 | 1      | ds_product |
| 15716172114 | 1      | ds_product |
| 15716173114 | 1      | ds_product |
| 18099515602 | 1      | ds_product |
| 18099515621 | 1      | ds_product |
| 18099515622 | 1      | ds_product |
| 18766746515 | 1      | ds_product |
| 18766747515 | 1      | ds_product |
+-------------+--------+------------+
10 rows in set (0.00 sec)

创建 ds_shadow 数据源,为影子库。

mysql -uroot -p -h192.168.xx.104 -P3306

CREATE DATABASE IF NOT EXISTS ds_shadow;
Query OK, 1 row affected (0.05 sec)

CREATE TABLE t_user
(
    mobile char(11) PRIMARY KEY,
    status varchar(18)  NOT NULL,
    type   varchar(255) NOT NULL
);
Query OK, 0 rows affected (0.11 sec)
  1. 使用 MySQL 客户端登陆 SphereEx-DBPlusEngine,创建逻辑库

注意:请务必加 -c 参数进行访问,来确保后续带有注释的 SQL 可生效。

--访问 DBPlusEngine 实例
mysql -uroot -p -P3307 -h192.168.xx.102 -c

CREATE DATABASE testdb;
Query OK, 0 rows affected (0.21 sec)

SHOW DATABASES;
5 rows in set (0.00 sec)
  1. 添加数据源,完成集群构建

在 SphereEx-DBPlusEngine 中注册两个数据库实例。

USE testdb;
Database changed

REGISTER STORAGE UNIT ds_0 (
     URL="jdbc:mysql://192.168.xx.103:3306/ds_product?serverTimezone=UTC&useSSL=false",
     USER="test",
     PASSWORD="Test@123"
), ds_1 (
     URL="jdbc:mysql://192.168.xx.104:3306/ds_shadow?serverTimezone=UTC&useSSL=false",
     USER="test",
     PASSWORD="Test@123"
);
Query OK, 0 rows affected (0.05 sec)

SHOW STORAGE UNITS\G
  1. 创建影子库规则及创建影子表

注意:此处创建影子表使用了注释操作,建表之前请再次确认该会话是通过 -c 参数开启的。

--创建影子库规则
CREATE SHADOW RULE shadow_rule(
    SOURCE=ds_0,
    SHADOW=ds_1,
    t_user(TYPE(NAME=VALUE_MATCH, PROPERTIES("operation"="insert","column"="status", "value"='2' )))
);
Query OK, 0 rows affected (0.20 sec)

该步骤创建了一个影子库规则,其中包括了基于值和基于 hint 的影子算法匹配:

  • 基于值匹配:当 insert 操作中,status 为 2 的记录会被写入到影子库中
SHOW SHADOW RULES;
+-------------+-------------+-------------+--------------+
| rule_name   | source_name | shadow_name | shadow_table |
+-------------+-------------+-------------+--------------+
| shadow_rule | ds_0        | ds_1        | t_user       |
+-------------+-------------+-------------+--------------+
1 row in set (0.10 sec)
  1. 验证影子规则生效情况 先通过 PREVIEW 命令验证影子规则已生效,复合影子库规则的数据应被写入到 ds_1 数据源中。
PREVIEW INSERT INTO t_user (mobile, status, type) VALUES (18236483857, 2, 'ds_shadow');
+------------------+--------------------------------------------------------------------------------+
| data_source_name | actual_sql                                                                     |
+------------------+--------------------------------------------------------------------------------+
| ds_1             | INSERT INTO t_user (mobile, status, type) VALUES (18236483857, 2, 'ds_shadow') |
+------------------+--------------------------------------------------------------------------------+
1 row in set (0.50 sec)

根据如上结果确认,复合影子规则的两条记录将会写入到影子库中,符合预期,下面将在 SphereEx-DBPlusEngine 中插入测试数据。

--在 Proxy 中查询 t_user 表的信息
SELECT * FROM t_user;
+-------------+--------+------------+
| mobile      | status | type       |
+-------------+--------+------------+
| 15639784513 | 1      | ds_product |
| 15639784703 | 1      | ds_product |
| 15639784713 | 1      | ds_product |
| 15716172114 | 1      | ds_product |
| 15716173114 | 1      | ds_product |
| 18099515602 | 1      | ds_product |
| 18099515621 | 1      | ds_product |
| 18099515622 | 1      | ds_product |
| 18766746515 | 1      | ds_product |
| 18766747515 | 1      | ds_product |
+-------------+--------+------------+
10 rows in set (0.01 sec)

--基于影子库列值算法的测试数据
INSERT INTO t_user (mobile, status, type)
VALUES (18236483857, 2, 'ds_shadow'),
       (15686689114, 2, 'ds_shadow'),
       (14523360225, 2, 'ds_shadow'),
       (18143924353, 2, 'ds_shadow'),
       (15523349333, 2, 'ds_shadow'),
       (18143924153, 2, 'ds_shadow'),
       (15523349313, 2, 'ds_shadow'),
       (18143924253, 2, 'ds_shadow'),
       (15523349323, 2, 'ds_shadow'),
       (13261527931, 2, 'ds_shadow');
Query OK, 10 rows affected (0.06 sec)

mysql> SELECT * FROM t_user;
+-------------+--------+------------+
| mobile      | status | type       |
+-------------+--------+------------+
| 15639784513 | 1      | ds_product |
| 15639784703 | 1      | ds_product |
| 15639784713 | 1      | ds_product |
| 15716172114 | 1      | ds_product |
| 15716173114 | 1      | ds_product |
| 18099515602 | 1      | ds_product |
| 18099515621 | 1      | ds_product |
| 18099515622 | 1      | ds_product |
| 18766746515 | 1      | ds_product |
| 18766747515 | 1      | ds_product |
+-------------+--------+------------+
10 rows in set (0.01 sec)

可见,在插入符合影子库的数据后,SphereEx-DBPlusEngine 中仍然只能查到生产库的数据,符合预期。

最后,在影子库中确认数据。

SELECT * FROM t_user;
+-------------+--------+-----------+
| mobile      | status | type      |
+-------------+--------+-----------+
| 13261527931 | 2      | ds_shadow |
| 14523360225 | 2      | ds_shadow |
| 15523349313 | 2      | ds_shadow |
| 15523349323 | 2      | ds_shadow |
| 15523349333 | 2      | ds_shadow |
| 15686689114 | 2      | ds_shadow |
| 18143924153 | 2      | ds_shadow |
| 18143924253 | 2      | ds_shadow |
| 18143924353 | 2      | ds_shadow |
| 18236483857 | 2      | ds_shadow |
| 18816175114 | 0      | ds_shadow |
+-------------+--------+-----------+
11 rows in set (0.00 sec)

从输出结果确认,能够看到 status 为 2 和 0 的数据,影子库场景的验证结果符合预期。

FAQ #

  1. 使用影子库压测方案是否会给生产库带来影响?

不会有影响。在正确配置了规则的前提下,影子库会对测试数据进行隔离,不会对生产库带来任何影响。

  1. 能否创建两个完全一样的影子规则?

不支持。在 SphereEx-DBPlusEngine 可创建多个影子库规则,但是不能作用于同一个字段。