海量數據分庫分表方案(二)技術選型與sharding-jdbc實現


上一章已經講述分庫分表算法選型,本章主要講述分庫分表技術選型

文中關聯上一章,若下文出現提及其時,可以點擊 分庫分表算法方案與技術選型(一)

主要講述

  • 框架比較
  • sharding-jdbc、zdal 代碼實現樣例,如需源碼可在后文中查看
  • 主鍵生成策略
    可以按需閱讀文章

點贊再看,關注公眾號:【地藏思維】給大家分享互聯網場景設計與架構設計方案
掘金:地藏Kelvin https://juejin.im/user/5d67da8d6fb9a06aff5e85f7

常見框架

除了原生JDBC,網上常見分庫分表框架有:
當當網 sharding-jdbc
alibaba.cobar (是阿里巴巴(B2B)部門開發)
MyCAT(基於阿里開源的Cobar產品而研發)
螞蟻金服 ZDAL (開源)
蘑菇街 TSharding

當然除了這些,還有很多各自公司提出的框架,但是根據用戶量較高的為以上幾種。
其中自從出現基於cobar的MyCAT,zdal,也很少人用cobar了。ZDAL雖然也是開源,但是很少文章和使用反饋,不支持MongoDb,交流活躍度也比較低。

所以本次文章來比較一下活躍度較高的sharding-jdbc和MyCAT

擴展閱讀:當當網做的不錯的,除了sharding-jdbc,還有elastic-job用於定時任務分片

對比概覽

主要指標 Sharding-jdbc Mycat zdal
ORM支持 任意 任意 任意
事務 自帶弱XA、最大努力送達型柔性事務BASE 自帶弱XA 自帶弱XA、最大努力送達型柔性事務BASE
分庫 支持 支持 支持
分庫 支持 不支持單庫分表 支持
開發 開發成本高,代碼入侵大 開發成本小,代碼入侵小 開發成本不算高配置明確
所屬公司 當當網 基於阿里Cobar二次開發,社區維護 螞蟻金服
數據庫支持 任意 Oracle、 SQL Server、 Mysql、DB2、mongodb 不支持mongodb
活躍度 也有不少的企業在最近幾年新項目使用 社區活躍度很高,一些公司已在使用 活躍度低
監控
讀寫分離 支持 支持
資料 資料少、github、官網、網上討論貼 資料多,github、官網、Q群、書籍
運維 維護成本低 維護成本高 維護成本低
限制 部分JDBC方法不支持、SQL語句限制 SQL語句限制
連接池 druid版本 無要求 無要求
配置難度 一般 復雜 比較簡單,讀寫分離、分開分表規則設置量少

關鍵指標對比

1.開發與運維成本

sharding-jdbc

  • sharding-jdbc是一個輕量級框架,不是獨立運行中間件,以工程的依賴jar的形式提供功能,無需額外部署,可以理解為增強版JDBC驅動。
  • 對運維、DBA人員無需感知代碼與分片策略規則,運維只需要維護執行建立表和數據的遷移。
  • 相對Mycat這是sharding-jdbc的優勢,減少了部署成本以及DBA學習成本。
  • 原理是通過規則改寫原sql,如select * from A 根據規則變成select * from A_01,運行執行sql時就會向mysql服務器傳select * from A_01指令。

MyCat

  1. 而MyCat並不是業務系統代碼里面的配置,而是獨立運行的中間件,所以配置都會交給DBA執行。
  2. 對於DBA來說,他是一個在mysql Server前,增加一層代理,mycat本身不存數據,數據是在后端的MySQL上存儲的,因此數據可靠性以及事務等都是MySQL保證的。
  3. 為了減少遷移數據的風險,在 上一章推薦的增量遷移算法方案(推薦大家閱讀)講述如何分片達到降低風險。
    若用MyCat,DBA需要配置多次的增量分片規則,每配置一次則要重啟一次,才能達到一輪的數據遷移。實際上MyCat down掉的時系統都不能對數據庫查詢,實際依然對所有用戶有影響。
  4. 然而sharding-jdbc都在代碼實現路由規則,則可以減少DBA操作次數和系統重啟次數,進而減少影響用戶數。

推薦閱讀第一章的第五節才比較好理解上述3~4點 分庫分表算法方案與技術選型(一)

  1. proxy整合大數據思路,將 OLTP 和 OLAP 分離處理,可能會對大數據處理的系統比較適合,畢竟數據工作不一定有java后端系統。

該點總結:sharding-jdbc增量分片和增量遷移數據效果更佳,mycat比較適合大數據工作

備注:
sharding-jdbc增強了JDBC驅動部分功能,但同時也限制部分原生JDBC接口的使用。具體限制參考:
限制情況:http://dangdangdotcom.github.io/sharding-jdbc/01-start/limitations/ 這個文檔現在好像訪問不了
附:
官網文檔
官網源碼

MyCat配置樣例
MyCat配置樣例2

2.分庫分表能力

  • sharding-jdbc另一個優勢是他的分表能力,可以不需要分庫的情況下單庫分表。
  • MyCAT不能單庫分多表,必須分庫,這樣就會造成讓DBA增加機器節點,即使不增加機器節點,也會在同一個機器上增加mysql server實例,若使用sharding-jdbc單庫分多表,則DBA只需要執行建立表語句即可。

3.事務

首先說說XA, XA 多階段提交的方式,雖然對分布式數據的完整性有比較好的保障,但會極大的降影響應用性能。

  • sharding-jdbc和mycat支持弱XA,弱 XA 就是分庫之后的數據庫各自負責自己事務的提交和回滾,沒有統一的調度器集中處理。這樣做的好處是天然就支持,對性能也沒有影響。但一旦出問題,比如兩個庫的數據都需要提交,一個提交成功,另一個提交時斷網導致失敗,則會發生數據不一致的問題,而且這種數據不一致是永久存在的。

  • 柔性事務是對弱 XA 的有效補充。柔性事務類型很多。
    Sharding-JDBC 主要實現的是最大努力送達型。即認為事務經過反復嘗試一定能夠成功。如果每次事務執行失敗,則記錄至事務庫,並通過異步的手段不斷的嘗試,直至事務成功(可以設置嘗試次數,如果嘗試太多仍然失敗則入庫並需要人工干預)。在嘗試的途中,數據會有一定時間的不一致,但最終是一致的。通過這種手段可以在性能不受影響的情況下犧牲強一致性,達到數據的最終一致性。最大努力送達型事務的缺點是假定事務一定是成功的,無法回滾,因此不夠靈活。

備注:
還有一種柔性事務類型是 TCC,即 Try Confirm Cancel。可以通過事務管理器控制事務的提交或回滾,更加接近原生事務,但仍然是最終一致性。其缺點是需要業務代碼自行實現 Try Confirm Cancel 的接口,對現有業務帶來一定沖擊。Sharding-JDBC 未對 TCC 的支持。

4.監控

為什么要監控,因為上述事務的弱XA、最大努力送達型,其實還是有概率失敗。

  • MyCat就要監控頁面,監控MyCat與Mysql server的心跳,運維人員可以看到
  • 而sharding-jdbc沒有監控事務是不是最終執行了,可能需要改寫源碼,如果有個分片沒執行成功就發一下短信、釘釘之類的。
    MyCat監控配置樣例

5.語句限制

  • sharding-jdbc分庫分表使用 like 查詢是有限制的。目前 Shariding-JDBC 不支持 like 語句中包含分片鍵,但不包含分片鍵的 like 語句可以正確執行。
    至於 like 性能問題,是與數據庫相關的,Shariding-JDBC 僅僅是解析 SQL 以及路由至正確的數據源而已。
    是否會查詢所有的庫和表是根據分片鍵決定的,如果 SQL 中不包括分片鍵,就會查詢所有庫和表,這個和是否有 like 沒有關系。
  • MyCat沒有限制

6.比較螞蟻金服的zdal

相對zdal來說,sharding-jdbc的配置量差不多,但是sharding-jdbc提供了java、springboot、yml、spring命名空間方式,而且有官方網站和gitee網站維護。相對zdal用戶更加活躍。


Sharding-jdbc分庫分表整合mybatis-plus 開發樣例

代碼樣例具體描述,下述關鍵的開發點。
具體源碼請到我的gitee地址sharding-jdbc-example

sharding-jdbc分片的開發主要幾個關鍵點:
0. 引入關鍵依賴 2019.10最新版4.0.0-RC2

         <dependency>
			<groupId>org.apache.shardingsphere</groupId>
			<artifactId>sharding-jdbc-spring-namespace</artifactId>
			<version>4.0.0-RC2</version>
		</dependency>
  1. 在xml中配置基礎數據源、分庫分表的策略,其中DbShardingAlgorithm,TbShardingAlgorithm需要在java代碼里面實現。
<--分庫的規則對象類->
    <bean id="preciseModuloDatabaseShardingAlgorithm" class="com.dizang.sharding.config.algorithm.DbShardingAlgorithm" />
    <--分表規則對象類->
    <bean id="preciseModuloTableShardingAlgorithm" class="com.dizang.sharding.config.algorithm.TbShardingAlgorithm" />
    <--分庫根據的key->
    <sharding:standard-strategy id="databaseStrategy" sharding-column="user_id" precise-algorithm-ref="preciseModuloDatabaseShardingAlgorithm" />
    <--分庫根據的key->
    <sharding:standard-strategy id="tableShardingStrategy" sharding-column="user_id" precise-algorithm-ref="preciseModuloTableShardingAlgorithm" />
    
    <sharding:key-generator id="orderKeyGenerator" type="SNOWFLAKE" column="id" />
    
    <sharding:data-source id="shardingDataSource">
    <--分表數據源->
        <sharding:sharding-rule data-source-names="ds0, ds1">
            <sharding:table-rules>
            <--邏輯表名->
                <sharding:table-rule logic-table="t_user" 
                actual-data-nodes="ds$->{0..1}.t_user_$->{0..2}" 
                <--分庫分表邏輯bean->
                database-strategy-ref="databaseStrategy" 
                table-strategy-ref="tableShardingStrategy" 
                key-generator-ref="orderKeyGenerator" />
            </sharding:table-rules>
            <--配置能適用規則的表->
            <sharding:binding-table-rules>
                <sharding:binding-table-rule logic-tables="t_user" />
            </sharding:binding-table-rules>
            <--配置不需要分庫分表的表->
            <sharding:broadcast-table-rules>
                <sharding:broadcast-table-rule table="t_order" />
            </sharding:broadcast-table-rules>
        </sharding:sharding-rule>
    </sharding:data-source>

<--sqlSessionFactory配置shardingDataSource數據源->
    <bean id="sqlSessionFactory"
    class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> 
        <property name="dataSource" ref="shardingDataSource"/>
        <property name="mapperLocations" value="classpath*:mapper/*.xml"/>
    </bean>
  1. java代碼編寫分庫策略
    需要繼承SingleKeyDatabaseShardingAlgorithm分開規則類,重寫equal等於、大於、小於時的路由規則
public class DbShardingAlgorithm implements PreciseShardingAlgorithm<Long>{  

    @Override
    public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {
        for (String each : databaseNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        return null;
    }  

}  
  1. java代碼編寫分表策略
    需要繼承SingleKeyTableShardingAlgorithm分開規則類,重寫equal等於、大於、小於時的路由規則
public class TbShardingAlgorithm implements PreciseShardingAlgorithm<Long>{  

    @Override
    public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {
        for (String each : tableNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
//        return shardingValue.getLogicTableName()+(shardingValue.getValue() % 2);
        throw new UnsupportedOperationException();
    }  

}  

zdal具體代碼實現推薦閱讀

Zdal分庫分表介紹、超詳細一步一步搭建簡單的zdal框架


歡迎關注

我的公眾號 :地藏思維

我的Gitee: 地藏Kelvin https://gitee.com/dizang-kelvin


推薦閱讀sharding-jdbc源碼:

Sharding-JDBC 源碼解析合集

Sharding-JDBC 源碼分析 —— SQL 改寫

原生jdbc讀寫分離


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM