zoukankan      html  css  js  c++  java
  • 数据库主从设置

    对于一些访问量比较大的项目,我们常常采用数据库主从的方式进行读写分离,以分流用户操作,实现负载均衡。因此网上查找了相关的信息,做一个总结。下面的概念部分内容摘自百科或网络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

    采自:http://www.2cto.com/kf/201207/139130.html

  • 相关阅读:
    异步-promise、async、await
    node
    node基础 day1
    gulp的简介以及使用方法
    web前端安全——常见的web攻击方法
    Linux修改IP地址
    在linux下批量删除文件
    常用内容的正则表达式
    Oracle 数据库自带用户有哪些
    统计Oracle数据库当前User下各表的记录数
  • 原文地址:https://www.cnblogs.com/flyoo/p/3120634.html
Copyright © 2011-2022 走看看