云數(shù)據(jù)庫(kù)服務(wù)2019年度大盤(pán)點(diǎn)">華為云數(shù)據(jù)庫(kù)服務(wù)2019年度大盤(pán)點(diǎn)
1609
2025-04-03
Gorm 讀寫(xiě)分離
寫(xiě)在前面
在gorm v2版本中,我們可以看到已經(jīng)支持讀寫(xiě)分離,那讀寫(xiě)分離是基于主從復(fù)制的,所以我們要先配置mysql的主從復(fù)制
1. 為什么需要主從復(fù)制?
在業(yè)務(wù)復(fù)雜的系統(tǒng)中,有這么一個(gè)情景:如果有一句sql語(yǔ)句需要鎖表,導(dǎo)致暫時(shí)不能使用讀的服務(wù),那么就很影響運(yùn)行中的業(yè)務(wù)。使用主從復(fù)制,讓主庫(kù)負(fù)責(zé)寫(xiě),從庫(kù)負(fù)責(zé)讀,這樣,即使主庫(kù)出現(xiàn)了鎖表的情景,通過(guò)讀從庫(kù)也可以保證業(yè)務(wù)的正常運(yùn)作。
做數(shù)據(jù)的熱備
業(yè)務(wù)量越來(lái)越大,I/O訪問(wèn)頻率過(guò)高,單機(jī)無(wú)法滿足,此時(shí)做多庫(kù)的存儲(chǔ),降低磁盤(pán)I/O訪問(wèn)的頻率,提高單個(gè)機(jī)器的I/O性能。
2. 什么是主從復(fù)制?
MySQL 主從復(fù)制是指數(shù)據(jù)可以從一個(gè)MySQL數(shù)據(jù)庫(kù)服務(wù)器主節(jié)點(diǎn)復(fù)制到一個(gè)或多個(gè)從節(jié)點(diǎn)。
MySQL 默認(rèn)采用異步復(fù)制方式,這樣從節(jié)點(diǎn)不用一直訪問(wèn)主服務(wù)器來(lái)更新自己的數(shù)據(jù),數(shù)據(jù)的更新可以在遠(yuǎn)程連接上進(jìn)行,從節(jié)點(diǎn)可以復(fù)制主數(shù)據(jù)庫(kù)中所有的數(shù)據(jù)庫(kù)或者特定的數(shù)據(jù)庫(kù),或者特定的表。
3. 原理
master服務(wù)器將數(shù)據(jù)的改變記錄二進(jìn)制binlog日志,當(dāng)master上的數(shù)據(jù)發(fā)生改變時(shí),則將其改變寫(xiě)入二進(jìn)制日志中。
slave服務(wù)器會(huì)在一定時(shí)間間隔內(nèi)對(duì)master二進(jìn)制日志進(jìn)行探測(cè)其是否發(fā)生改變,如果發(fā)生改變,則開(kāi)始一個(gè)I/OThread請(qǐng)求master二進(jìn)制事件。
同時(shí)主節(jié)點(diǎn)為每個(gè)I/O線程啟動(dòng)一個(gè)dump線程,用于向其發(fā)送二進(jìn)制事件,并保存至從節(jié)點(diǎn)本地的中繼日志中。
從節(jié)點(diǎn)將啟動(dòng)SQL線程從中繼日志中讀取二進(jìn)制日志,在本地重放,使得其數(shù)據(jù)和主節(jié)點(diǎn)的保持一致。
最后I/OThread和SQLThread將進(jìn)入睡眠狀態(tài),等待下一次被喚醒。
總結(jié):
從庫(kù)生成兩個(gè)線程,一個(gè)I/O線程,一個(gè)SQL線程,一定要保證這兩個(gè)是開(kāi)啟的狀態(tài)。
I/O線程會(huì)去請(qǐng)求主庫(kù)的binlog,并將得到的binlog寫(xiě)到本地的relay-log(中繼日志)文件中。
主庫(kù)會(huì)生成一個(gè)log dump線程,用來(lái)給從庫(kù)I/O線程傳binlog。
SQL線程,會(huì)讀取relay log文件中的日志,并解析成sql語(yǔ)句逐一執(zhí)行。
4. 配置
4.1 準(zhǔn)備兩臺(tái)服務(wù)器(已經(jīng)安裝了MySQL)
master:xxx slave:xxx
4.2 修改配置
兩臺(tái)機(jī)子同時(shí)創(chuàng)建一個(gè)同名的數(shù)據(jù)庫(kù)。
create database test_db charset=utf8mb4;
4.2.1 master 主服務(wù)器
找到 my.cnf
sudo vim /etc/mysql/my.cnf
添加這些信息
#在mysqld模塊中添加如下配置信息 [mysqld] log-bin=master-bin #二進(jìn)制文件名稱 binlog-format=ROW #二進(jìn)制日志格式,有row、statement、mixed三種格式,row指的是把改變的內(nèi)容復(fù)制過(guò)去,而不是把命令在從服務(wù)器上執(zhí)行一遍,statement指的是在主服務(wù)器上執(zhí)行的SQL語(yǔ)句,在從服務(wù)器上執(zhí)行同樣的語(yǔ)句。MySQL默認(rèn)采用基于語(yǔ)句的復(fù)制,效率比較高。mixed指的是默認(rèn)采用基于語(yǔ)句的復(fù)制,一旦發(fā)現(xiàn)基于語(yǔ)句的無(wú)法精確的復(fù)制時(shí),就會(huì)采用基于行的復(fù)制。 server-id=1 # 要求各個(gè)服務(wù)器的id必須不一樣 binlog-do-db=test_db # 同步的數(shù)據(jù)庫(kù)名稱
配置從服務(wù)器登錄主服務(wù)器的賬號(hào)授權(quán)
grant replication slave on *.* to 'root'@'%' identified by 'root';
刷新權(quán)限
flush privileges;
重啟master服務(wù)器
service mysql restart
在mysql中查看master的status
show master stataus
4.2.2 slave 從服務(wù)器
找到 my.cnf文件
配置信息
這個(gè)server-id記得一定要和主服務(wù)器的不一樣!
重啟mysql服務(wù)
service mysqld restart
連接主服務(wù)器
change master to master_host='主服務(wù)地址',master_user='root',master_password='root',master_port=3306,master_log_file='master-bin.000001',master_log_pos=154;
這個(gè)master_log_file就是上面那個(gè)show master stataus的信息。
這個(gè)master_log_pos就是上面那個(gè)show master stataus的信息。
啟動(dòng)slave
start slave
查看slave
show slave status \G(注意沒(méi)有分號(hào))
當(dāng)我們看著這兩個(gè)都是YES的時(shí)候就可以了,注意不能是其他CONNECTING
停止slave
stop slave
4.2.3 驗(yàn)證
master 主服務(wù)器
slave 子服務(wù)器
兩個(gè)服務(wù)器都是空的狀態(tài)
那首先我們可以先在master節(jié)點(diǎn)上進(jìn)行插入一條語(yǔ)句
然后在slave節(jié)點(diǎn)上查看
于是我們看到已經(jīng)實(shí)現(xiàn)主從復(fù)制了。
5. 設(shè)置連接mysql
構(gòu)建mysql連接集群
var Db1Dsn = "root:root@tcp(localhost:3306)/db_ex1?charset=utf8&parseTime=true" var Db2Dsn = "root:root@tcp(localhost:3306)/db_ex2?charset=utf8&parseTime=true" var Db3Dsn = "root:root@tcp(localhost:3306)/db_ex3?charset=utf8&parseTime=true" var Db4Dsn = "root:root@tcp(localhost:3306)/db_ex4?charset=utf8&parseTime=true"
主數(shù)據(jù)庫(kù)連接
var DB, _ = gorm.Open(mysql.Open(Db1Dsn), &gorm.Config{} // `db1` 作為 sources(DB 的默認(rèn)連接)
定義數(shù)據(jù)庫(kù)模型
type User struct { // 用戶 Name string Sex string } type Address struct { // 地址 Local string Number string } type Product struct { // 產(chǎn)品 Title string ImgUrl string } type UserStruct struct { // 用戶 ID uint Age uint }
6. mysql數(shù)據(jù)庫(kù)的主從配置(讀為主,寫(xiě)為從)
注意:一定要在這步驟之前確保各個(gè)數(shù)據(jù)庫(kù)之間都已經(jīng)達(dá)到主從復(fù)制的狀態(tài)
數(shù)據(jù)庫(kù)的遷移連接
_ = DB.Set("gorm:table_options", "charset=utf8mb4"). AutoMigrate(&User{},&Address{},&Product{}, &Pet{}, &Order{}, &UserStruct)
配置數(shù)據(jù)庫(kù)的讀寫(xiě)(哪個(gè)數(shù)據(jù)庫(kù)進(jìn)行讀,哪個(gè)數(shù)據(jù)庫(kù)進(jìn)行寫(xiě))
_ = DB.Use(dbresolver. Register(dbresolver.Config{ // `db2` 作為 sources,`db3`、`db4` 作為 replicas Sources: []gorm.Dialector{mysql.Open(Db2Dsn)}, Replicas: []gorm.Dialector{mysql.Open(Db3Dsn), mysql.Open(Db4Dsn)}, Policy: dbresolver.RandomPolicy{}, // sources/replicas 負(fù)載均衡策略 }). Register(dbresolver.Config{ // `db1` 作為 sources(DB 的默認(rèn)連接),對(duì)于 `User`、`Address` 使用 `db5` 作為 replicas Replicas: []gorm.Dialector{mysql.Open(Db5Dsn)}, }, &User{}, &Address{}). Register(dbresolver.Config{ // `db6`、`db7` 作為 sources,對(duì)于 `orders`、`Product` 使用 `db8` 作為 replicas Sources: []gorm.Dialector{mysql.Open(Db6Dsn), mysql.Open(Db7Dsn)}, Replicas: []gorm.Dialector{mysql.Open(Db8Dsn)}, }, "orders", &Product{}))
sources:主源,主要用來(lái)進(jìn)行寫(xiě)操作。
replicas:次源,主要用來(lái)進(jìn)行讀操作。
7. 讀寫(xiě)驗(yàn)證
這個(gè)我們配置的時(shí)候就是配置userStruct是通過(guò)db3/db4進(jìn)行讀取,db2進(jìn)行寫(xiě)的
var userStruct UserStruct // Global Resolver 示例 db.Model(&UserStruct{}).Find(&userStruct,1) // replicas `db3`/`db4` userStruct.Age=24 db.Save(&userStruct) // sources `db2`
db4
db3
db2
8. 總結(jié)
當(dāng)我們是讀操作的時(shí)候,grom會(huì)把我們的讀操作作用于replicas中。
當(dāng)我們涉及寫(xiě)操作,比如create,update之類(lèi)的會(huì)從source中操作。
如果沒(méi)有指定特殊的表進(jìn)行特殊的操作的話,是默認(rèn)在沒(méi)有特殊規(guī)定的數(shù)據(jù)庫(kù)進(jìn)行讀或是寫(xiě),比如上面例子的userStruct是在db2和db3/db4這三個(gè)數(shù)據(jù)庫(kù)進(jìn)行操作,而不是在其他固定寫(xiě)其他表的db5,db8和db6/db7數(shù)據(jù)庫(kù)。
MySQL 數(shù)據(jù)庫(kù)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。