thinkphp Distributed Database

Keywords: Database MySQL PDO

1. distributed data base What is it?

The distributed database of tp is mainly through this configuration:

DB_DEPLOY_TYPE'=> 1, //database deployment: 0 centralized (single server), 1 distributed (master-slave server)

2. What is the read-write separation between master and slave servers?

A master-slave database is a master database with n slave databases, while a slave database can only have one slave database. Written operations in master-slave databases need to use master databases, while read operations use slave databases. Data consistency is maintained between master and slave databases. The principle of database consistency is that when the main database data changes, the operation will be written to the main database log, while the log of the main database will be continuously read from the database and saved to its own log system, and then executed, so as to maintain the consistency between the master database and the slave database.

3. detailed explanation

I. Connection of a Single Database

When used, the connection configuration of a single database is very simple. We just need to configure the information in the configuration file.

  1. 'DB_TYPE' => 'mysql',  
  2. 'DB_HOST' => '192.168.5.102',  
  3. 'DB_NAME' => 'databasename',  
  4. 'DB_USER' => 'user',  
  5. 'DB_PWD' => 'password',  
  6. 'DB_PORT' => '3306',  
  7. 'DB_PREFIX' => 'onmpw_',  


Once the settings are complete, they can be used. By default, it's a single database connection.

II. Connection of Distributed Database

The connection of a single database is very simple. We will focus on the analysis of the connection of a distributed database.

  1. 'DB_TYPE' => 'mysql',  
  2. 'DB_HOST' => '192.168.5.191,192.168.5.88,192.168.5.103',  
  3. 'DB_NAME' => 'test,test,test',  
  4. 'DB_USER' => 'masteruser,slaveuser,slaveuser',  
  5. 'DB_PWD' => 'masterpass,slavepass,slavepass',  
  6. 'DB_PORT' => '3306',  
  7. 'DB_PREFIX' => '',  
  8. 'DB_DEPLOY_TYPE'        =>  1, //Database deployment: 0 centralized (single server), 1 distributed (master-slave server)
  9. 'DB_RW_SEPARATE'        =>  true,       //Does the database read and write separately? The master-slave mode is valid?
  10. 'DB_MASTER_NUM'         =>  1, //Number of primary servers after read-write separation
  11. 'DB_SLAVE_NO'           =>  '', //Specify slave server serial number


According to the above configuration, you can connect to the distributed database.

Let's look at the following options

'DB_HOST'

Distributed database, there are several servers to fill in several server addresses, each address is separated by commas. If it is a master-slave distribution, the front address is the address of the main database.

For the following usernames and passwords, as well as listening ports and so on, of course, there are a few to write a few. If the user name and password of each database are the same, you can write only one.

The code for the analysis of these options is as follows

  1. $_config['username']  =   explode(',',$this->config['username']);  
  2. $_config['password']  =   explode(',',$this->config['password']);  
  3. $_config['hostname']  =   explode(',',$this->config['hostname']);  
  4. $_config['hostport']   =   explode(',',$this->config['hostport']);  
  5. $_config['database']  =   explode(',',$this->config['database']);  
  6. $_config['dsn']      =   explode(',',$this->config['dsn']);  
  7. $_config['charset']   =   explode(',',$this->config['charset']);  


'DB_DEPLOY_TYPE'=>1

1 denotes distributed, 0 denotes centralized (that is, a single server).

The implementation of this option is in the class ThinkDbDirver

  1. protected function initConnect($master=true) {  
  2.     if(!empty($this->config['deploy']))  
  3.        //Using distributed databases
  4.        $this->_linkID = $this->multiConnect($master);  
  5.     else  
  6.        //Default single database
  7.        if ( !$this->_linkID ) $this->_linkID = $this->connect();  
  8. }  


$this - > config ['deploy'] denotes the configuration option of'DB_DEPLOY_TYPE'. The above configuration has been parsed before use, and the configuration items are in the $this - > config array. As for how to parse the configuration file, we will not introduce it here, but we can refer to the Think Db class if you are interested.

The $this - > multiConnect () function is used for distributed connections, and if the'DB_DEPLOY_TYPE'option is set to 1, the function executes. Otherwise, the $this - > connect () function is executed directly.

'DB_RW_SEPARATE'=>true

true denotes read-write separation; false denotes read-write separation.

It should be noted that the separation of reading and writing is based on master-slave database system. When this option is set to true, the main database writes and reads from the database.

  1. if($this->config['rw_separate']){  
  2.       //Separation of reading and writing is adopted in master-slave mode.
  3.       if($master)  
  4.           //Primary server write
  5.           $r  =   $m;  
  6.       else{  
  7.           if(is_numeric($this->config['slave_no'])) {//Specify server reads
  8.               $r = $this->config['slave_no'];  
  9.           }else{  
  10.                //Read operation connection slave server
  11.               $r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1));   //Each randomly connected database
  12.           }  
  13.             }  
  14. }else{  
  15.       //Read-write operations do not differentiate between servers.
  16.       $r = floor(mt_rand(0,count($_config['hostname'])-1));   //Each randomly connected database
  17. }  


When $this - > config ['rw_separate'] is true, read-write separation is used, while read-write separation is not used for false. Why must the separation of reading and writing be principal and subordinate? Because slave servers cannot write but read, if data is written to slave servers, the data cannot be synchronized. This will result in inconsistent data. So, if our system is master-slave, we must adopt read-write separation. That is to say, the DB_RW_SEPARATE option must be configured as true.

'DB_MASTER_NUM'=>1

The number after this option represents the number of primary servers after read-write separation. Therefore, this option is also used for master-slave database systems.

The following code is to select the primary server.

$m  =  floor(mt_rand(0,$this->config['master_num']-1));

Select the core code read from server when reading master-slave database

$r = floor (mt_rand ($this - > config ['master_num'], count ($_config ['hostname']) - 1); // each randomly connected database

Where $this - > config ['master_num'] denotes the number of primary servers.

'DB_SLAVE_NO'=> ''

Specifies the serial number of the slave server for reading data. If not, the number of books from servers is calculated according to the number of primary servers, and then one of them is randomly selected for reading.

If (is_numeric ($this - > config ['slave_no']){// Specify server read
   $r = $this->config['slave_no'];
}else{
// Read Operations Connect Slave Servers
$r = floor (mt_rand ($this - > config ['master_num'], count ($_config ['hostname']) - 1); // each randomly connected database
}

The above is a brief description of the implementation code for each option.

Let's look at the links below.

  1. if($m != $r ){  
  2.    $db_master  =  array(  
  3.       'username' =>  isset($_config['username'][$m])?$_config['username'][$m]:$_config['username'][0],  
  4.       'password'  =>  isset($_config['password'][$m])?$_config['password'][$m]:$_config['password'][0],  
  5.       'hostname'  =>  isset($_config['hostname'][$m])?$_config['hostname'][$m]:$_config['hostname'][0],  
  6.       'hostport'  =>  isset($_config['hostport'][$m])?$_config['hostport'][$m]:$_config['hostport'][0],  
  7.       'database'  =>  isset($_config['database'][$m])?$_config['database'][$m]:$_config['database'][0],  
  8.       'dsn'  =>  isset($_config['dsn'][$m])?$_config['dsn'][$m]:$_config['dsn'][0],  
  9.       'charset'  =>  isset($_config['charset'][$m])?$_config['charset'][$m]:$_config['charset'][0],  
  10.     );  
  11. }  
  12. $db_config = array(  
  13.    'username'  =>  isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],  
  14.     'password'  =>  isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],  
  15.     'hostname'  =>  isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],  
  16.     'hostport'  =>  isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],  
  17.      'database'  =>  isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],  
  18.      'dsn'  =>  isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],  
  19.      'charset'   =>  isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],  
  20. );  
  21. return $this->connect($db_config,$r,$r == $m ? false : $db_master);  


Looking at this, I think you should look at what $r and $m do when you introduce the code for each configuration option above.

Now let's look at $r == $m? False: $db_master. If the database is read and write inseparable, the value passed to the connect function is false if the read and write is a server. Or the value passed to connect is false if the master and slave are written separately. From the above code, we can see that if $r and $m are not equal, we will set $db_master. In fact, it is equivalent to a standby, if the selected $r server fails to connect, it will connect to $db_master.

The third parameter of the connect() function actually indicates whether to choose a standby connection when the $db_config server connection fails. false denotes no reconnection, and other values denote reconnection.

The core code is as follows

  1. try{  
  2.    if(empty($config['dsn'])) {  
  3.       $config['dsn']  =   $this->parseDsn($config);  
  4.    }  
  5.    if(version_compare(PHP_VERSION,'5.3.6','<=')){  
  6.        //Disable simulated preprocessing statements
  7.        $this->options[PDO::ATTR_EMULATE_PREPARES]  =   false;  
  8.    }  
  9.    $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$this->options);  
  10. }catch (\PDOException $e) {  
  11.    if($autoConnection){ //autoConnection is not false, but the default primary server.
  12.         trace($e->getMessage(),'','ERR');  
  13.             return $this->connect($autoConnection,$linkNum);  //If an exception occurs, reconnect using a recursive function.
  14.         }elseif($config['debug']){  
  15.             E($e->getMessage());  
  16.     }  
  17. }  


In this way, $r and $m will certainly not be the same for master-slave. Therefore, if the selected slave server fails when reading data, then the master server is standby and will read to the master server at last. It can ensure the timeliness of data reading.

Posted by geek_girl_2020 on Fri, 29 Mar 2019 22:57:28 -0700