背景说明

我们的Java项目已经运行了快2年了,这两年期间经过2个外包团队的开发,加上前期并没有做什么质量管理,所以代码质量比较差。项目中使用的数据库是MySQL,留着流量的增长,目前这个阶段需要着手读写分离和分表的一些事项。因为之前没有什么相关的经验,所以找了一圈使用业内比较流行的shardingsphere 中间件。

什么是 ShardingSphere

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

Apache ShardingSphere 设计哲学为 Database Plus,旨在构建异构数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。 它站在数据库的上层视角,关注它们之间的协作多于数据库自身。

具体介绍:shardingsphere 文档


ShardingSphere-JDBC

ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。

ShardingSphere-JDBC 集成

ShardingSphere-JDBC 集成在代码是比较简单的,只需2个步骤:

  1. 引入 Maven 依赖
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
    <version>${shardingsphere.version}</version>
</dependency>
  1. 配置 Spring Boot
# 配置 DataSource Driver
spring.datasource.driver-class-name=org.apache.shardingsphere.driver.ShardingSphereDriver
# 指定 YAML 配置文件
spring.datasource.url=jdbc:shardingsphere:classpath:xxx.yaml

注意:上面的配置版本需要是5.3.0 以上(从5.3.0开始弃用对 spring.factories 的支持),对使用5.3.0以下的用户Maven 引用就不同了,具体看对应版本的文档,像5.2.x 和5.1.x的yaml的配置也是有点不同,所以5.1.x升级到5.2.x还是要看文档。

ShardingSphere-JDBC 在项目使用的情况

在我们项目中使用遇到几个问题后,由于项目中代码比较多,改动量较大,所以我们根本不敢用到生产,以下是需要改动的地方。

  1. 我们继承mybatis-plus工具,很多批量保存都是用batchSave(X x),保存后无法返回自增的Id,有些业务保存后需要返回的id。(sharding-proxy 不存在这个问题)
  2. 不支持查询视图,这个不知道是不是我有没有记错。

还有一些问题,时间有点长了,一些问题也就忘记了。


ShardingSphere-Proxy 使用

为什么没有打算使用mycat2 ,主要是mycat2 的文档太山寨了, ShardingSphere-Proxy文档多好呀。

ShardingSphere-Proxy 定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。

ShardingSphere-Proxy 部署

  • dockercompose 文件
version: '3.1'

services:
  zoo1:
    container_name: zoo1
    image: zookeeper
    hostname: zoo1
    ports:
      - 2181:2181
    restart: always
    volumes:
        - /data/zookeeper/zoo1/data:/data
        - /data/zookeeper/zoo1/conf/zoo.cfg:/conf/zoo.cfg
        - /data/zookeeper/zoo1/logs:/datalog
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ALLOW_ANONYMOUS_LOGIN: "yes"
  zoo2:
    container_name: zoo2
    image: zookeeper
    hostname: zoo2
    ports:
      - 2182:2181

    volumes:
      - /data/zookeeper/zoo2/data:/data
      - /data/zookeeper/zoo2/conf/zoo.cfg:/conf/zoo.cfg
      - /data/zookeeper/zoo2/logs:/datalog
    restart: always
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ALLOW_ANONYMOUS_LOGIN: "yes"
  zoo3:
    container_name: zoo3
    image: zookeeper
    hostname: zoo3
    ports:
      - 2183:2181

    volumes:
      - /data/zookeeper/zoo3/data:/data
      - /data/zookeeper/zoo3/conf/zoo.cfg:/conf/zoo.cfg
      - /data/zookeeper/zoo3/logs:/datalog
    restart: always
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ALLOW_ANONYMOUS_LOGIN: "yes"
  sharding:
    container_name: sharding-proxy
    image: apache/shardingsphere-proxy:5.3.2
    hostname: sharding
    ports:
      - 3308:3308
    restart: always
    volumes:
      - /data/shardingsphere/conf:/opt/shardingsphere-proxy/conf
      - /data/shardingsphere/ext-lib:/opt/shardingsphere-proxy/ext-lib
    environment:
      PORT: 3308
      JVM_OPTS: "-Djava.awt.headless=true"
  • 运行:
sudo docker-compose   up -d

部署要注意的地方是:

  1. 挂载的目录里的文件,最好是用docker cp sharding-proxy:/opt/shardingsphere-proxy/conf xx, 拷贝出来修改,这样子启动才不会遇到一些坑
  2. 使用mysql 需要自己下载到ext-lib

以上2点官方文档有写。

ShardingSphere-Proxy 在项目使用的情况

现在说下我们在项目中使用遇到了一些问题,导致我们最后还是弃用了。

  1. 跨库查询:支持跨库,但是不能指定目标库,而是在数据源配置的时候,把目标库配置在一起,查询的时候直接查表就可以了,但是两个库表名刚好相同的话,我不清楚会不会报错(因为我们使用的项目中刚好没有相同表),但是要大量修改脚本。 例如:
-- 原SQL
select *  from abc.table_a
-- 需要修改成
select *  from table_a
  1. 脚本空格问题:因为我们项目比较复杂,之前没有做质量管理,所以有些sql 存在空格,胡导致查询失败,当然我们项目修改这个问题,我觉得没有什么问题。
-- 无法查询
select a. * from table
  1. mysql 关键字问题处理:mysql 关键字例如:function mybaits 的实体中 @TableField("function") 或者sql 中没有加反单引号会报错 ,需要修改成:@TableField("`function`") ,这样子需要排查所有关键字问题。
  2. 在事务中不支持多语句查询,例如:
-- 没有事务查询正常
SET SESSION group_concat_max_len = 102400;
select * from ...
-- 在事务中查询不出来事务中的数据


总结

Apache ShardingSphere 是一款很好的中间件,其实我还是很喜欢的,但是如果使用他需要造成项目中的大量的修改,我还是不得不放弃。

我们常常会评审一些项目是否具备读写分离和分库分表的能力,如果有项目可以加分,如果做作为要售卖的JAVA项目产品,而且有一定的数据规模,可以考虑趁早集成,这样子可以规避很多问题。