Gorm 讀寫(xiě)分離

      網(wǎng)友投稿 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

      Gorm 讀寫(xiě)分離

      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)容。

      上一篇:表格中如何刪除文字內(nèi)容(表格怎么刪除文字內(nèi)容)
      下一篇:wps熱點(diǎn)怎么關(guān)?
      相關(guān)文章
      亚洲国产一区二区a毛片| 亚洲国产区男人本色| 亚洲黄色高清视频| 亚洲AV无码成H人在线观看| 亚洲无人区码一二三码区别图片| 亚洲国产成a人v在线| 亚洲AV无码国产精品麻豆天美 | 亚洲六月丁香六月婷婷色伊人| 久久亚洲AV成人无码国产| 亚洲高清在线视频| 亚洲AV无码专区在线播放中文 | 久久久久亚洲国产AV麻豆| 亚洲Aⅴ在线无码播放毛片一线天| 亚洲国产精品无码观看久久| 亚洲色偷偷综合亚洲av78| 亚洲精品无播放器在线播放| 亚洲成a人片在线不卡一二三区| 亚洲sm另类一区二区三区| 亚洲AV无码乱码在线观看性色扶| 亚洲国产精品丝袜在线观看| 国产av无码专区亚洲av果冻传媒| 亚洲日韩精品无码一区二区三区| 亚洲va无码手机在线电影| 日韩精品亚洲人成在线观看| 亚洲成综合人影院在院播放| 国产成人精品日本亚洲专| 亚洲乱理伦片在线观看中字| 国产综合成人亚洲区| 亚洲国产日韩成人综合天堂 | 国产亚洲精品VA片在线播放| 亚洲中文字幕无码爆乳app| 色天使亚洲综合一区二区| 亚洲一区无码精品色| 亚洲国产成人精品无码区在线观看| 亚洲国产精品久久久久| 亚洲天堂一区二区三区四区| 亚洲色www永久网站| 亚洲va中文字幕无码| 亚洲精品白浆高清久久久久久| 亚洲专区先锋影音| 国产亚洲精aa在线看|