程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 數據庫主從設置

數據庫主從設置

編輯:關於PHP編程

對於一些訪問量比較大的項目,我們常常采用數據庫主從的方式進行讀寫分離,以分流用戶操作,實現負載均衡。因此網上查找了相關的信息,做一個總結。下面的概念部分內容摘自百科或網絡PPT,結尾的代碼源自此次項目。

首先,因為之前沒有做過類似的功能,需要在概念上進行了解:

負載均衡
負載均衡(Load Balance):將負載(工作任務)進行平衡、分攤到多個操作單元上進行執行,從而共同完成工作任務。主要分為兩種類型:
1.集群(clustering)
單個重負載的運算分擔到多台節點設備上做並行處理,每個節點設備處理結束後,將結果匯總,返回給用戶,使系統處理能力得到大幅度提高。
2.分流
大量的並發訪問或數據流量分擔到多台節點設備上分別處理,減少用戶等待響應的時間,這主要針對Web服務器、FTP服務器、企業關鍵應用服務器等網絡應用。主從架構就是這種類型的負載均衡。

主從架構的好處
1.負載均衡(讀寫分離,提升數據處理效率)
2.高可用和故障轉移的能力(數據分布,穩定性提升。主服務器出現故障,還可以用從服務器支撐)
3.備份(本身不能備份,但是能提供一個備份機,便於實現數據庫的容災、備份、恢復等操作)
4.數據一致性,避免沖突
5.測試Mysql升級

Mysql的復制功能
1:支持一主多從機制。數據通過主服務器復制到從服務器上。
2:支持多級結構。主從,從從,主主(互為主從)。
3:支持過濾功能(可以只復制主服務器上的部分數據,而非全部)。

復制的類型
1. 基於語句的復制:在主服務器上執行的SQL語句,在從服務器上執行同樣的SQL語句。Mysql默認采用基於語句的復制,效率比較高。
2. 基於行的復制:把改變的內容復制過去,而不是把命令在從服務器上執行一遍(mysql5.0開始支持)。
3. 混合類型的復制:默認采用基於語句的復制。發現基於語句無法精確復制時,就會采用基於行的復制
相應的二進制日志也有三種:
1:STATEMENT
2:ROW
3:MIXED

服務器結構的要求
1:主從服務器中的表可以使用不同的表類型。另外:一台主服務器同時帶多台從服務器,會影響其性能,可以拿出一台服務器作為從服務器代理,使用BLOCKHOLE表類型。只記錄日志,不寫數據,由它帶多台服務器,從而提升性能。     
2:主從服務器中的表可以使用不同的字段類型。
3:主從服務器中的表可以使用不同的索引。主服務器主要用來寫操作,所以除了主鍵和唯一索引等保證數據關系的索引一般都可以不加;從服務器一般用來讀操作,所以可以針對查詢特征設置索引。甚至:不同的從服務器可以針對不同的查詢設置不同的索引。

復制流程
1:master服務器將改變記錄到二進制日志文件(binary log)中,這些記錄叫做二進制日志事件(binary log events)
2:slave服務器將master的binary log  events拷貝到他的中繼日志(relay log)
3:slave重做中繼日志的事件,將改變反映到它自己的數據。

PHP代碼實現
1.服務器連接配置文件
如有多態主|從服務器,那麼只需數字往下遞增即可。

[php] 
[database] 
dbname                              = "vis_db" 
charset                             = "utf8" 
;主 
servers.0.master                    = true 
servers.0.adapter                   = "MYSQLI" 
servers.0.host                      = "vis_db" 
servers.0.username                  = "vis" 
servers.0.password                  = "vis" 
;從 
servers.1.master                    = false 
servers.1.adapter                   = "MYSQLI" 
servers.1.host                      = "vis_mmc" 
servers.1.username                  = "vis" 
servers.1.password                  = "vis" 

2.數據庫操作類代碼
根據用戶IP取余後,確定連接哪台服務器上的數據庫。
項目中使用了Zend Framework框架。
[php] 
<?php 
 
/**
 * 數據庫工廠類
 * 
 * @create 2012-05-29
 * @note:該類用於創建各種配置參數的Zend_Db_Adapter實例
 */ 
include_once 'lib/getRequestIP.php'; 
 
class Free_Db_Factory 

 
    /**
     * Zend_Db_Adapter實例數組
     *
     * @var array
     */ 
    protected static $_dbs = array(); 
 
    protected function __construct($sName) 
    { 
        try { 
            $params = $this->_getDbConfig($sName); 
            self::$_dbs[$sName] = Zend_Db::factory($params['adapter'], $params); 
        } catch (Exception $e) { 
            if (DEBUG) { 
                echo $e->getMessage(); 
            } 
            exit; 
        } 
    } 
 
    /**
     * 獲取Zend_Db_Adapter實例
     * @return Zend_Db_Adapter
     */ 
    public static function getDb($sName) 
    { 
        if (emptyempty($sName)) { 
            exit; 
        } 
 
        if (!isset(self::$_dbs[$sName])) { 
            new self($sName); 
        } 
        return self::$_dbs[$sName]; 
    } 
 
    /**
     * 獲取數據庫的配置
     */ 
    private function _getDbConfig($sName) 
    { 
        $configArr = array(); 
        $dbConfig = Zend_Registry::get('db')->database->toArray(); 
        $serverConfigs = $dbConfig['servers']; 
        $masters = array(); 
        $slaves = array(); 
        foreach ($serverConfigs as $value) { 
            if (!isset($value['master'])) { 
                continue; 
            } 
            if (true == $value['master']) { 
                $masters[] = $value; 
            } 
            if (false == $value['master']) { 
                $slaves[] = $value; 
            } 
        } 
        $masterNum = count($masters); 
        $slaveNum = count($slaves); 
 
        $requestIP = $this->_getRequestIP(); 
 
        switch ($sName) { 
            case 'master' : 
                if ($masterNum > 1) { 
                    $configArr = $masters[$requestIP % $masterNum]; 
                } else { 
                    $configArr = $masters[0]; 
                } 
                break; 
            case 'slave' : 
                if ($slaveNum > 1) { 
                    $configArr = $slaves[$requestIP % $slaveNum]; 
                } else { 
                    $configArr = $slaves[0]; 
                } 
                break; 
            default : 
                break; 
        } 
        if (emptyempty($configArr)) { 
            return array(); 
        } 
 
        $configArr['dbname'] = $dbConfig['dbname']; 
        $configArr['charset'] = $dbConfig['charset']; 
        return $configArr; 
    } 
 
    /**
     * 獲取請求IP
     */ 
    private function _getRequestIP() 
    { 
        $ip = getRequestIP(true); 
        return sprintf('%u', ip2long($ip)); 
    }   www.2cto.com
 
    /**
     * 析構Zend_Db_Adapter實體(由於有些請求很耗時間,這段時間可能會讓數據庫超時)
     */ 
    public static function destructDb($sName = null) 
    { 
        if (null === $sName) { 
            self::$_dbs = null; 
        } else { 
            unset(self::$_dbs[$sName]); 
        } 
    } 
 

調用代碼時,傳入一個標志,確定是操作主還是從數據庫即可:
[php] 
$oSlaveDb = Free_Db_Factory::getDb('slave'); 


作者:xinsheng2011

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