1. 程式人生 > >從零開發分散式資料庫中介軟體 一、讀寫分離的資料庫中介軟體

從零開發分散式資料庫中介軟體 一、讀寫分離的資料庫中介軟體

  在傳統的單機體系中,我們在操作資料庫時,只需要直接得到資料庫的連線,然後操作資料庫即可,可是在現在的資料爆炸時代,只靠單機是無法承載如此大的使用者量的,即我們不能縱向擴充套件,那麼我們就只能水平進行擴充套件,即使用讀寫分離的主從資料庫來緩解資料庫的壓力,而在讀寫分離之後,如何使程式能正確的得到主資料庫的連線或者是從資料庫的連線,就是我們今天讀寫分離的資料庫中介軟體需要實現的。

一、主從資料庫介紹:

  主從資料庫即為一個主資料庫會有對應n個從資料庫,而從資料庫只能有一個對應的從資料庫。主從資料庫中寫的操作需要使用主資料庫,而讀操作使用從資料庫。主資料庫與從資料庫始終保持資料一致性。其中保持資料庫一致的原理即為當主資料庫資料發生變化時,會將操作寫入到主資料庫日誌中,而從資料庫會不停的讀取主資料庫的日誌儲存到自己的日誌系統中,然後進行執行,從而保持了主從資料庫一致。

二、開發前準備及ConnectionFactory類的開發:

  在瞭解了主從資料庫後,我們可以進行分散式資料庫中介軟體的開發,由於mysql本身支援主從資料庫,但限於篇幅,就不講mysql的主從配置了,我們先使用本機的mysql作為一主兩從的資料庫源即可,下面是我本機的資料庫連線配置檔案,其中有一主兩從:

master.driver=com.mysql.jdbc.Driver
master.dburl=jdbc\:mysql\://127.0.0.1\:3306/master_slave_db
master.user=root
master.password=mytestcon

slave1.driver=com.mysql.jdbc.Driver
slave1.dburl=jdbc\:mysql\://127.0.0.1\:3306/master_slave_db
slave1.user=root
slave1.password=mytestcon

slave2.driver=com.mysql.jdbc.Driver
slave2.dburl=jdbc\:mysql\://127.0.0.1\:3306/master_slave_db
slave2.user=root
slave2.password=mytestcon
有了主從資料庫的連線配置後,就可以將配置進行封裝。

封裝的DataSource類:

public class DataSource {

    private String driver;

    private String url;

    private String user;

    private String password;


    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
在Spring配置檔案中,從配置檔案中讀取配置並將配置轉換為封裝的DataSource類:
    <bean id="masterDataSource" class="com.happyheng.connection.DataSource">
        <property name="driver" value="${master.driver}"/>
        <property name="url" value="${master.dburl}"/>
        <property name="user" value="${master.user}"/>
        <property name="password" value="${master.password}"/>
    </bean>

    <bean id="slaveDataSource1" class="com.happyheng.connection.DataSource">
        <property name="driver" value="${slave1.driver}"/>
        <property name="url" value="${slave1.dburl}"/>
        <property name="user" value="${slave1.user}"/>
        <property name="password" value="${slave1.password}"/>
    </bean>

    <bean id="slaveDataSource2" class="com.happyheng.connection.DataSource">
        <property name="driver" value="${slave2.driver}"/>
        <property name="url" value="${slave2.dburl}"/>
        <property name="user" value="${slave2.user}"/>
        <property name="password" value="${slave2.password}"/>
    </bean>

    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:dataSource.properties</value>
            </list>
        </property>
    </bean>
有了主從的連線之後,我們就可以寫一個ConnectionFactory類,此類可以為外部類直接提供主資料庫、從資料庫的連線,相當於資料庫連線的封裝:
@Service
public class ConnectionFactory {

    @Autowired
    private DataSource masterDataSource;

    @Autowired
    private DataSource slaveDataSource1;

    @Autowired
    private DataSource slaveDataSource2;

    private List<DataSource> slaveDataSourceList;

    private int slaveDataSourceSize;


    @PostConstruct
    private void init() {
        slaveDataSourceList = new ArrayList<>();
        slaveDataSourceList.add(slaveDataSource1);
        slaveDataSourceList.add(slaveDataSource2);

        slaveDataSourceSize = slaveDataSourceList.size();
    }


    /**
     * 得到主資料的連線
     */
    public Connection getMasterConnection() {
        return getConnection(masterDataSource);
    }

    /**
     * 得到從資料庫的連線數量
     */
    public int getSlaveDataSourceSize() {
        return slaveDataSourceSize;
    }

    /**
     * 得到從資料n的連線
     */
    public Connection getSlaveConnection(int index){
        return getConnection(slaveDataSourceList.get(index));
    }


    private Connection getConnection(DataSource dataSource){

        Connection connection = null;
        try {
            Class.forName(dataSource.getDriver());

            connection = DriverManager.getConnection(dataSource.getUrl(), dataSource.getUser(), dataSource.getPassword());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }
}
封裝完成後,我們就可以使用getMasterConnection()直接得到主資料庫的連線,使用getSlaveConnection(int)可以得到從資料庫1或者是從資料2的連線。

三、Proxy代理類的實現:

  代理類即是可以讓程式中資料庫訪問得到正確的資料庫連線,所以稱為代理。

  1、使用ThreadLocal為當前執行緒指定資料庫訪問模式:

  由於Proxy不知道程式使用的是主資料庫還是從資料庫,所以程式在訪問資料庫之前要呼叫Proxy代理類來為當前執行緒打一個Tag,即指定是使用主資料庫還是從資料庫。由於而web伺服器中每個請求是多執行緒環境,所以使用ThreadLocal類:

  2、使用隨機法來訪問從資料庫:

  由於從資料庫有多個,所以我們可以使用隨機法來隨機訪問每個從資料庫,隨機法在高併發的情況下有很平均的分佈,效能也非常好。

  3、具體實現:

@Service
public class DataSourceProxy {

    ThreadLocal<String> dataSourceThreadLocal = new ThreadLocal<>();

    public static final String MASTER = "master";
    public static final String SLAVE = "slave";

    @Resource
    private ConnectionFactory connectionFactory;

    /**
     * 設定當前執行緒的資料庫Mode
     */
    public void setMode(String dataMode) {
        dataSourceThreadLocal.set(dataMode);
    }

    /**
     * 得到當前資料庫Mode
     */
    public String getMode() {
        return dataSourceThreadLocal.get();
    }

    /**
     * 根據當前Mode得到Connection連線物件
     */
    public Connection getThreadConnection() {

        // 1.判斷當前是從資料還是主資料庫,預設是主資料庫
        String mode = getMode();
        if (!StringUtils.isEmpty(mode) && SLAVE.equals(mode)) {

            // y1.如果是從資料庫,那麼使用隨機數的形式來得到從資料庫連線
            double random = Math.random();
            int index = (int) (random * connectionFactory.getSlaveDataSourceSize());

            System.out.println("----使用的為第" + (index + 1) + "從資料庫----");

            return connectionFactory.getSlaveConnection(index);
        } else {

            System.out.println("----使用的為主資料庫----");

            // f1.如果是主資料庫,因為只有一個,所以直接獲取即可
            return connectionFactory.getMasterConnection();
        }

    }

}

4、此工程已在github上開源,可以完整實現資料庫的讀寫分離,地址為:github 。如果覺得不錯,那麼就star一下來鼓勵我吧。 

相關推薦

開發分散式資料庫中介軟體 分離資料庫中介軟體

  在傳統的單機體系中,我們在操作資料庫時,只需要直接得到資料庫的連線,然後操作資料庫即可,可是在現在的資料爆炸時代,只靠單機是無法承載如此大的使用者量的,即我們不能縱向擴充套件,那麼我們就只能水平進行擴充套件,即使用讀寫分離的主從資料庫來緩解資料庫的壓力,而在讀寫分離之後

開發分布式數據庫中間件 分離的數據庫中間件(轉)

mark str 日誌系統 arraylist none views gpo arr 體系 從零開發分布式數據庫中間件 一、讀寫分離的數據庫中間件

阿里P8架構師談:資料庫分庫分表分離的原理實現,使用場景

為什麼要分庫分表和讀寫分離?   類似淘寶網這樣的網站,海量資料的儲存和訪問成為了系統設計的瓶頸問題,日益增長的業務資料,無疑對資料庫造成了相當大的負載,同時對於系統的穩定性和擴充套件性提出很高的要求。隨著時間和業務的發展,資料庫中的表會越來越多,表中的資料量也會越來越大,相應地,

使用Mycat實現Mysql資料庫的主從複製分離分表分庫負載均衡和高可用

Mysql叢集搭建 使用Mycat實現Mysql資料庫的主從複製、讀寫分離、分表分庫、負載均衡和高可用(Haproxy+keepalived),總體架構:   說明:資料庫的訪問通過keepalived的虛擬IP訪問HAProxy負載均衡器,實現HAProxy的高可用,HAProxy用於實

資料庫分庫分表分離的實現原理及使用場景

為什麼要分庫分表和讀寫分離? 類似淘寶網這樣的網站,海量資料的儲存和訪問成為了系統設計的瓶頸問題,日益增長的業務資料,無疑對資料庫造成了相當大的負載,同時對於系統的穩定性和擴充套件性提出很高的要求。隨著時間和業務的發展,資料庫中的表會越來越多,表中的資料量也會越來越

阿里P8架構師談:資料庫分庫分表分離的原理和實現,以及使用場景

架構設計的重要的一環:資料庫分庫分表、讀寫分離,希望你看完本篇,能獨立完成該環節的設計!   為什麼要分庫分表和讀寫分離? 類似淘寶網這樣的網站,海量資料的儲存和訪問成為了系統設計的瓶頸問題,日益增長的業務資料,無疑對資料庫造成了相當大的負載,同時對於系統的穩定性和擴充套件性提出很高的要求。隨

Mysql主從複製分離+MyCat資料庫中介軟體

最近搭建了 MySQL 主從 並使用MyCat作為資料庫中介軟體 版本: Mysql  5.5.48 Linux :CentOS 6.8 MyCat : 1.4 節點: 192.168.152.11Cluster1 192.168.152.12Cluster2 192.1

Mysql 分散式叢集 主從同步 分離 amoeba 中介軟體配置

首先說明一下amoeba 跟 MySQL proxy在讀寫分離的使用上面的區別: 在MySQL proxy 6.0版本 上面如果想要讀寫分離並且 讀叢集、寫叢集 機器比較多情況下,用mysql proxy 需要相當大的工作量,目前mysql proxy沒有現

使用MyCat中介軟體代理MySql分離

其前提條件: mysql主從複製已經配置完成 配置過程可以參考這篇文章 目的 使用mycat作為一個訪問資料庫前的一層,用來管理讀寫操作,而不用配置多個數據源訪問不同mysql伺服器 當前資訊: 主mysql:118.25.178.145,使用者名稱root,密碼123456

MySQL中介軟體proxysql實現分離

環境說明: IP 角色 應用 平臺 192.168.161.96 讀寫分離解析主機 proxysql rhel7.4 19

CentOS7,MySQL主從配置和分離(MySQL主從分離分散式資料庫分離主從配置)

一、實驗目標搭建兩臺MySQL伺服器,一臺作為主伺服器,一臺作為從伺服器,主伺服器進行寫操作,從伺服器進行讀操作。二、測試環境主資料庫: CentOS7, MySQL15.1 , 192.168.1.233從資料庫: CentOS7, MySQL15.1 , 192.168.

Mysql 實現分離-Atlas中介軟體

Mysq主從同步原理: Mysql 之間資料複製的基礎是二進位制日誌檔案(bin log file) Slave 資料庫作為slave通過一個 I/O執行緒與主伺服器保持通訊,並監控master的二進位制日誌檔案的變化,如果發現,master二進位制檔案發生變化,則會把變

Linux—Centos7.4之搭建Mysql數據庫主同步分離

搭建Mysql主從同步、讀寫分離MySQL主從同步與讀寫分離 目錄第一部分 實驗環境第二部分 配置主從同步第三部分 配置讀寫分離第四部分 測試驗證 第一部分 實驗環境 實驗拓撲圖: 服務器五臺:1)客戶端服務器一臺:IP地址:192.168.80.10(client)需安裝軟件:mysql-bo

【Qt開發】QThread中的互斥訊號量條件變數

在gemfield的《從pthread到QThread》一文中我們瞭解了執行緒的基本使用,但是有一大部分的內容當時說要放到這片文章裡討論,那就是執行緒的同步問題。關於這個問題,gemfield在《從進 程到執行緒》中有一個比喻,有必要重新放在下面溫習下: ***************

. Mysql分離 :Linux上配置,通過binlog進行主從同步

mysql主從複製,讀寫分離配置   1.主資料庫:       a.在主資料庫裡建立一個同步賬號      #每個從資料庫會使用一個MySQL賬號來連線主資料庫,所以我們要在主資料庫裡建立一個賬號,並且該賬號要授予

資料庫分割槽分表以及分離

資料庫結構的優化有多種方法,主要的有兩種: 一是利用儲存過程來代替常用的SQL查詢語句,減少sql語句解析編譯的過程。      另一種是使用資料庫管理系統中的分割槽表方法進。使用儲存過程的優化方法有

mysql主從複製分離資料庫水平拆分及庫表雜湊

web專案最原始的情況是一臺伺服器只能連線一個mysql伺服器(c3p0只能配置一個mysql),但隨著專案的增大,這種方案明顯已經不能滿足需求了。Mysql主從複製,讀寫分離:上面的方案使用mysql-Proxy代理,分發讀寫請求,寫操作轉發到Mysql主伺服器,讀操作轉發

資料庫水平切分的實現原理—分庫分表分離負載均衡主從複製

水平切分資料庫的目的 其主要目的是為突破單節點資料庫伺服器的 I/O 能力限制,解決資料庫擴充套件性問題  通過一系列的切分規則將資料水平分佈到不同的DB或table中,在通過相應的DB路由或者table路由規則找到需要查詢的具體的DB或者table,以進行Query操作

資料庫資料庫負載均衡分離技術

隨著網際網路應用的廣泛普及,海量資料的儲存和訪問成為了系統設計的瓶頸問題。對於一個大型的網際網路應用,每天百萬級甚至上億的PV無疑對資料庫造成了相當高的負載。對於系統的穩定性和擴充套件性造成了極大的問題。 一、負載均衡技術 負載均衡叢集是由一組相互獨立的計算機系統構成,通過

CQRS-分離的資料處理模式

譯者按: 本文是翻譯自Martin Fowler的一篇部落格。 老馬同志向來是我所敬仰的大師級人物,現在的“微服務”這個詞就是從老馬同志的部落格開始火起來的。 原文連結 CQRS CQRS指的是命令查詢職責分離模式,最早我聽 Greg You