什么是 Apache ShardingSphere

Apache ShardingSphere 是一款分布式的数据库生态系统,可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。

根据编程语言场景不同,其又分为2个产品:

  • ShardingSphere-JDBC:定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
  • ShardingSphere-Proxy:定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。

官网:https://shardingsphere.apache.org/index_zh.html


Java 以为的语言需要用 ShardingSphere-Proxy,本篇将阐述如何在 docker 环境下做 mysql 数据分片。

使用 docker 镜像演示

1)编写 docker-compose.yml

内容如下

version: "3.3"

networks:
  ShardingSphere:
    ipam:
      config:
        - subnet: 172.12.0.0/24
          gateway: 172.12.0.1

services:
  sharding_proxy:
    container_name: sharding_proxy
    environment:
      TZ: Asia/Shanghai
    image: apache/shardingsphere-proxy:latest
    networks:
      - ShardingSphere
    ports:
      - "3312:3307"
    restart: always
    volumes:
      - ./conf:/opt/shardingsphere-proxy/conf
      - ./logs:/opt/shardingsphere-proxy/logs
      - ./ext-lib:/opt/shardingsphere-proxy/ext-lib

 ShardingSphere-Proxy 默认端口是3307,我将其映射到宿主机的3312端口。

挂载了3个目录,其中 conf 目录是放配置文件的,logs 是日志文件存储目录,ext-lib 目录放扩展依赖包。

2)获取配置文件

刚开始我们是没有配置文件的,需要将默认配置文件从容器中拷贝出来:

docker run -d --name tmp --entrypoint=bash apache/shardingsphere-proxy
docker cp tmp:/opt/shardingsphere-proxy/conf /host/path/to/conf
docker rm tmp

执行完后,将 /host/path/to/conf 目录下的文件拷贝的挂载的 conf 目录下,可以看到有7个文件:

config-database-discovery.yaml
config-encrypt.yaml
config-readwrite-splitting.yaml
config-shadow.yaml
config-sharding.yaml
logback.xml
server.yaml

3)下载 mysql 连接依赖包

ShardingSphere-Proxy 连接 MySQL 数据库,需要用到 mysql-connector-java 驱动包,请下载 mysql-connector-java-5.1.49.jar 或者 mysql-connector-java-8.0.30.jar,并将其放入 ext-lib 目录。

4)修改配置文件 server.yaml

默认整个文件是全部注释的,需要将下图圈起来的部分取消注释(删除行首的 # 号),同时更改 sql-show 为 true(方便观察 SQL 日志):

此处配置的授权用户 root 可从任意主机连接,密码是 root;而用户 sharding 只能从本机连接,密码是 sharding。

5)修改配置文件 config-sharding.yaml

这个文件用于配置数据分片(分表分库),默认也是全部注释的。

找到 “If you want to connect to MySQL” 这一行,将后面的注释全部取消,同时按实际情况配置你已有的 MySQL 主机地址和账号密码:

此配置文件定义了库和表的分片规则,具体解释如下图:

6)在 MySQL 服务器上创建数据库和数据表

根据上一步的数据分片配置规则,得知,需要创建2个数据库:demo_ds_0、demo_ds_1,每个库还要创建4个表:t_order_0、t_order_1、t_order_item_0、t_order_item_1。

建表 sql 如下:

CREATE TABLE `t_order_0` (
  `order_id` bigint(20) unsigned NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `remarks` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `t_order_1` (
  `order_id` bigint(20) unsigned NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `remarks` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `t_order_item_0` (
  `order_item_id` bigint(20) unsigned NOT NULL,
  `order_id` bigint(20) unsigned NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `price` decimal(10,2) NOT NULL,
  PRIMARY KEY (`order_item_id`),
  KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `t_order_item_1` (
  `order_item_id` bigint(20) unsigned NOT NULL,
  `order_id` bigint(20) unsigned NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `price` decimal(10,2) NOT NULL,
  PRIMARY KEY (`order_item_id`),
  KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

7)启动服务

打开终端,切换到 docker-compose.yml 目录,执行 docker-compose up(为了方便观察日志所以没有加 -d):

由输出结果可知,启动成功了,后端连接的数据库是 MySQL 5.7.36。若没有启动成功,请检查配置的 MySQL 主机地址是否可 ping 通,账号密码是否正确。

8)使用 MySQL 客户端连接 ShardingSphere-Proxy

跟连接普通的 MySQL 服务器一样,前面我们映射的端口号是3312,配置的用户名和密码都是 root,所以执行:

mysql -h192.168.1.6 -P3312 -uroot -proot

登录成功,可以看到虚拟的库名 sharding_db 和两个虚拟表 t_order、t_order_item:

root@5e29717d68e6:/# mysql -h192.168.1.6 -P3312 -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.7.22-ShardingSphere-Proxy 5.1.2 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| schema_name        |
+--------------------+
| sharding_db        |
| mysql              |
| information_schema |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

mysql> use sharding_db;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-----------------------+------------+
| Tables_in_sharding_db | Table_type |
+-----------------------+------------+
| t_order_item          | BASE TABLE |
| t_order               | BASE TABLE |
+-----------------------+------------+
2 rows in set (0.00 sec)

mysql>

9)插入数据

执行以下 SQL 插入订单数据(只演示 t_order 表):

INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (1, '1-1');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (1, '1-2');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (2, '2-1');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (2, '2-2');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (3, '3-1');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (3, '3-2');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (4, '4-1');
INSERT INTO `t_order`(`user_id`, `remarks`) VALUES (4, '4-2');

观察 docker 容器 sharding_proxy 的输出日志,如下:

Logic SQL 就是我们输入的 SQL 语句,而 Actual SQL 是被 ShardingSphere 转换后的真实 SQL,还自动追加了雪花算法生成的 order_id 主键,数据分片算法根据 order_id 和 user_id 的不同取值将数据插入到对应的库节点和分表里。

10)查询数据

分别执行下面3个 SQL 语句:

SELECT * FROM t_order WHERE order_id=774342042821066753;
SELECT * FROM t_order WHERE order_id=774342042821066753 AND user_id=4;
SELECT * FROM t_order;

观察 docker 容器 sharding_proxy 的输出日志,如下:

通过输出日志可知:

  • 第1个 SQL 只提供 orde_id 时,ShardingSphere 可以确定分表的名称,但不能确定库节点,所以底层要查询2个节点才能得到结果;
  • 第2个 SQL 同时提供了 order_id 和 user_id,可以确定分表名称和库节点,所以底层只需要执行了一条 SQL 便可得到结果;
  • 第3个 SQL 未提供 order_id 和 user_id,底层则需要查询所有库节点和的所有分表。

总结

使用 ShardingSphere-Proxy 做数据分片的演示就到此结束,如果原来的业务代码是未分库分表,引入 ShardingSphere 做分表分库几乎无须改动代码。