ShardingSphere踩坑之旅02-proxy

1,487 阅读4分钟

简介

头一次接触ShardingSphere-Proxy,先扫一遍官方介绍

看完后,尝试用自己的话来解释proxy:

  • 从开发者的角度看,proxy基本做到了用户无感知,对代码的侵入也很少,使用起来就像使用普通数据库一样简单方便
  • 从工作原理的角度看,相比于ShardingSphere-JDBC,proxy是在ORM层发挥作用,本质是个代理服务:用户->proxy->数据库

暂时了解了这么多,接下来是踩坑之旅...

启动ShardingSphere-Proxy

基于上一篇文章里准备的开发环境(ShardingSphere代码clone到本地),博主选择了直接修改本地配置文件后,启动Bootstrap方式,来开启本地的proxy服务。

具体步骤

1. 改配置文件

工程:shardingsphere-proxy-bootstrap

路径:src\main\resources\conf\server.yaml、config-sharding.yaml、config-readwrite-splitting.yaml、config-encrypt.yaml

示例:

放开server.yaml中的注释配置,并修改sql-show,便于后期调试

rules:
  - !AUTHORITY
    users:
      - root@:root
      - sharding@:sharding
    provider:
      type: NATIVE

props:
  max-connections-size-per-query: 1
  executor-size: 16  # Infinite by default.
  proxy-frontend-flush-threshold: 128  # The default value is 128.
    # LOCAL: Proxy will run with LOCAL transaction.
    # XA: Proxy will run with XA transaction.
    # BASE: Proxy will run with B.A.S.E transaction.
  proxy-transaction-type: LOCAL
  proxy-opentracing-enabled: false
  proxy-hint-enabled: false
  sql-show: true
  check-table-metadata-enabled: false

放开config-sharding.yaml中的注释配置

schemaName: sharding_db

dataSources:
  ds_0:
    url: jdbc:mysql://127.0.0.1:3306/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password:
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
  ds_1:
    url: jdbc:mysql://127.0.0.1:3306/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password:
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

注意

config-shardingyaml文件中,有一处配置schemaName:sharding_db,此为分片策略的逻辑库名称,在后续启动示例工程,验证策略时会用到。

config-readwrite-splitting.yaml、config-encrypt.yaml也如上处理,不再赘述

2. 启动Bootstrap

微信截图_20210824211133.png

3. Navicat测试连接

在proxy服务启动前:

微信截图_20210824194817.png

proxy服务启动后:

微信截图_20210824195428.png

由此可见,对于使用者而言,proxy生效后,相当于一个数据库服务!

运行示例

数据分片

1. 数据库初始化

CREATE SCHEMA IF NOT EXISTS demo_ds_0;
CREATE SCHEMA IF NOT EXISTS demo_ds_1;

2. 改工程配置文件

工程:shardingsphere-proxy-boot-mybatis-example

文件路径:src\main\resources\application.properties

修改如下:

mybatis.config-location=classpath:META-INF/mybatis-config.xml

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/sharding_db?useServerPrepStmts=true&cachePrepStmts=true
spring.datasource.username=root
spring.datasource.password=root

注意,数据库ip、端口都是本地的proxy代理服务,数据库用的是逻辑数据库sharding_db,对应数据分片

3. 执行用例

为了更好的查看效果,先注释掉代码中的delete、drop操作:

image.png

image.png 运行ProxySpringBootStarterExample

4. 观察结果

示例工程的控制台日志打印正常:

image.png

到数据库里查看,订单数据确实实现了分表:

image.png

image.png

proxy服务的控制台日志,可以看出执行了分片策略:

image.png

读写分离

1. 数据库初始化

CREATE SCHEMA IF NOT EXISTS demo_write_ds;
CREATE SCHEMA IF NOT EXISTS demo_read_ds_0;
CREATE SCHEMA IF NOT EXISTS demo_read_ds_1;

CREATE TABLE IF NOT EXISTS demo_read_ds_0.t_order (order_id BIGINT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id));
CREATE TABLE IF NOT EXISTS demo_read_ds_1.t_order (order_id BIGINT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id));
CREATE TABLE IF NOT EXISTS demo_read_ds_0.t_order_item (order_item_id BIGINT NOT NULL AUTO_INCREMENT, order_id BIGINT NOT NULL, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_item_id));
CREATE TABLE IF NOT EXISTS demo_read_ds_1.t_order_item (order_item_id BIGINT NOT NULL AUTO_INCREMENT, order_id BIGINT NOT NULL, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_item_id));

2. 改工程配置文件

同上,需要注意的是,修改逻辑库为:readwrite-splitting_db

mybatis.config-location=classpath:META-INF/mybatis-config.xml

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/readwrite-splitting_db?useServerPrepStmts=true&cachePrepStmts=true
spring.datasource.username=root
spring.datasource.password=root

3. 执行用例

同上

4. 观察结果

重点看proxy服务的控制台日志,可以看到读写分别走了不同的库

image.png

加密

1. 数据库初始化

CREATE SCHEMA IF NOT EXISTS demo_ds_0;
CREATE SCHEMA IF NOT EXISTS demo_ds_1;

2. 改工程配置文件

同上,需要注意的是,修改逻辑库为:encrypt_db

mybatis.config-location=classpath:META-INF/mybatis-config.xml

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/encrypt_db?useServerPrepStmts=true&cachePrepStmts=true
spring.datasource.username=root
spring.datasource.password=root

3. 执行用例

同上

4. 观察结果

从proxy服务的控制台日志,可以看到项目正常执行,但是数据并未加密???

image.png

加密未生效的坑,还需填上(今天搞太晚了,后面找时间再测试一把。。)

(更新于2021.08.25,来填坑了)

查看了项目里config-encrypt.yaml的配置,以及官方文档对加密配置项的介绍,发现数据未加密的原因是没有填对配置项。。o(╯□╰)o

赶紧改了一把(注意加密字段的数据类型,跟加密后的数据类型是否一致,这一步得选择合适的算法)

最终效果:

image.png

总结

相比第一天的jdbc,proxy的调试顺利多了,后面还得再接再厉!!!

踩坑的过程也暴露出自己身上很多问题:

  1. 事先准备不够,既没有完整地浏览一遍文档,也没有认真地思考文档内容,只看了个大概,就急着动手,导致后续犯了太多低级错误(很多错误只要足够细心就能避免)
  2. 过程里只求调通,没有进一步沉下心去琢磨实现原理