進入正題之前,首先來看下分布式數據庫出現的場景都有哪些:
- 單表數據量爆炸,千萬級、億級等,各種數據操作效率很低 。 關系型數據庫在大于一定數據量的情況下檢索性能會急劇下降。在面對互聯網海量數據情況時,所有數據都存于一張表,顯然會輕易超過數據庫表可承受的數據量閥值。這個單表可承受的數據量閥值,需根據數據庫和并發量的差異,通過實際測試獲得;
- 單機數據庫的瓶頸問題,處理不了高強度io?,F代企業程序的瓶頸問題是數據庫的瓶頸問題,所以數據庫只做存儲用,不再使用觸發器,事物;
- 不同業務對應不同業務數據庫,即使某個數據庫掛了,不影響其他數據庫對應的服務使用,服務高可用;
- 為了方便擴展,動態增加數據庫節點,保證擴展性好;
- 數據備份,數據最重要的嘛。
環境要求
- PHP7.1+,使用ThinkPHP6.0框架的話,運行環境要求PHP7.1+;
- 至少兩個服務,當然不是真的買兩臺服務器,推薦使用vagrant+virtualBox搭建本地虛擬服務
項目中數據庫配置文件修改,支持讀寫分離
數據訪問層支持分布式數據庫,包括讀寫分離,要啟用分布式數據庫,需要開啟數據庫配置文件中的deploy參數。在config文件夾下找到database.php文件
// 數據庫連接配置信息
'connections' => [
'mysql' => [
// 數據庫類型
'type' => Env::get('database.type', 'mysql'),
// 服務器地址
'hostname' => ['192.168.33.10', '188.180.0.228'],
// 數據庫名
'database' => "tp",
// 用戶名
'username' => "root",
// 密碼
'password' => '123456',
// 端口
'hostport' => Env::get('database.hostport', '3306'),
// 數據庫連接參數
'params' => [],
// 數據庫編碼默認采用utf8
'charset' => Env::get('database.charset', 'utf8'),
// 數據庫表前綴
'prefix' => Env::get('database.prefix', ''),
// 數據庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器)
'deploy' => 1,
// 數據庫讀寫是否分離 主從式有效
'rw_separate' => true,
// 開啟自動主庫讀取
'read_master' => false,
// 讀寫分離后 主服務器數量
'master_num' => 1,
// 指定從服務器序號
'slave_no' => '',
// 是否嚴格檢查字段是否存在
'fields_strict' => true,
// 是否需要斷線重連
'break_reconnect' => false,
// 監聽SQL
'trigger_sql' => true,
// 開啟字段緩存
'fields_cache' => false,
// 字段緩存路徑
'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR,
],
],
配置修改需要注意以下幾點
- 啟用分布式數據庫后,hostname參數是關鍵,hostname的個數決定了分布式數據庫的數量,默認情況下第一個地址就是主服務器。
- 如果主從服務器的下列連接參數一致,只需要設置一個即可,對于不同的參數,可以分別設置。切記要么相同,要么每個都設置。
連接參數 |
---|
username |
password |
hostport |
database |
dsn |
charset |
- 讀寫分離
- 默認的情況下讀寫不分離,也就是每臺服務器都可以進行讀寫操作,對于主從式數據庫而言,需要設置讀寫分離,修改這個參數就好了。
'rw_separate' => true,
在讀寫分離的情況下,默認第一個數據庫配置是主服務器的配置信息,負責寫入數據,如果設置了master_num參數,則可以支持多個主服務器寫入(每次隨機連接其中一個主服務器)。其它的地址都是從數據庫,負責讀取數據,數量不限制。每次連接從服務器并且進行讀取操作的時候,系統會隨機進行在從服務器中選擇。同一個數據庫連接的每次請求只會連接一次主服務器和從服務器,如果某次請求的從服務器連接不上,會自動切換到主服務器進行查詢操作。
如果不希望隨機讀取,或者某種情況下其它從服務器暫時不可用,還可以設置slave_no 指定固定服務器進行讀操作,slave_no指定的序號表示hostname中數據庫地址的序號,從0開始。
更詳細的配置可參考官方文檔。
主從同步
主從數據庫的數據同步工作不在框架實現,需要數據庫考慮自身的同步或者復制機制。
半自動復制插件腳本安裝
- 登錄MySQL執行腳本:
- 主庫:
install plugin rpl_semi_sync_master soname 'semisync_master.so';
- 從庫:
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
主從數據庫的my.cnf文件配置:
主庫:
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000 #此單位是毫秒
log-bin=mysql-bin #打開日志(主機需要打開)
server-id=1 #服務器id
log-bin-index=mysql-bin.index
sync_binlog=1
#給從機同步的庫,可以多個
binlog-do-db=tp #從庫的數據庫名稱
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
expire_logs_days=1
從庫:
rpl_semi_sync_slave_enabled=1
server-id=2 #服務器id
#要從主機同步的庫
replicate-do-db=tp #主庫的數據庫名
修改好之后,重新啟動主從數據庫的服務
主庫授權同步從庫的賬戶
GRANT REPLICATION SLAVE ON *.* TO 'root'@'188.180.0.228' IDENTIFIED BY 'XXXXXX'; #主數據庫授權同步賬戶
FLUSH PRIVILEGES; #刷新權限
SHOW MASTER STATUS; #查看主服務狀態
配置從庫連接主庫服務器的參數
CHANGE MASTER TO MASTER_HOST='192.168.33.10',MASTER_USER='root', MASTER_PASSWORD='XXXXXX',MASTER_LOG_FILE='mysql-bin.000008',MASTER_LOG_POS=1528;
start slave; #開啟SLAVE同步
show slave status \G; #查看下slave狀態
注意:MASTER_LOG_FILE=’mysql-bin.000008’,MASTER_LOG_POS=1528是通過前面的主數據庫SHOW MASTER STATUS;得到
[圖片上傳失敗...(image-8e2326-1576826636354)]
當Slave_IO_Running和Slave_SQL_Running都為Yes,說明主從復制配置成功,如果有必要停止或者撤銷同步賬號的權限,還可操作。
stop slave; #停止SLAVE同步
GRANT REPLICATION SLAVE ON *.* TO 'root'@'188.180.0.228' IDENTIFIED BY 'XXXXXX';# 撤銷已經賦予給MySQL同步賬戶的權限
實際操作
1.先插入5條數據
public function add()
{
$data = [];
for ($i = 0; $i < 5; $i++) {
array_push($data, ['name' => 'name_' . ($i+1)]);
}
$res = Db::table('user')->insertAll($data);
echo '插入成功條數:' . $res;
}
瀏覽器訪問:
如上圖所示,插入數據連接的是主數據庫。
主從數據庫插入數據如下:
- 執行查詢和更新操作
public function list()
{
$res = Db::table('user')->where('id','=',1)->find();
$row = Db::table('user')->where('id','=',$res['id'])->update(['name' => 'name_9527']);
echo $row;
}
如上圖所示:查詢連接的是從庫,而更新操作連接的主庫。
數據同步結果:
以上就是數據庫讀寫分離、主從同步的框架內文件配置、數據庫服務器文件配置和代碼示例。