用DistSQL建立一个数据分片服务的方法

133 阅读7分钟

如果你正在阅读这篇文章,那么你可能熟悉数据查询和编程语言,SQL(结构化查询语言)。它也被用作管理系统的标准语言,用于访问数据、查询、更新和管理关系型数据库系统。与标准SQL、DistSQL或分布式SQL一样,它是ShardingSphere独有的内置SQL语言,提供超出标准SQL的增量功能。利用ShardingSphere强大的SQL解析引擎,DistSQL提供了与标准SQL一样的语法结构和语法验证系统,使DistSQL在保持规律性的同时更加灵活。ShardingSphere的Database Plus概念旨在创建一个开源的分布式数据库系统,其功能和与实际数据库业务相关。DistSQL建立在传统数据库之上,提供既符合标准又具有ShardingSphere功能的SQL功能,以加强传统数据库管理。

DistSQL的设计初衷

经过多年的快速发展,ShardingSphere的内核逐渐稳定,核心功能不断磨合,已经在数据库中间件领域独树一帜。作为亚洲的开源领导者,ShardingSphere不断追求对分布式数据库生态系统的探索。重新定义中间件和数据库之间的界限,让开发者能够利用Apache ShardingSphere,就像他们原生使用数据库一样,这是DistSQL的设计目标。它也是ShardingSphere从面向开发者的框架和中间件转变为面向运营的基础设施产品的能力的一个组成部分。

DistSQL的语法系统

DistSQL从一开始就被设计为面向标准,考虑到数据库开发者和操作者的习惯。DistSQL的语法基于标准的SQL语言,在保持可读性和易用性的同时,最大限度地保留了ShardingSphere自身的功能,为用户提供了尽可能多的定制选项,以应对不同的业务场景。

熟悉SQL和ShardingSphere的开发人员可以快速上手。

标准SQL提供不同类型的语法,如DQL、DDL、DML、DCL等,以定义各种功能的SQL语句。DistSQL也定义了一个自己的语法系统。

在ShardingSphere中,DistSQL语法目前分为三种主要类型。RDL、RQL和RAL。

  • RDL(资源与规则定义语言)--资源规则定义语言,用于创建、修改和删除资源和规则。
  • RQL(资源和规则查询语言)--资源规则查询语言,用于查询和展示资源和规则。
  • RAL (Resource & Rule Administrate Language) - 资源规则管理语言,用于增量功能操作,如提示、交易类型切换和查询分片执行计划。

DistSQL的语法为ShardingSphere走向分布式数据库搭建了一座桥梁。随着更多想法的实现,它还在不断改进,所以DistSQL将变得越来越强大。欢迎有兴趣的开发者加入ShardingSphere,为DistSQL贡献想法和代码。

关于更详细的语法规则,请参考官方文档

实践中的DistSQL

在了解了DistSQL的设计理念和语法体系后,我们来演示一下如何在ShardingSphere的基础上构建一个数据分片服务。

环境准备

  • 启动MySQL服务
  • 创建一个用于分片的MySQL数据库
  • 启动Zookeeper服务
  • 打开分布式治理配置,启动ShardingSphere-Proxy

实际演示

1.使用MySQL命令行连接到启动的ShardingSphere-Proxy。

2.创建并查询分布式数据库sharding_db

mysql> CREATE DATABASE sharding_db;
Query OK, 0 ROWS affected (0.04 sec)
mysql> SHOW DATABASES;
+-------------+
| SCHEMA_NAME |
+-------------+
| sharding_db |
+-------------+
1 ROW IN SET (0.04 sec)

3.使用新创建的数据库。

mysql> USE sharding_db;
No connection. Trying TO reconnect...
Connection id: 2
CURRENT DATABASE: *** NONE ***
DATABASE changed

4.执行RDL,配置两个数据源资源,ds_1ds_2 ,进行分片。

mysql> ADD RESOURCE ds_1 (
    -> HOST=127.0.0.1,
    -> PORT=3306,
    -> DB=ds_1,
    -> USER=root,
    -> PASSWORD=root123456
    -> );
Query OK, 0 ROWS affected (0.53 sec)
mysql>
mysql> ADD RESOURCE ds_2 (
    -> HOST=127.0.0.1,
    -> PORT=3306,
    -> DB=ds_2,
    -> USER=root,
    -> PASSWORD=root123456
    -> );
Query OK, 0 ROWS affected (0.02 sec)

5.执行RQL来查询新添加的数据源资源。

    mysql> SHOW RESOURCES FROM sharding_db;
    +------+-------+-----------+------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | name | TYPE  | host      | port | db   | attribute                                                                                                                                                   |
    +------+-------+-----------+------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | ds_1 | MySQL | 127.0.0.1 | 3306 | ds_1 | {"maxLifetimeMilliseconds":1800000,"readOnly":FALSE,"minPoolSize":1,"idleTimeoutMilliseconds":60000,"maxPoolSize":50,"connectionTimeoutMilliseconds":30000} |
    | ds_2 | MySQL | 127.0.0.1 | 3306 | ds_2 | {"maxLifetimeMilliseconds":1800000,"readOnly":FALSE,"minPoolSize":1,"idleTimeoutMilliseconds":60000,"maxPoolSize":50,"connectionTimeoutMilliseconds":30000} |
    +------+-------+-----------+------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
    2 ROWS IN SET (0.13 sec)

6.执行RDL,为t_order 表创建一个分片规则。

mysql> CREATE SHARDING TABLE RULE t_order(
    -> RESOURCES(ds_1,ds_2),
    -> SHARDING_COLUMN=order_id,
    -> TYPE(NAME=hash_mod,PROPERTIES("sharding-count"=4)),
    -> GENERATED_KEY(COLUMN=order_id,TYPE(NAME=snowflake,PROPERTIES("worker-id"=123)))
    -> );
Query OK, 0 ROWS affected (0.06 sec)

7.执行RQL来查询分片规则。

    mysql> SHOW SHARDING TABLE RULES FROM sharding_db;
    +---------+-----------------+-------------------+----------------------+------------------------+-------------------------------+--------------------------------+-------------------+---------------------+----------------------------+-----------------------------+-------------------+------------------+-------------------+
    | TABLE   | actualDataNodes | actualDataSources | databaseStrategyType | databaseShardingColumn | databaseShardingAlgorithmType | databaseShardingAlgorithmProps | tableStrategyType | tableShardingColumn | tableShardingAlgorithmType | tableShardingAlgorithmProps | keyGenerateColumn | keyGeneratorType | keyGeneratorProps |
    +---------+-----------------+-------------------+----------------------+------------------------+-------------------------------+--------------------------------+-------------------+---------------------+----------------------------+-----------------------------+-------------------+------------------+-------------------+
    | t_order |                 | ds_1,ds_2         |                      |                        |                               |                                | hash_mod          | order_id            | hash_mod                   | sharding-COUNT=4            | order_id          | snowflake        | worker-id=123     |
    +---------+-----------------+-------------------+----------------------+------------------------+-------------------------------+--------------------------------+-------------------+---------------------+----------------------------+-----------------------------+-------------------+------------------+-------------------+
    1 ROW IN SET (0.01 sec)

除了查询当前数据库下的所有分片规则外,RQL还可以通过以下语句查询单个表的分片规则。

SHOW SHARDING TABLE RULE t_order FROM sharding_db

创建并查询t_order 分片表。

mysql> CREATE TABLE `t_order`(
    -> `order_id` INT NOT NULL,
    -> `user_id` INT NOT NULL,
    -> `status` VARCHAR(45) DEFAULT NULL,
    -> PRIMARY KEY (`order_id`)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 ROWS affected (0.28 sec)
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_sharding_db |
+-----------------------+
| t_order               |
+-----------------------+
1 ROW IN SET (0.01 sec)

在ShardingSphere-Proxy端成功创建分片表t_order 后,ShardingSphere通过客户端连接到底层数据库ds_1ds_2 ,自动根据t_order 表的分片规则创建分片表。

mysql> USE ds_1;
DATABASE changed
mysql> SHOW TABLES;
+----------------+
| Tables_in_ds_1 |
+----------------+
| t_order_0      |
| t_order_2      |
+----------------+
2 ROWS IN SET (0.01 sec)
mysql> USE ds_2;
DATABASE changed
mysql> SHOW TABLES;
+----------------+
| Tables_in_ds_2 |
+----------------+
| t_order_1      |
| t_order_3      |
+----------------+
2 ROWS IN SET (0.00 sec)

分片表创建完毕后,继续在ShardingSphere-Proxy端执行SQL语句,插入数据。

mysql> INSERT INTO t_order VALUES(1, 1, 'ok');
Query OK, 1 ROW affected (0.06 sec)
mysql> INSERT INTO t_order VALUES(2, 2, 'disabled');
Query OK, 1 ROW affected (0.00 sec)
mysql> INSERT INTO t_order VALUES(3, 3, 'locked');
Query OK, 1 ROW affected (0.01 sec)
mysql> SELECT * FROM t_order;
+----------+---------+----------+
| order_id | user_id | STATUS   |
+----------+---------+----------+
|        1 |       1 | ok       |
|        2 |       2 | disabled |
|        3 |       3 | locked   |
+----------+---------+----------+
3 ROWS IN SET (0.06 sec)

通过RAL查询执行计划。

mysql> preview SELECT * FROM t_order;
+-----------------+------------------------------------------------+
| datasource_name | SQL                                            |
+-----------------+------------------------------------------------+
| ds_1            | SELECT * FROM t_order_0 ORDER BY order_id ASC  |
| ds_1            | SELECT * FROM t_order_2 ORDER BY order_id ASC  |
| ds_2            | SELECT * FROM t_order_1 ORDER BY order_id ASC  |
| ds_2            | SELECT * FROM t_order_3 ORDER BY order_id ASC  |
+-----------------+------------------------------------------------+
4 ROWS IN SET (0.02 sec)

这样就完成了使用DistSQL的ShardingSphere数据分片服务。与ShardingSphere代理的上一版本(即配置文件驱动)相比,DistSQL在管理资源和规则方面对开发者更加友好和灵活。此外,SQL驱动的方法能够实现DistSQL和标准SQL之间的无缝对接。

schemaName: sharding_db
dataSources:
  ds_0:
    url: jdbc:mysql://127.0.0.1:3306/ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root123456
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
  ds_1:
    url: jdbc:mysql://127.0.0.1:3306/ds_2?serverTimezone=UTC&useSSL=false
    username: root
    password: root123456
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
rules:
- !SHARDING
  tables:
    t_order:
      actualDataNodes: ds_${0..1}.t_order_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    none:
  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${order_id % 2}
  keyGenerators:
    snowflake:
      type: SNOWFLAKE
      props:
        worker-id: 123
1. CREATE a distributed DATABASE
CREATE DATABASE sharding_db;
2. ADD DATA resources
ADD RESOURCE ds_1 (
HOST=127.0.0.1,
PORT=3306,
DB=ds_1,
USER=root,
PASSWORD=root123456
);
ADD RESOURCE ds_2 (
HOST=127.0.0.1,
PORT=3306,
DB=ds_2,
USER=root,
PASSWORD=root123456
);
3. CREATE sharding rules
CREATE SHARDING TABLE RULE t_order(
RESOURCES(ds_1,ds_2),
SHARDING_COLUMN=order_id,
TYPE(NAME=hash_mod,PROPERTIES("sharding-count"=4)),
GENERATED_KEY(COLUMN=order_id,TYPE(NAME=snowflake,PROPERTIES("worker-id"=123)))
);

在上面的例子中,只展示了DistSQL语法的一小部分。除了通过CREATESHOW 语句创建和查询资源和规则外,DistSQL还提供了额外的操作,如ALTRE DROP ,并支持对数据分片的核心功能、读写分离、数据加密和数据库发现的配置控制。

结语

作为Apache ShardingSphere的5.0.0-beta版本中发布的新功能之一,DistSQL将继续在这个版本的基础上改进语法和越来越强大的功能。DistSQL为ShardingSphere探索分布式数据库空间开辟了无限的可能性。在未来,DistSQL将被用作连接更多功能的纽带,并提供一键式操作。

比如,可以一键分析数据库整体状态,与弹性迁移连接,提供一键数据扩容和缩容,与控制连接,实现一键主从切换,改变数据库状态。热烈欢迎开源和JavaScript爱好者加入Slack社区或查看项目的GitHub页面,了解更多ShardingSphere的最新进展。