审核你的分片数据库算法

ShardingSphere 5.2.0 的此演示详细阐述了使用特定 SQL 示例审核数据分片功能的实现逻辑。
2 位读者喜欢这篇文章。
Business woman on laptop sitting in front of window

图片来源:Mapbox Uncharted ERG, CC-BY 3.0 US

感谢 ShardingSphere 社区 的持续审查和反馈,开发了诸如 数据分片 和读/写分离等功能,我们的团队发现一些用户在使用数据分片功能时创建了许多分片。

在这种情况下,一个分片逻辑表可能对应 1,000 个物理表,这给用户带来了困扰。

例如,SELECT * FROM t_order 语句将导致全路由,这显然不适用于 OLTP。此 SQL 可以放在另一个 Proxy 中,以避免阻塞其他请求。

但是,如果用户不熟悉 Proxy 或如何编写 where 条件,并且不知道分片在此条件中不受支持,则仍然需要全路由。

全路由可能会降低 Proxy 的性能,甚至导致合理的请求失败。想象一下,一个物理数据库中有 1,000 个分片。如果它们并行执行,则需要 1,000 个连接;如果串行执行,则请求可能会导致超时。因此,社区用户询问是否可以直接拦截不合理的请求。

我们的团队考虑了这个问题一段时间。一种选择是简单地阻止全路由操作。这样做需要在代码中进行检查,并在配置文件中添加一个开关。另一方面,如果用户稍后需要将表设置为只读,或要求更新操作携带 limit,这是否意味着代码和配置再次更改?这种方法显然与 Proxy 的可插拔逻辑背道而驰。

为了响应上述问题,最近发布的 Apache ShardingSphere 5.2.0 为用户提供了 SQL 分片功能的审计。审计可以是拦截操作或统计操作。与分片和唯一键生成算法类似,审计算法是面向插件的、用户定义的和可配置的。

[ 相关阅读 Apache ShardingSphere 的 5 项新改进 ]

接下来,我将详细阐述使用特定 SQL 示例审核数据分片功能的实现逻辑。

分片接口的审计

Apache ShardingSphere 审计的入口点位于 org.apache.shardingsphere.infra.executor.check.SQLCheckEngine 类中,该类将调用 SQLChecker 接口的 check 方法。目前,ShardingSphere 审计包含权限审计(验证用户名和密码)和分片审计。

本示例重点介绍在分片审计的 ShardingAuditChecker 中实现的父接口。

Audit for sharding design

(Yacine Si Tayeb,CC BY-SA 4.0)

您可以通过查看 org.apache.shardingsphere.sharding.checker.audit.ShardingAuditCheckercheck 代码快速了解其工作原理。

public interface ShardingAuditAlgorithm extends ShardingSphereAlgorithm {
    
    /**
     * Sharding audit algorithm SQL check.
     *
     * @param sqlStatementContext SQL statement context
     * @param parameters SQL parameters
     * @param grantee grantee
     * @param database database
     * @return SQL check result
     */
    SQLCheckResult check(SQLStatementContext<?> sqlStatementContext, List<Object> parameters, Grantee grantee, ShardingSphereDatabase database);
}

此方法获取所有涉及的分片表的审计策略,并调用在每个分片表审计策略中配置的审计算法。如果审计算法未能通过,则会向用户显示异常。

一些用户可能想知道 disableAuditNames 在这里的作用。分片审计还允许用户跳过此过程。在某些情况下,用户可能需要执行本应被审计阻止的 SQL,并且他们知道此 SQL 的影响。

用户可以利用 Hint: disableAuditNames 跳过审计拦截,稍后将通过实际示例进行描述。Proxy 管理员可以配置 allowHintDisable 来控制是否允许用户跳过此过程。默认值为 true,表示允许基于 Hint 的跳过。

分片算法的审计

分片算法审计接口 org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm 继承自 SPI 类 ShardingSphereAlgorithm。它继承了 typeprops 属性,并定义了自己的 check 方法。如果您想自定义您的审计算法,只需实现该接口并将其添加到 INF.services 中。

Implement audit for sharding

(Yacine Si Tayeb,CC BY-SA 4.0)

public interface ShardingAuditAlgorithm extends ShardingSphereAlgorithm {
    
    /**
     * Sharding audit algorithm SQL check.
     *
     * @param sqlStatementContext SQL statement context
     * @param parameters SQL parameters
     * @param grantee grantee
     * @param database database
     * @return SQL check result
     */
    SQLCheckResult check(SQLStatementContext<?> sqlStatementContext, List<Object> parameters, Grantee grantee, ShardingSphereDatabase database);
}

Apache ShardingSphere 实现了分片算法的通用审计 org.apache.shardingsphere.sharding.algorithm.audit.DMLShardingConditionsShardingAuditAlgorithm,即上述拦截全路由的 SQL 语句。

该算法通过确定分片条件是否为 null 来做出决策。当然,它不会拦截广播表和非分片表。

public final class DMLShardingConditionsShardingAuditAlgorithm implements ShardingAuditAlgorithm {
    
    @Getter
    private Properties props;
    
    @Override
    public void init(final Properties props) {
        this.props = props;
    }
    
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public SQLCheckResult check(final SQLStatementContext<?> sqlStatementContext, final List<Object> parameters, final Grantee grantee, final ShardingSphereDatabase database) {
        if (sqlStatementContext.getSqlStatement() instanceof DMLStatement) {
            ShardingRule rule = database.getRuleMetaData().getSingleRule(ShardingRule.class);
            if (rule.isAllBroadcastTables(sqlStatementContext.getTablesContext().getTableNames())
                    || sqlStatementContext.getTablesContext().getTableNames().stream().noneMatch(rule::isShardingTable)) {
                return new SQLCheckResult(true, "");
            }
            ShardingConditionEngine shardingConditionEngine = ShardingConditionEngineFactory.createShardingConditionEngine(sqlStatementContext, database, rule);
            if (shardingConditionEngine.createShardingConditions(sqlStatementContext, parameters).isEmpty()) {
                return new SQLCheckResult(false, "Not allow DML operation without sharding conditions");
            }
        }
        return new SQLCheckResult(true, "");
    }
    
    @Override
    public String getType() {
        return "DML_SHARDING_CONDITIONS";
    }
}

我想介绍另一种分片算法的审计:LimitRequiredShardingAuditAlgorithm。此算法可以拦截在 updatedelete 操作中未携带 limit 的 SQL。

由于此算法的通用性较差,因此目前尚未集成到 Apache ShardingSphere 中。如您所见,实现自定义算法非常容易,这就是为什么需要分片框架审计的原因。得益于其面向插件的架构,ShardingSphere 具有出色的可扩展性。

public final class LimitRequiredShardingAuditAlgorithm implements ShardingAuditAlgorithm {
    
    @Getter
    private Properties props;
    
    @Override
    public void init(final Properties props) {
        this.props = props;
    }
    
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public SQLCheckResult check(final SQLStatementContext<?> sqlStatementContext, final List<Object> parameters, final Grantee grantee, final ShardingSphereDatabase database) {
        if (sqlStatementContext instanceof UpdateStatementContext && !((MySQLUpdateStatement) sqlStatementContext.getSqlStatement()).getLimit().isPresent()) {
            return new SQLCheckResult(false, "Not allow update without limit");
        }
        if (sqlStatementContext instanceof DeleteStatementContext && !((MySQLDeleteStatement) sqlStatementContext.getSqlStatement()).getLimit().isPresent()) {
            return new SQLCheckResult(false, "Not allow delete without limit");
        }
        return new SQLCheckResult(true, "");
    }
    
    @Override
    public String getType() {
        return "LIMIT_REQUIRED";
    }
}

使用分片审计

分片审计要求您为逻辑表配置审计策略。为了帮助您快速入门,其配置与分片算法和分片键值生成器的配置相同。

有算法定义和策略定义,也支持默认审计策略。如果在逻辑表中配置了审计策略,则它仅影响该逻辑表。

如果在逻辑表中配置了 defaultAuditStrategy,则它对分片规则下的所有逻辑表生效。Auditors 类似于 ShardingAlgorithmsauditStrategy 类似于 databaseStrategy,而 defaultAuditStrategy 类似于 defaultDatabaseStrategydefaultTableStrategy

请参考以下示例。仅显示了分片审计的配置。您必须自己配置分片算法和数据源。

rules:
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_${0..1}.t_order_${0..1}
        auditStrategy:
          auditorNames:
            - sharding_key_required_auditor
          allowHintDisable: true
    defaultAuditStrategy:
      auditorNames:
        - sharding_key_required_auditor
      allowHintDisable: true
    auditors:
      sharding_key_required_auditor:
        type: DML_SHARDING_CONDITIONS

步骤 1:执行查询操作。由于配置了拦截全数据库路由的审计策略,因此显示错误。

mysql> select * from t_order;
ERROR 13000 (44000): SQL check failed, error message: Not allow DML operation without sharding conditions

步骤 2:添加 HINTHINT 的名称为 /* ShardingSphere hint: disableAuditNames */disableAuditNames 后跟前面命令中配置的 auditorsNames

如果存在多个名称,请用空格分隔它们,例如 /* ShardingSphere hint: disableAuditNames=auditName1 auditName2*/。使用 HINT 后,您可以看到 SQL 操作已成功执行。

mysql> /* ShardingSphere hint: disableAuditNames=sharding_key_required_auditor */ select * from t_order;
+----------+---------+------------+--------+
| order_id | user_id | address_id | status |
+----------+---------+------------+--------+
|       30 |      20 |         10 | 20     |
|       32 |      22 |         10 | 20     |
+----------+---------+------------+--------+
2 rows in set (0.01 sec)

注意HINT 要求您修改 Proxy 的 server.yaml 配置文件。此外,如果您使用 MySQL 终端直接连接到 Proxy,则需要添加 -c 属性——否则,HINT 注释将被 MySQL 终端过滤掉,并且不会被后端的 Proxy 解析。

rules:
  - !SQL_PARSER
    sqlCommentParseEnabled: true
    sqlStatementCache:
      initialCapacity: 2000
      maximumSize: 65535
    parseTreeCache:
      initialCapacity: 128
      maximumSize: 1024
props:
  proxy-hint-enabled: true
mysql -uroot -proot -h127.0.0.1 -P3307  -c

带有分片审计的 DistSQL

如您从 发行说明 中所见,Apache ShardingSphere 5.2.0 支持以下带有分片功能审计的 DistSQL

CREATE SHARDING AUDITOR
ALTER SHARDING AUDITOR
SHOW SHARDING AUDIT ALGORITHMS
The following DistSQL will be supported in future releases:

DROP SHARDING AUDITOR
SHOW UNUSED SHARDING AUDIT ALGORITHMS
CREATE SHARDING TABLE RULE # including AUDIT_STRATEGY

这篇文章介绍了分片审计如何通过具体示例工作。我相信您已经对此功能有了基本的了解,并且可以在需要时使用它,或者使用自定义算法。

也欢迎您向社区提交通用算法。如果您有任何想法要贡献或在使用 ShardingSphere 时遇到问题,请随时在 GitHub 上发布它们。


本文最初出现在 ShardingSphere 5.2.0:分片审计在多分片场景中拦截不合理的请求 上,并经许可重新发布。

接下来阅读什么
标签
Yacine Si Tayeb
我热衷于技术和创新。我搬到北京攻读管理学博士学位,并对当地的创业和科技景象感到敬畏。到目前为止,我的职业道路是由技术和商业交叉领域的机会塑造的。

评论已关闭。

© . All rights reserved.