天天看點

分庫分表後,測試小姐姐都哭了(sharding-proxy)

什麼?你們的測試是小哥哥?那就不要往下看了,讓他們怎麼難怎麼來。

建議

根據你的業務特點,單表 > 分區 > 單庫分表 > 分庫分表,在滿足業務前提下,優先級從左到右,不接受任何反駁。嘿嘿

背景

做過分表的(單庫分表或者分庫分表)都知道,在你沒有依賴任何中間件之前,使用Navicat或者其他類似工具操作MySQL,那将是災難,如下圖所示:

分庫分表後,測試小姐姐都哭了(sharding-proxy)

sharding table view

如果是類似取模這類簡單算法分表還好說,能一眼根據分片鍵知道分表結,比如根據使用者ID對128取模分表,那麼使用者ID為128的使用者資料就在表tb_user_0中。但是如果是采用類似一緻性hash算法或者更複雜的分表算法,那麼我們首先需要利用程式根據分片鍵算出分表結果,然後再到Navicat中對該表進行CRUD。

剛才提到的隻能搞定帶有分片鍵的操作,對于那些沒有帶有分片鍵條件的操作,例如查詢最新的10條資料,那真的隻能呵呵了。開發尚且如此困難,測試小姐姐能不哭嘛。馬雲爸爸說:哪裡有困難,哪裡就有機會。是以,這就是你和測試小姐姐拉近機會、表現自己的時候。當然不是要你送下面這輛奔馳大G給小姐姐,畢竟不是每個人都是王思聰。不過利用我們所學,給測試小姐姐解決一些問題,還是可以的嘛(這種機會都不抓住,活該你單身):

本文要介紹的,可以優雅解決這個問題的工具就是 sharding-proxy(MyCAT也有類似工具,隻是易用性簡直就是渣渣)。話不多說,我們先來看看部署sharding-proxy前後使用Navicat通路MySQL的對比效果圖,開不開森,激不激動:

分庫分表後,測試小姐姐都哭了(sharding-proxy)

image.png

是以,sharding-proxy能帶來什麼呢?先說優點吧:

  1. 完全屏蔽sharding細節,把它當做一張普通的表增删改查即可(分表算法內建在sharding-proxy的配置檔案中,使用者不需要care)
  2. 打開資料庫後,不再是看到滿屏的表,而是隻有幾張簡單的表(如上圖左側所示)。
  3. 一個sharding-proxy可以代理多個資料源,測試隻需要對接一個sharding-proxy即可。

再說缺點:

  1. 無法操作"設計表",即不能看到DDL。但是可以通過F6快捷鍵後show create table table_name檢視表結果(以Navicat為例);
  2. sharding-sphere不支援的文法(非常有限),也不能在Navicat上操作。

是不是感覺很厲害的樣子,OK,讓我們花10分鐘給測試小姐姐一個驚喜吧(部署sharding-proxy)。

sharding-proxy

部署sharding-proxy非常簡單,隻需如下幾個簡單的步驟。另外,本次部署以sharding-proxy-3.0.0版本為例。

下載下傳

下載下傳位址:https://github.com/sharding-sphere/sharding-sphere-doc/raw/master/dist/sharding-proxy-3.0.0.tar.gz

下載下傳後解壓,我們看到隻有簡單的三個目錄:lib目錄就是sharding-proxy核心代碼,以及依賴的JAR包;bin目錄就是存放啟停腳本的;conf目錄就是存放所有配置檔案,包括sharding-proxy服務的配置檔案、資料源以及sharding規則配置檔案和項目日志配置檔案。

lia目錄沒什麼好說的。bin目錄裡面就是window或者Linux環境啟停腳本。sharding-proxy啟動的預設端口是3307,如果要自定義端口(比如3308),執行sh start.sh 3308即可(window環境修改start.bat即可)。所有重要的配置都在conf目錄下。

配置

  • logback.xml

首先就是最簡單的日志配置檔案logback.xml,筆者對其簡單的修改了一下,你可以任意自定義,這個沒什麼好說的,非常簡單。

  • server.xml

接下來就是與sharding-proxy服務相關的配置檔案server.yaml,筆者的配置檔案如下所示:

orchestration:
  name: orchestration_afei
  overwrite: true
  registry:
    serverLists: 172.29.3.245:2181,172.29.3.245:2182,172.29.3.245:2183
    namespace: orchestration_afei

# 使用者通過Navicat通路sharding-proxy的使用者名密碼
authentication:
  username: afei
  password: afei

# sharding-proxy相關配置,建議sql.show設定為true,友善定位問題
props:
  max.connections.size.per.query: 1
  acceptor.size: 16 
  executor.size: 16 
  proxy.transaction.enabled: false
  proxy.opentracing.enabled: false
  sql.show: true
      
  • config.xml

接下來就是最重要的資料源以及sharding規則配置檔案config-*.xml了。需要說明的是,一個sharding-proxy執行個體能支援多個資料源,隻需多個config.yaml即可。例如支付和賬戶兩個資料源,那麼添加兩個配置檔案即可:config-pay.yaml,config-account.yaml,配置參考:

schemaName: afei

dataSources:
  afei:
    url: jdbc:mysql://172.29.2.239:3311/afei?serverTimezone=UTC&useSSL=false
    username: afei
    password: afei
    autoCommit: true
    connectionTimeout: 10000
    idleTimeout: 60000
    maxLifetime: 1800000
    maximumPoolSize: 50

shardingRule:
  tables:
    # tb_batch_trade_detail的分表算法是根據trade_id對128取模
    tb_batch_trade_detail:
      actualDataNodes: afei.tb_batch_trade_detail${0..127}
      tableStrategy:
        inline:
          shardingColumn: trade_id
          algorithmExpression: tb_batch_trade_detail${trade_id % 128}    
    # tb_repay_file_detail的分表算法是在RepayFileDetailShardingAlgorithm中自定義      
    tb_repay_file_detail:
      actualDataNodes: afei.tb_repay_file_detail${0..127}
      tableStrategy:
        standard:
          shardingColumn: project_no
          preciseAlgorithmClassName: com.afei.sharding.RepayFileDetailShardingAlgorithm
  bindingTables:

  # 預設資料庫沒有分的政策
  defaultDatabaseStrategy:
    none:
  # 預設表沒有分的政策
  defaultTableStrategy:
    none:
  defaultKeyGeneratorClassName: io.shardingsphere.core.keygen.DefaultKeyGenerator
      

對應自定義分表算法,隻需要将對應算法的class檔案放到conf目錄下即可,參考目錄結構:

com
  ├── afei/sharding/RepayFileDetailShardingAlgorithm.class
config-pay.yaml
config-account.yaml
logback.xml
server.yaml
      

這個自定義分表算法的源碼非常簡單,參考sharding-sphere中的分表,實作自己的算法即可,參考源碼:

import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import java.util.Collection;

public class RepayFileDetailShardingAlgorithm implements PreciseShardingAlgorithm<String> {

    private static final int SHARDING_COUNT = 128;

    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<String> shardingValue) {
        String hashCode = String.valueOf(shardingValue.getValue().hashCode());
        long segment = Math.abs(Long.parseLong(hashCode)) % SHARDING_COUNT;

        for (String each : availableTargetNames) {
            if (each.equals( "tb_repay_file_detail"+segment )) {
                return each;
            }
        }
        throw new UnsupportedOperationException();
    }

}
      
  • Navicat