MySplitter 是什么?

[English] [Github] [Apache License 2.0]

MySplitter 是轻量级的读/写分离,多数据源,高可用性,负载均衡数据库连接中间件。

当你需要一个程序连接2个或者更多的数据库,甚至是不同类型的数据库;数据库配置了读写分离,但是读操作有多个数据源且无法负载均衡;希望数据源不可使用时有提醒,并且可以切换到可用的数据源,那就让 MySplitter 来帮助你吧!

当前特性

开发计划:

配置文件快速预览:

只需进行简单的配置,就可以让 MySplitter 管理数据源,你就可以轻松地使用多数据源了。

mysplitter:
  databasesRoutingHandler: com.xxx.your.databasesRoutingHandler
  databases:
    database-a:
      integrates:
        database-a-integrate-node:
          dataSourceClass: com.alibaba.druid.pool.DruidDataSource
          configuration:
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://localhost:3306/test
            username: root
            password: admin
    database-b:
      integrates:
        database-b-integrate-node:
          dataSourceClass: com.zaxxer.hikari.HikariDataSource
          configuration:
            driverClassName: oracle.jdbc.driver.OracleDriver
            jdbcUrl: jdbc:oracle:thin:@//localhost:1521/orcl 
            username: scott
            password: tiger

开始使用

1.导入依赖

  1. 普通项目

    Maven:

     <dependency>
         <groupId>com.mysplitter</groupId>
         <artifactId>mysplitter</artifactId>
         <version>0.9.1</version>
     </dependency>
    

    Gradle:

     compile group: 'com.mysplitter', name: 'mysplitter', version: '0.9.1'
    
  2. Spring Boot 项目

    Maven:

     <dependency>
         <groupId>com.mysplitter</groupId>
         <artifactId>mysplitter-spring-boot-starter</artifactId>
         <version>0.9.1</version>
     </dependency>
    

    Gradle:

     compile group: 'com.mysplitter', name: 'mysplitter-spring-boot-starter', version: '0.9.1'
    

2.设置数据源

使用 com.mysplitter.MySplitterDataSource 获取连接、管理多个数据源。

3.创建配置文件

在项目的 resources 目录创建文件名为 mysplitter.yml 的配置文件,明确你需要几个数据库,是否需要读写分离、高可用和负载均衡。并参考下面的文档进行配置。

配置向导

1.准备工作

MySplitter 默认读取 mysplitter.yml 配置文件。请确该文件在项目的 resources 目录下。(暂不支持Spring Boot配置文件配置以及自定义配置文件名称)

2.统一配置

// TODO

3.配置多数据源/读写分离

下面将演示一个读写分离的多数据源配置:

mysplitter:
  databases:
    database-a: # 可以自定义数据库的名称
      readers:
        reader-read-slave-1: # 可以自定义读数据源节点的名称
          dataSourceClass: com.alibaba.druid.pool.DruidDataSource
          configuration: # 读数据源的配置信息
            url: jdbc:mysql://localhost:3306/user
            username: root
            password: admin
            driverClassName: com.mysql.jdbc.Driver
      writers:
        writer-write-master-1: # 可以自定义写数据源节点的名称
          dataSourceClass: com.alibaba.druid.pool.DruidDataSource
          configuration: # 写数据源的配置信息
            url: jdbc:mysql://localhost:3306/user
            username: root
            password: admin
            driverClassName: com.mysql.jdbc.Driver

4.配置自定义读写解析器

当不配置读写解析器时,将使用自带的读写解析器 com.mysplitter.DefaultReadAndWriteParser 。如果自带的解析器无法满足你的需求,请自定义读写解析器并实现 com.mysplitter.advise.MySplitterReadAndWriteParserAdvise

配置文件示例:

mysplitter:
  readAndWriteParser: com.xxx.MyReadAndWriteParser

Java代码示例:

public class MyReadAndWriteParser implements MySplitterReadAndWriteParserAdvise {

    /**
     * @param sql 要执行的sql语句
     * @return readers:当前数据源是读数据源  writers:当前数据源是写数据源
     */
    @Override
    public String parseOperation(String sql) {
        if (sql.startsWith("SELECT") || sql.startsWith("select")) {
            return "readers";
        }
        return "writers";
    }

}

5.配置多数据库

如果是多个数据库的数据源,需要先定义数据源路由并实现 com.mysplitter.advise.MySplitterDatabasesRoutingHandlerAdvise

配置文件示例:

mysplitter:
  databasesRoutingHandler: com.xxx.MyDatabasesRoutingHandler
  common:
    dataSourceClass: com.zaxxer.hikari.HikariDataSource
  databases:
    database-a: # 可以自定义数据库的名称,注意在数据源路由实现类中进行对应
      readers: # 代表子节点都是读数据源
        reader-read-slave-1: # 可以自定义数据源节点名称
          configuration:
            url: jdbc:mysql://localhost:3306/user
            username: root
            password: admin
            driverClassName: com.mysql.jdbc.Driver
      writers: # 代表子节点都是写数据源
        writer-write-master-1: # 可以自定义数据源节点名称
          configuration:
            url: jdbc:mysql://localhost:3306/user
            username: root
            password: admin
            driverClassName: com.mysql.jdbc.Driver
    database-b: # 可以自定义数据库的名称,注意在数据源路由实现类中进行对应
      integrates: # 代表子节点是不进行读写分离的数据源
        integrate-slave-1: # 可以自定义数据源节点名称
          configuration:
            jdbcUrl: jdbc:mysql://localhost:3306/dept
            username: root
            password: admin
            driverClassName: com.mysql.jdbc.Driver

Java代码示例:

public class MyDatabasesRoutingHandler implements MySplitterDatabasesRoutingHandlerAdvise {

    /**
     * @param sql 要执行的sql语句
     * @return 配置文件中定义的数据库名称
     */
    @Override
    public String routerHandler(String sql) {
        if (sql.contains("user")) {
            return "database-a";
        } else {
            return "database-b";
        }
    }
    
    /**
     * @param sql 要执行的sql语句
     * @return 要执行的sql语句,如果不需要重写,直接返回"sql"即可
     */
    @Override
    public String rewriteSql(String sql) {
        return sql;
    }

}

6.配置负载均衡

当读写分离,有多个读/写节点,可以对数据源负载均衡,配置文件示例:

  1. 负载均衡轮询算法:

     mysplitter:
       common:
         dataSourceClass: com.zaxxer.hikari.HikariDataSource
       databases:
         database-a:
           loadBalance:
             read:
               enabled: true
               strategy: polling #现在是使用轮询方式进行负载均衡
             write:
               enabled: false
           readers:
             reader-read-slave-1:
               configuration:
                 url: jdbc:mysql://localhost:3306/user
                 username: root
                 password: admin
                 driverClassName: com.mysql.jdbc.Driver
             reader-read-slave-2:
               configuration:
                 url: jdbc:mysql://localhost:3307/user
                 username: root1
                 password: admin2
                 driverClassName: com.mysql.jdbc.Driver
           writers:
             writer-write-master-1:
               configuration: # dataSource configuration
                 url: jdbc:mysql://localhost:3306/user
                 username: root
                 password: admin
                 driverClassName: com.mysql.jdbc.Driver
    
  2. 负载均衡随机权重算法:

     mysplitter:
       common:
         dataSourceClass: com.zaxxer.hikari.HikariDataSource
       databases:
         database-a:
           loadBalance:
             read:
               enabled: true
               strategy: random #现在是使用随机权重方式进行负载均衡,需要在每个节点定义weight,默认是1
             write:
               enabled: false
           readers:
             reader-read-slave-1:
               weight: 1 #此节点的权重是1,此时访问当前节点的概率为25%
               configuration:
                 url: jdbc:mysql://localhost:3306/user
                 username: root
                 password: admin
                 driverClassName: com.mysql.jdbc.Driver
             reader-read-slave-2:
               weight: 3 #此节点的权重是3,此时访问当前节点的概率为75%
               configuration:
                 url: jdbc:mysql://localhost:3307/user
                 username: root1
                 password: admin2
                 driverClassName: com.mysql.jdbc.Driver
           writers:
             writer-write-master-1:
               configuration: # dataSource configuration
                 url: jdbc:mysql://localhost:3306/user
                 username: root
                 password: admin
                 driverClassName: com.mysql.jdbc.Driver
    

7.数据源高可用

自动检测数据源是否可用,如果数据源不可用,自动从数据源节点中剔除,默认30秒再次重试,直到数据源可用。

如果需要配置重试时间间隔,请设置 failTimeout 参数,参考如下配置:

  1. 定义在common中:

     mysplitter:
       readAndWriteParser: com.mysplitter.demo.datasource.ReadAndWriteParser
       illAlertHandler: com.mysplitter.demo.datasource.DataSourceIllAlertHandler
       common:
         dataSourceClass: com.alibaba.druid.pool.DruidDataSource
         loadBalance:
           read:
             enabled: true
             strategy: polling
             failTimeout: 1m
           write:
             enabled: false
    
  2. 定义在数据库节点中

     mysplitter:
       enablePasswordEncryption: true
       readAndWriteParser: com.mysplitter.demo.datasource.ReadAndWriteParser
       illAlertHandler: com.mysplitter.demo.datasource.DataSourceIllAlertHandler
       common:
         dataSourceClass: com.alibaba.druid.pool.DruidDataSource
       databases:
         database-a:
           loadBalance:
             read:
               enabled: true
               strategy: polling
               failTimeout: 1m
             write:
               enabled: false
           readers:
             reader-read-slave-1:
               configuration:
                 url: jdbc:mysql://localhost:3306/user?useSSL=false
                 username: root
                 password: UtDAi2eqmspIDSHqpoGQU5JC9kpfFeZPBhUxkPnWtNwsTEYFkTh/QAa5wyU7LDufruSYN+0WCUTE6F5X++5tDA==
                 publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKVbfAja9r0HF29S/ph/T+f6UbeNxn4giAzgxweKABRsJ2sI/MNhV8x7jTsCM15xDHKM4G++QqC1Bx0tdgG/BI0CAwEAAQ==
                 driverClassName: com.mysql.jdbc.Driver
                 maxWait: 1000
             reader-read-slave-2:
               configuration:
                 url: jdbc:mysql://localhost:3306/user?useSSL=false
                 username: root
                 password: Oe7fcF2TLqytAlvy37C/IWfBhNhBFXmMGceE6GRxYyjJXh3TUdmq8EvebiFb0pB1hF9aH7thnnkthFiy5n3M8Q==
                 publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMWmL+AzrbsKwfrtP/a/aQpQplNsoySxCHUQb0aJw2t8iemRtbxtxJhXmQqPMlAZdYppyK0wB48HTArD2am3/NMCAwEAAQ==
                 driverClassName: com.mysql.jdbc.Driver
                 maxWait: 1000
           writers:
             writer-write-master-1:
               configuration:
                 url: jdbc:mysql://localhost:3306/user?useSSL=false
                 username: root
                 password: MAtsEynrB5qJp6oDfmae2Z2Hx1lqPwFDNMKnwUr/P7+HvYy8ZXIm6DKI5VWfLO34Bjcdy+Jsr4+/N++Bxx0Y5w==
                 publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIvm9Ez/X3VOLUGNfATqtyQsK5+TOR66uK6MvHdX89N1K8S3l3bNVB2BKiPZ1hDxZNZfYtbQNUUHKjDyV+eUtq8CAwEAAQ==
                 driverClassName: com.mysql.jdbc.Driver
                 maxWait: 1000
    

8.配置过滤器(暂不支持)

9.数据源状态监控

你可以通过调用 com.mysplitter.MySplitterDataSourcegetStatus 方法获取当前所有数据源的状态。

10.数据源异常提醒

创建一个类并实现 com.mysplitter.advise.DataSourceIllAlerterAdvise,并在配置文件中进行配置:

mysplitter:
  illAlertHandler: com.mysplitter.demo.datasource.DataSourceIllAlertHandler

11.数据源密码加密

  1. 执行加密命令获取私钥、公钥和加密后的密码。加密直接使用了 com.alibaba.druid 的加密算法以及源码。

     java -cp mysplitter-0.9.1.jar com.mysplitter.util.SecurityUtil password [password...]
    
  2. 在配置文件中启用密码加密 enablePasswordEncryption: true,然后添加并修改数据源的配置中的 passwordpublicKey

    以文档中配置文件快速预览中的配置进行示例:

    mysplitter:
      enablePasswordEncryption: true
      databasesRoutingHandler: com.xxx.your.databasesRoutingHandler
      databases:
        database-a:
          integrates:
            database-a-integrate-node:
              dataSourceClass: com.alibaba.druid.pool.DruidDataSource
              configuration:
                driverClassName: com.mysql.jdbc.Driver
                url: jdbc:mysql://localhost:3306/test
                username: root
                password: M1jnmaflpqw/FoZ4mSdD2e7pvQPiBWxJrEa3xvFjRb5ZCIkH5lCbfUQlbDBg58YJAhfxo8dd3KiYlygZVa2Ecw==
                publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKZ+PehB68CplrpZJ0qyyp5NV40HAKVlc0zf5LMD7luVd9buSvLqgmJKnT/QhRYaFDXAIaXRCKxd0TUf1ZhEafECAwEAAQ==
        database-b:
          integrates:
            database-b-integrate-node:
              dataSourceClass: com.zaxxer.hikari.HikariDataSource
              configuration:
                driverClassName: oracle.jdbc.driver.OracleDriver
                jdbcUrl: jdbc:oracle:thin:@//localhost:1521/orcl 
                username: scott
                password: rJuZ5fak54A7n4iPFfRIP2TN8xPx8nEJGfsLQzhKF6uBnDr0bfbWL8yRIeqv8h2Jbf/YuJeQnR7oUUIEcOPklg==
                publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALaSX/yimY5Hzqd8InW2ETrodqcVTVfiGATESTFGDKNbKfFjJFLzzFJqvwg+ZmOhXjj2tVyb5j7qz4We94zIaH8CAwEAAQ==
    

常见问题解答

// TODO