Cobar + MySQL 技術驗證(li)

1、簡介html

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

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

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

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

                            

2、Cobar的使用驗證spring

  目前, 我在開發環境 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),正常鏈接便可。示例代碼以下:sql

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 的記錄, 所以, 須要額外使用主鍵生成機制保障在不一樣表內的主鍵不會發生重複。

3、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自增生成器 就行,每次插入以前,都去調用一個自增加的函數,返回的數值永遠是惟一,全局惟一的

相關文章
相關標籤/搜索