進(jìn)入正題之前势决,首先來(lái)看下分布式數(shù)據(jù)庫(kù)出現(xiàn)的場(chǎng)景都有哪些:
- 單表數(shù)據(jù)量爆炸阻塑,千萬(wàn)級(jí)、億級(jí)等果复,各種數(shù)據(jù)操作效率很低 陈莽。 關(guān)系型數(shù)據(jù)庫(kù)在大于一定數(shù)據(jù)量的情況下檢索性能會(huì)急劇下降。在面對(duì)互聯(lián)網(wǎng)海量數(shù)據(jù)情況時(shí)虽抄,所有數(shù)據(jù)都存于一張表走搁,顯然會(huì)輕易超過數(shù)據(jù)庫(kù)表可承受的數(shù)據(jù)量閥值。這個(gè)單表可承受的數(shù)據(jù)量閥值迈窟,需根據(jù)數(shù)據(jù)庫(kù)和并發(fā)量的差異私植,通過實(shí)際測(cè)試獲得;
- 單機(jī)數(shù)據(jù)庫(kù)的瓶頸問題,處理不了高強(qiáng)度io〕岛ǎ現(xiàn)代企業(yè)程序的瓶頸問題是數(shù)據(jù)庫(kù)的瓶頸問題曲稼,所以數(shù)據(jù)庫(kù)只做存儲(chǔ)用索绪,不再使用觸發(fā)器,事物;
- 不同業(yè)務(wù)對(duì)應(yīng)不同業(yè)務(wù)數(shù)據(jù)庫(kù)躯肌,即使某個(gè)數(shù)據(jù)庫(kù)掛了者春,不影響其他數(shù)據(jù)庫(kù)對(duì)應(yīng)的服務(wù)使用,服務(wù)高可用;
- 為了方便擴(kuò)展清女,動(dòng)態(tài)增加數(shù)據(jù)庫(kù)節(jié)點(diǎn)钱烟,保證擴(kuò)展性好;
- 數(shù)據(jù)備份,數(shù)據(jù)最重要的嘛嫡丙。
環(huán)境要求
- PHP7.1+,使用ThinkPHP6.0框架的話拴袭,運(yùn)行環(huán)境要求PHP7.1+;
- 至少兩個(gè)服務(wù)曙博,當(dāng)然不是真的買兩臺(tái)服務(wù)器拥刻,推薦使用vagrant+virtualBox搭建本地虛擬服務(wù)
項(xiàng)目中數(shù)據(jù)庫(kù)配置文件修改,支持讀寫分離
數(shù)據(jù)訪問層支持分布式數(shù)據(jù)庫(kù)父泳,包括讀寫分離般哼,要啟用分布式數(shù)據(jù)庫(kù),需要開啟數(shù)據(jù)庫(kù)配置文件中的deploy參數(shù)惠窄。在config文件夾下找到database.php文件
// 數(shù)據(jù)庫(kù)連接配置信息
'connections' => [
'mysql' => [
// 數(shù)據(jù)庫(kù)類型
'type' => Env::get('database.type', 'mysql'),
// 服務(wù)器地址
'hostname' => ['192.168.33.10', '188.180.0.228'],
// 數(shù)據(jù)庫(kù)名
'database' => "tp",
// 用戶名
'username' => "root",
// 密碼
'password' => '123456',
// 端口
'hostport' => Env::get('database.hostport', '3306'),
// 數(shù)據(jù)庫(kù)連接參數(shù)
'params' => [],
// 數(shù)據(jù)庫(kù)編碼默認(rèn)采用utf8
'charset' => Env::get('database.charset', 'utf8'),
// 數(shù)據(jù)庫(kù)表前綴
'prefix' => Env::get('database.prefix', ''),
// 數(shù)據(jù)庫(kù)部署方式:0 集中式(單一服務(wù)器),1 分布式(主從服務(wù)器)
'deploy' => 1,
// 數(shù)據(jù)庫(kù)讀寫是否分離 主從式有效
'rw_separate' => true,
// 開啟自動(dòng)主庫(kù)讀取
'read_master' => false,
// 讀寫分離后 主服務(wù)器數(shù)量
'master_num' => 1,
// 指定從服務(wù)器序號(hào)
'slave_no' => '',
// 是否嚴(yán)格檢查字段是否存在
'fields_strict' => true,
// 是否需要斷線重連
'break_reconnect' => false,
// 監(jiān)聽SQL
'trigger_sql' => true,
// 開啟字段緩存
'fields_cache' => false,
// 字段緩存路徑
'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR,
],
],
配置修改需要注意以下幾點(diǎn)
- 啟用分布式數(shù)據(jù)庫(kù)后蒸眠,hostname參數(shù)是關(guān)鍵,hostname的個(gè)數(shù)決定了分布式數(shù)據(jù)庫(kù)的數(shù)量杆融,默認(rèn)情況下第一個(gè)地址就是主服務(wù)器楞卡。
- 如果主從服務(wù)器的下列連接參數(shù)一致,只需要設(shè)置一個(gè)即可脾歇,對(duì)于不同的參數(shù)蒋腮,可以分別設(shè)置。切記要么相同藕各,要么每個(gè)都設(shè)置池摧。
連接參數(shù) |
---|
username |
password |
hostport |
database |
dsn |
charset |
- 讀寫分離
- 默認(rèn)的情況下讀寫不分離,也就是每臺(tái)服務(wù)器都可以進(jìn)行讀寫操作激况,對(duì)于主從式數(shù)據(jù)庫(kù)而言险绘,需要設(shè)置讀寫分離,修改這個(gè)參數(shù)就好了誉碴。
'rw_separate' => true,
在讀寫分離的情況下宦棺,默認(rèn)第一個(gè)數(shù)據(jù)庫(kù)配置是主服務(wù)器的配置信息,負(fù)責(zé)寫入數(shù)據(jù)黔帕,如果設(shè)置了master_num參數(shù)代咸,則可以支持多個(gè)主服務(wù)器寫入(每次隨機(jī)連接其中一個(gè)主服務(wù)器)。其它的地址都是從數(shù)據(jù)庫(kù)成黄,負(fù)責(zé)讀取數(shù)據(jù)呐芥,數(shù)量不限制逻杖。每次連接從服務(wù)器并且進(jìn)行讀取操作的時(shí)候,系統(tǒng)會(huì)隨機(jī)進(jìn)行在從服務(wù)器中選擇思瘟。同一個(gè)數(shù)據(jù)庫(kù)連接的每次請(qǐng)求只會(huì)連接一次主服務(wù)器和從服務(wù)器荸百,如果某次請(qǐng)求的從服務(wù)器連接不上,會(huì)自動(dòng)切換到主服務(wù)器進(jìn)行查詢操作滨攻。
如果不希望隨機(jī)讀取够话,或者某種情況下其它從服務(wù)器暫時(shí)不可用,還可以設(shè)置slave_no 指定固定服務(wù)器進(jìn)行讀操作光绕,slave_no指定的序號(hào)表示hostname中數(shù)據(jù)庫(kù)地址的序號(hào)女嘲,從0開始。
更詳細(xì)的配置可參考官方文檔诞帐。
主從同步
主從數(shù)據(jù)庫(kù)的數(shù)據(jù)同步工作不在框架實(shí)現(xiàn)欣尼,需要數(shù)據(jù)庫(kù)考慮自身的同步或者復(fù)制機(jī)制。
半自動(dòng)復(fù)制插件腳本安裝
- 登錄MySQL執(zhí)行腳本:
- 主庫(kù):
install plugin rpl_semi_sync_master soname 'semisync_master.so';
- 從庫(kù):
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
主從數(shù)據(jù)庫(kù)的my.cnf文件配置:
主庫(kù):
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000 #此單位是毫秒
log-bin=mysql-bin #打開日志(主機(jī)需要打開)
server-id=1 #服務(wù)器id
log-bin-index=mysql-bin.index
sync_binlog=1
#給從機(jī)同步的庫(kù)停蕉,可以多個(gè)
binlog-do-db=tp #從庫(kù)的數(shù)據(jù)庫(kù)名稱
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
expire_logs_days=1
從庫(kù):
rpl_semi_sync_slave_enabled=1
server-id=2 #服務(wù)器id
#要從主機(jī)同步的庫(kù)
replicate-do-db=tp #主庫(kù)的數(shù)據(jù)庫(kù)名
修改好之后愕鼓,重新啟動(dòng)主從數(shù)據(jù)庫(kù)的服務(wù)
主庫(kù)授權(quán)同步從庫(kù)的賬戶
GRANT REPLICATION SLAVE ON *.* TO 'root'@'188.180.0.228' IDENTIFIED BY 'XXXXXX'; #主數(shù)據(jù)庫(kù)授權(quán)同步賬戶
FLUSH PRIVILEGES; #刷新權(quán)限
SHOW MASTER STATUS; #查看主服務(wù)狀態(tài)
配置從庫(kù)連接主庫(kù)服務(wù)器的參數(shù)
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狀態(tài)
注意:MASTER_LOG_FILE=’mysql-bin.000008’,MASTER_LOG_POS=1528是通過前面的主數(shù)據(jù)庫(kù)SHOW MASTER STATUS;得到
[圖片上傳失敗...(image-8e2326-1576826636354)]
當(dāng)Slave_IO_Running和Slave_SQL_Running都為Yes,說(shuō)明主從復(fù)制配置成功慧起,如果有必要停止或者撤銷同步賬號(hào)的權(quán)限菇晃,還可操作。
stop slave; #停止SLAVE同步
GRANT REPLICATION SLAVE ON *.* TO 'root'@'188.180.0.228' IDENTIFIED BY 'XXXXXX';# 撤銷已經(jīng)賦予給MySQL同步賬戶的權(quán)限
實(shí)際操作
1.先插入5條數(shù)據(jù)
public function add()
{
$data = [];
for ($i = 0; $i < 5; $i++) {
array_push($data, ['name' => 'name_' . ($i+1)]);
}
$res = Db::table('user')->insertAll($data);
echo '插入成功條數(shù):' . $res;
}
瀏覽器訪問:
如上圖所示完慧,插入數(shù)據(jù)連接的是主數(shù)據(jù)庫(kù)谋旦。
主從數(shù)據(jù)庫(kù)插入數(shù)據(jù)如下:
- 執(zhí)行查詢和更新操作
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;
}
如上圖所示:查詢連接的是從庫(kù)剩失,而更新操作連接的主庫(kù)屈尼。
數(shù)據(jù)同步結(jié)果:
以上就是數(shù)據(jù)庫(kù)讀寫分離、主從同步的框架內(nèi)文件配置拴孤、數(shù)據(jù)庫(kù)服務(wù)器文件配置和代碼示例脾歧。