程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Cobar + MySQL 技術驗證(Ali),cobarali

Cobar + MySQL 技術驗證(Ali),cobarali

編輯:JAVA綜合教程

Cobar + MySQL 技術驗證(Ali),cobarali


一、簡介

  Cobar是一個對數據進行拆分後進行分布式存儲的產品,可以支持使用後台的 MySQL或者Oracle數據庫,通過配置,將數據按照一定規則存儲入不同的數據庫中。即用分布式數據庫代替了集中式數據庫。傳統的集中式數據庫系統有如下不足:集中式處理,勢必造成性能瓶頸;應用程序集中在一台計算機上運行,一旦該計算機發生故障,則整個系統受到影響,可靠性不高;集中式處理引起系統的規模和配置都不夠靈活,系統的可擴充性差。在這種形勢下,集中式數據庫將向分布式數據庫發展。

  分布式數據庫系統的優點:降低費用。分布式數據庫在地理上可以是分布的。其系統的結構符合這種分布的要求。允許用戶在自己的本地錄用、查詢、維護等操作,實行局部控制,降低通信代價,避免集中式需要更高要求的硬件設備。而且分布式數據庫在單台機器上面數據量較少,其響應速度明顯提升;提高系統整體可用性。避免了因為單台數據庫的故障而造成全部癱瘓的後果;易於擴展處理能力和系統規模。分布式數據庫系統的結構可以很容易地擴展系統,在分布式數據庫中增加一個新的節點,不影響現有系統的正常運行。這種方式比擴大集中式系統要靈活經濟。在集中式系統中擴大系統和系統升級,由於有硬件不兼容和軟件改變困難等缺點,升級的代價常常是昂貴和不可行的。

//優點: 
//        配置簡單, 可以很方便的實現數據的分布式存儲。
//        使用透明, 客戶端幾乎不需要為此做任何的特殊設定。
//        擴展方便, Cobar服務端可以通過負載均衡進行擴展, 數據庫可以根據不同的壓力進行擴張。
//
//缺點:
//        查詢限制, 如果提交的請求不包含分表字段的限制, 則可能在多個分區執行, 效率和可行性都大打折扣 (碰到過一個普通查詢拋出異常的情況, 具體場景還需要驗證)
//        聯合查詢限制, 對於在不同分區的數據, 無法進行聯合查詢。
//        擴展, 在初始時的分區數目如果無法應對後續需求, 需要增加分區的話 (如, 初始設計分為 64 個分區表, 因為單表通常限制數據量在 20G, 
//        後期發現無法滿足容量需求, 需要擴展成 128/256 個分區), 沒有現成的解決方案, 只能對數據進行人工拆分

  Cobar在分布式數據庫領域將致力解決數據切分,應付客戶端"集中式"處理分布式數據。這兒集中式是一個相對概念,客戶端不需要知道某種數據的物理存儲地。避免這種邏輯出現在業務端,大大簡化了客戶端操作分布式數據的復雜程度。 專注分布式數據庫proxy開發。其架設在Client、DB Server(s)之間、對客戶端透明、具有負載均衡、高可用性、sql過濾、讀寫分離、可路由相關的query到目標數據庫、可並發請求多台數據庫合並結果。

                            

二、Cobar的使用驗證

  目前, 我在開發環境 10.20.130.119 上部署了 Cobar 和 MySQL 的測試環境:MySQL 分為 128 個 DataBase, 分別是 cobar_1 至 cobar_128, 端口是 3306, 用戶名/密碼: root/password。Cobar 的訪問方式為使用 MySQL 連接, URL 為 jdbc:mysql://10.20.130.119:8066/cobar, 用戶名/密碼: root/12345。測試數據庫表為 q_reportkeywordsum, 分區所用字段為 custid, int 型。如果使用JDBC方式連接Cobar, 則只需要使用 MySQL的JDBC驅動(注意,不能使用最新的 5.1.13 版本, 需要使用 Cobar 自帶的 5.1.6 版 MySQL Connector),正常連接即可。示例代碼如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class CobarHelloWorld {

    public void mian(String[] args) {
        String url = "jdbc:mysql://10.20.130.119:8066/cobar";
        String driver = "com.mysql.jdbc.Driver";
        String user = "root";
        String pwd = "12345";
        Connection con = null;
        try {
            Class.forName(driver).newInstance();
            con = DriverManager.getConnection(url, user, pwd);
            Statement stmt = con.createStatement();
            // TODO
            stmt.close();
        } catch (Exception e) {
            // ...
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

如果使用 Spring + iBatis 訪問, 則需要對配置文件作少許改動, 將原org.springframework.orm.ibatis.SqlMapClientTemplate 替換為 Cobar Client 提供的com.alibaba.cobar.client.CobarSqlMapClientTemplate。同時, 將TransactionManager從原 org.springframework.jdbc.datasource.DataSourceTransactionManager替換為 com.alibaba.cobar.client.transaction.MultipleDataSourcesTransactionManager,其他部分不需要改動, 修改後的配置代碼類似以下示例:

<bean id="sqlMapClientTemplate" class="com.alibaba.cobar.client.CobarSqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClient"/>
...
</bean>
 
<bean id="transactionManager" class="com.alibaba.cobar.client.transaction.MultipleDataSourcesTransactionManager">
...
</bean>
 
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:META-INF/ibatis/sqlmap-config.xml" />
</bean>
 
<bean id="dataSource" ...>
...
</bean>

開發注意點:如果查詢條件不包含分區字段條件, 則會將請求在所有的分區執行後返回全部結果集, 如執行:

select count(*) from q_reportkeywordsum

則返回所有分區中的查詢結果 (如分區為 128 個, 則結果集中包含 128 個記錄). 而且, 在這樣的情況下, 效率會很差, 需要等待 128 個分區全部執行完後才會返回結果集.解決: 所有查詢都 必須 限定在某一指定的分區字段, 如

select count(*) from q_reportkeywordsum where custid=1

但是,要注意:select count(*) from q_reportkeyworsum where custid < 10; 代碼是不能正確返回結果的。同樣的,如果插入記錄時不指定分區字段, 則會在所有分區表內均插入記錄, 如執行:

insert into q_reportkeywordsum (id, keywordid) values (2, ...)

將會在全部 128 個分區內均插入本條記錄。解決: 對於用作分區規則的字段 (如示例中所用 custid) 必須設置為非空 (NOT NULL) 字段,以避免此類問題。對於不同的分區表, 數據庫主鍵可以重復, 這一點從上一段即可看出, id 作為主鍵字段, 插入過程會在所有分區中均插入一條 id 為 2 的記錄, 因此, 需要額外使用主鍵生成機制保障在不同表內的主鍵不會發生重復。

三、Cobar使用約束

Cobar表的水平拆分,上圖中,數據庫表被水平拆分成2份,分別放到兩個庫中。F( x )是拆分函數,它根據每一條記錄的拆分字段的取值,決定將這條記錄拆分到哪個庫裡。拆分函數可以是多元函數,即 F(x1,x2,..xn)。但是對任意一個拆分函數,不存在該函數的兩個自變量xi,xj,使得 xi 和 xj 是來自不同拆分表的拆分字段。

左圖所示,cobar位於應用和數據庫之間,cobar與應用通過mysql protocol交互。若應用發來的sql語句中包含拆分字段(拆分函數的自變量),以左圖方式工作:否則,根據配置,以右圖方式工作,或直接報錯。

// 如果應用和cobar之間通過F5連接,那麼F5與cobar的連接保持時間設置為1小時。
// 應用必須通過mysql-connector-5.0.4連接cobar,拆分函數值域元素數最大1024
// 不支持DDL,不支持事務,不允許跨庫的join、跨庫的子查詢、跨庫的分頁排序
// 對於操作拆分表的sql語句,需包含拆分字段,方式如下:
// 1.對select, delete, update語句,拆分字段存在於where中,以c[i]=xx的形式存在(運算符必須是=、xx必須是某個具體值,不能是字段名或子查詢結果)
// 2.insert語句(insert into table (c1, c2 ...) values (value1,value2); insert into table set
// c1=value1,c2=....)中拆分字段出現在紅色部分中,同時拆分字段對應的valueXX也必須是某個具體值。

// 建議:
// 1. 記錄數小於1千萬或表空間小於10G的,不做拆分。
// 2. F(拆分字段取值)服從均勻分布,其中F是拆分函數。

備注:

利用Redis解決MySQL分表自增ID的問題。采用redis的ID自增生成器 就行,每次插入之前,都去調用一個自增長的函數,返回的數值永遠是唯一,全局唯一的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved