mysql讀寫分離(PHP類)
自己實現了php的讀寫分離,並且不用修改程式
優點:實現了讀寫分離,不依賴伺服器硬體配置,並且都是可以配置read伺服器,無限擴充套件
缺點:錯誤轉移不購明確,現只有3次嘗試機會,失敗了就會選擇其他的伺服器.當伺服器恢復時,需要手動去消除錯誤日誌不人性化
修改於discux x 的mysql類
配置檔案
“db”=>array(
`1`=>array(
`dbhost`=> `127.0.0.1`,
`dbuser` => `root`,
`dbpw` => `xxx`,
`dbcharset` => `utf8`,
`pconnect` => `0`,
`dbname` => `test`,
`tablepre` => `w_`,
),
`2`=>array(
`dbhost`=> `127.0.0.1`,
`dbuser` => `root`,
`dbpw` => `xxx`,
`dbcharset` => `utf8`,
`pconnect` => `0`,
`dbname` => `test2`,
`tablepre` => `w_`,
),
`3`=>array(
`dbhost`=> `127.0.0.1`,
`dbuser` => `root`,
`dbpw` => `xxx`,
`dbcharset` => `utf8`,
`pconnect` => `0`,
`dbname` => `test3`,
`tablepre` => `w_`,
),
`writes`=>array(`2`,`3`),
`reads`=>array(`2`,`1`),
`broken`=>array(),
`broken_file`=>str_replace(`\`,`/`,dirname(__FILE__)) .”/____mysql_broken_file.php”,
//`broken_file`=>array(),
)
類檔案
<?php
/*
[Discuz!] (C)2001-2009 Comsenz Inc.
This is NOT a freeware, use is subject to license terms
$Id: db_mysql.class.php 20294 2009-09-23 06:00:37Z zhaoxiongfei $
*/
if(!defined(`IN_APP`)) {
exit(`Access Denied`);
}
class lib_db_mysql extends app_lib
{
var $tablepre;
var $version = “;
var $querynum = 0;
var $curlink;
var $link = array();
var $config = array();
var $sqldebug = array();
var $map = array();
var $reads=array();//讀伺服器id
var $writes=array();//寫伺服器id
var $broken=array();//重試3次壞掉的伺服器
var $broken_file=””;
function init(){
$this->set_config(config_item(`db`));
}
function set_config($config) {
$this->config = &$config;
$this->tablepre = $config[`1`][`tablepre`];
if(!empty($this->config[`map`])) {
$this->map = $this->config[`map`];
}
/**
* 讀寫分離
*/
if(!empty($this->config[`reads`])) {
$this->reads=$this->config[`reads`];
unset($this->config[`reads`]);
}
if(!empty($this->config[`writes`])) {
$this->writes=$this->config[`writes`];
unset($this->config[`writes`]);
}
if(!empty($this->config[`broken_file`])) {
$this->broken_file=$this->config[`broken_file`];
unset($this->config[`broken_file`]);
}else{
$this->broken_file=str_replace(`\`,`/`,dirname(__FILE__)) .”/____mysql_broken_file.php”;
}
$this->broken=$this->get_broken($this->config[`broken`]);
unset($this->config[`broken`]);
//-讀寫分離
}
function connect($serverid = 1) {
if(empty($this->config) || empty($this->config[$serverid])) {
$this->set_broken($serverid);
$this->halt(`config_db_not_found`);
}
$this->link[$serverid] = $this->_dbconnect(
$this->config[$serverid][`dbhost`],
$this->config[$serverid][`dbuser`],
$this->config[$serverid][`dbpw`],
$this->config[$serverid][`dbcharset`],
$this->config[$serverid][`dbname`],
$this->config[$serverid][`pconnect`],
$serverid
);
$this->curlink = $this->link[$serverid];
}
function _dbconnect($dbhost, $dbuser, $dbpw, $dbcharset, $dbname, $pconnect,$serverid=0) {
$link = null;
$func = empty($pconnect) ? `mysql_connect` : `mysql_pconnect`;
if(!$link = @$func($dbhost, $dbuser, $dbpw, 1)) {
$this->set_broken($serverid);
$this->halt(`notconnect`);
} else {
$this->curlink = $link;
if($this->version() > `4.1`) {
$dbcharset = $dbcharset ? $dbcharset : $this->config[1][`dbcharset`];
$serverset = $dbcharset ? `character_set_connection=`.$dbcharset.`, character_set_results=`.$dbcharset.`, character_set_client=binary` : “;
$serverset .= $this->version() > `5.0.1` ? ((empty($serverset) ? “ : `,`).`sql_mode=“`) : “;
$serverset && mysql_query(“SET $serverset”, $link);
}
$dbname && @mysql_select_db($dbname, $link);
}
return $link;
}
function table($tablename) {
if(!empty($this->map) && !empty($this->map[$tablename])) {
$id = $this->map[$tablename];
if(!$this->link[$id]) {
$this->connect($id);
}
$this->curlink = $this->link[$id];
} else {
$this->curlink = $this->link[1];
}
return $this->tablepre.$tablename;
}
function select_db($dbname) {
return mysql_select_db($dbname, $this->curlink);
}
function fetch_array($query, $result_type = MYSQL_ASSOC) {
return mysql_fetch_array($query, $result_type);
}
function fetch_first($sql) {
return $this->fetch_array($this->query($sql));
}
function result_first($sql) {
return $this->result($this->query($sql), 0);
}
/**
* 讀寫分離,並從池中選中隨機選中資料庫
* 如果沒有read連線將使用write代替
*
* @param string $sql
*/
function switch_server($sql,$default=1){
$sql=ltrim($sql);
if(preg_match(`/^select/i`,$sql)){
$type=`reads`;
}else{
$type=`writes`;
}
$servers=array_diff($this->$type,$this->filter_broken($this->broken));
if(!$servers&&$type==`reads`){
$type=`writes`;
$servers=array_diff($this->$type,$this->filter_broken($this->broken));
}
$t=count($servers);
if($t>0){
//有合理的服務
/**
* 根據ip的hash隨機抽伺服器執行,
*/
$servers=array_values($servers);
$onlineip = “;
if(getenv(`HTTP_CLIENT_IP`) && strcasecmp(getenv(`HTTP_CLIENT_IP`), `unknown`)) {
$onlineip = getenv(`HTTP_CLIENT_IP`);
} elseif(getenv(`HTTP_X_FORWARDED_FOR`) && strcasecmp(getenv(`HTTP_X_FORWARDED_FOR`), `unknown`)) {
$onlineip = getenv(`HTTP_X_FORWARDED_FOR`);
} elseif(getenv(`REMOTE_ADDR`) && strcasecmp(getenv(`REMOTE_ADDR`), `unknown`)) {
$onlineip = getenv(`REMOTE_ADDR`);
} elseif(isset($_SERVER[`REMOTE_ADDR`]) && $_SERVER[`REMOTE_ADDR`] && strcasecmp($_SERVER[`REMOTE_ADDR`], `unknown`)) {
$onlineip = $_SERVER[`REMOTE_ADDR`];
}
!$onlineip&&$onlineip=rand(100);
$i=abs(crc32($onlineip))%$t;
return $servers[$i];
}
return $default;
}
function set_broken($server_id){
$this->broken[$server_id]++;
if($this->broken_file){
$str=var_export($this->broken,true);
$c=”<?php
$broken=$str;
?>”;
return file_put_contents($this->broken_file,$c);
}
}
function filter_broken($broken){
$error_try=3;
foreach($broken as $id=>$num){
if($num<$error_try){
unset($broken[$id]);
}
}
return array_keys($broken);
}
function get_broken($realbroken){
$broken=array();
$error_try=3;
if($this->broken_file&&is_file($this->broken_file)){
@include($this->broken_file);
}
settype($realbroken,`array`);
foreach($realbroken as $id){
$broken[$id]=$error_try;
}
return $broken;
}
/**
* 讀寫分離
*
* @param mixed $sql
* @param mixed $type
*/
function query($sql, $type = “) {
if(defined(`DISCUZ_DEBUG`) && DISCUZ_DEBUG) {
$starttime = dmicrotime();
}
//讀寫分離
$server_id=$this->switch_server($sql,1);
if($this->link[$server_id]){
$this->curlink=$this->link[$server_id];
}else{
$this->connect($server_id);
}
//-讀寫分離
$func = $type == `UNBUFFERED` && @function_exists(`mysql_unbuffered_query`) ?
`mysql_unbuffered_query` : `mysql_query`;
if(!($query = $func($sql, $this->curlink))) {
if(in_array($this->errno(), array(2006, 2013)) && substr($type, 0, 5) != `RETRY`) {
$this->connect($server_id);
return $this->query($sql, `RETRY`.$type);
}
if($type != `SILENT` && substr($type, 5) != `SILENT`) {
$this->halt(`query_error`, $sql);
}
}
if(defined(`DISCUZ_DEBUG`) && DISCUZ_DEBUG) {
$this->sqldebug[] = array($sql, number_format((dmicrotime() – $starttime), 6), debug_backtrace());
}
$this->querynum++;
return $query;
}
function affected_rows() {
return mysql_affected_rows($this->curlink);
}
function error() {
return (($this->curlink) ? mysql_error($this->curlink) : mysql_error());
}
function errno() {
return intval(($this->curlink) ? mysql_errno($this->curlink) : mysql_errno());
}
function result($query, $row = 0) {
$query = @mysql_result($query, $row);
return $query;
}
function num_rows($query) {
$query = mysql_num_rows($query);
return $query;
}
function num_fields($query) {
return mysql_num_fields($query);
}
function free_result($query) {
return mysql_free_result($query);
}
function insert_id() {
return ($id = mysql_insert_id($this->curlink)) >= 0 ? $id : $this->result($this->query(“SELECT last_insert_id()”), 0);
}
function fetch_row($query) {
$query = mysql_fetch_row($query);
return $query;
}
function fetch_fields($query) {
return mysql_fetch_field($query);
}
function version() {
if(empty($this->version)) {
$this->version = mysql_get_server_info($this->curlink);
}
return $this->version;
}
function close() {
return mysql_close($this->curlink);
}
function halt($message = “, $sql = “) {
global $_G;
$dberror = $this->error();
$dberrno = $this->errno();
$phperror = `<table style=”font-size:11px” cellpadding=”0″><tr><td width=”270″>File</td><td width=”80″>Line</td><td>Function</td></tr>`;
foreach (debug_backtrace() as $error) {
$error[`file`] = str_replace(DISCUZ_ROOT, “, $error[`file`]);
$error[`class`] = isset($error[`class`]) ? $error[`class`] : “;
$error[`type`] = isset($error[`type`]) ? $error[`type`] : “;
$error[`function`] = isset($error[`function`]) ? $error[`function`] : “;
$phperror .= “<tr><td>$error[file]</td><td>$error[line]</td><td>$error[class]$error[type]$error[function]()</td></tr>”;
}
$phperror .= `</table>`;
$helplink = “http://faq.comsenz.com/?type=mysql&dberrno=”.rawurlencode($dberrno).”&dberror=”.rawurlencode($dberror);
@header(`Content-Type: text/html; charset=`.$_G[`config`][`output`][`charset`]);
echo `<div style=”position:absolute;font-size:11px;font-family:verdana,arial;background:#EBEBEB;padding:0.5em;line-height:1.5em”>`;
echo “<b>PHP Backtrace</b><br />$sql error<br /> $dberror</div>”;
exit();
}
function delete($table, $condition, $limit = 0, $unbuffered = true) {
if(empty($condition)) {
$where = `1`;
} elseif(is_array($condition)) {
$where = $this->implode_field_value($condition, ` AND `);
} else {
$where = $condition;
}
$sql = “DELETE FROM “.$this->table($table).” WHERE $where “.($limit ? “LIMIT $limit” : “);
return $this->query($sql, ($unbuffered ? `UNBUFFERED` : “));
}
function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {
$sql = $this->implode_field_value($data);
$cmd = $replace ? `REPLACE INTO` : `INSERT INTO`;
$table = $this->table($table);
$silent = $silent ? `SILENT` : “;
$return = $this->query(“$cmd $table SET $sql”, $silent);
return $return_insert_id ? $this->insert_id() : $return;
}
function update($table, $data, $condition, $unbuffered = false, $low_priority = false) {
$sql = $this->implode_field_value($data);
$cmd = “UPDATE “.($low_priority ? `LOW_PRIORITY` : “);
$table = $this->table($table);
$where = “;
if(empty($condition)) {
$where = `1`;
} elseif(is_array($condition)) {
$where = $this->implode_field_value($condition, ` AND `);
} else {
$where = $condition;
}
$res = $this->query(“$cmd $table SET $sql WHERE $where”, $unbuffered ? `UNBUFFERED` : “);
return $res;
}
function implode_field_value($array, $glue = `,`) {
$sql = $comma = “;
foreach ($array as $k => $v) {
$sql .= $comma.”`$k`=`$v`”;
$comma = $glue;
}
return $sql;
}
}
相關文章
- MySQL Amoeba讀寫分離MySql
- Amoeba for mysql讀寫分離MySql
- MySQL讀寫分離AtlasMySql
- 【Mysql】mysql-proxy讀寫分離MySql
- MySQL + Atlas --- 部署讀寫分離MySql
- Amoeba for MySQL讀寫分離配置MySql
- ProxySQL實現MySQL讀寫分離MySql
- MySQL 讀寫分離的好處MySql
- mysql優化之讀寫分離MySql優化
- 探究MySQL MGR的讀寫分離MySql
- Amoeba 實現 MySQL 讀寫分離MySql
- mysql讀寫分離Amoeba的部署MySql
- [PHP]Larval主從讀寫分離配置PHP
- MySQL cetus 中介軟體 讀寫分離MySql
- MYSQL 主從 + ATLAS 讀寫分離 搭建MySql
- 配置\清除 MySQL 主從 讀寫分離MySql
- Mysql之讀寫分離架構-AtlasMySql架構
- Mysql 高可用(MHA)-讀寫分離(Atlas)MySql
- MySQL主從複製讀寫分離MySql
- Amoeba+Mysql 實現讀寫分離MySql
- MySQL 讀寫分離介紹及搭建MySql
- mysql-proxy實現讀寫分離MySql
- mysql讀寫分離的最佳實踐MySql
- MySQL 官宣:支援讀寫分離了!!MySql
- docker+atlas+mysql實現讀寫分離DockerMySql
- MySQL 中讀寫分離資料延遲MySql
- mysql讀寫分離實戰準備一MySql
- haproxy+keepalived+mycat+mysql (讀寫分離)MySql
- MySQL主從複製與讀寫分離MySql
- [Mysql]主從複製和讀寫分離MySql
- Mysql讀寫分離方案-MySQL Proxy環境部署記錄MySql
- mysql-proxy+keepalived對mysql做讀寫分離MySql
- 搭建MySQL主從實現Django讀寫分離MySqlDjango
- Mysql-主從複製與讀寫分離MySql
- Mysql讀寫分離方案-Amoeba環境部署記錄MySql
- ProxySQL實現Mysql讀寫分離 - 部署手冊MySql
- MySQL 中介軟體Atlas 實現讀寫分離MySql
- LAMP(Linux+Apache+MySQL+PHP)(四)+Discuz+Redis+Mysql-proxy讀寫分離(centos7)LAMPLinuxApacheMySqlPHPRedisCentOS