MySQL連線池與超時設定

2021-10-05 22:43:42 字數 3579 閱讀 3076

func setmaxidleconns(n int){} 

func setmaxopenconns(n int){}

寫乙個網路後端, 啟動資料庫, 連線資料庫, 開始之前配置你的資料庫. 流量一大, 各種問題都出來了, 你開始認識到mysql是一整套系統, 一套需要配置的系統.以上兩個函式是什麼? 什麼是mysql連線,什麼是連線池. 我應該怎麼配置? 等你知道這些東西是什麼, 怎麼工作的. 你立刻就能理解應該怎麼去配置他們.

現在你是乙個go程式, 你需要用資料庫, 你叮一下資料庫, 告訴資料庫我想查資料庫. 然後你開始查. 你叮的哪一下就產生了乙個連線. 你使用哪個連線來查詢. 但是, 每查一次就叮一次, 這樣是不是不合理, 很浪費時間. 事實上(預設引數下)mysql會把你那個連線儲存8小時, 也就是說8小時內, 你拿著這個連線去查數都是可以的. 如果超過8小時沒人用這個鏈結, mysql就會關掉這個鏈結.‌

你可以把那個連線存起來, 或者存5個連線, 想用的時候, 就從裡面拿乙個出來用一下, 這就構成了連線池. 現在我們可以開始解釋上面兩個函式是幹什麼的了:setmaxopenconns: 我允許你最多開這麼多個連線setmaxidleconns: 連線池裡最多有這麼多連線

假設這個時刻下現在有4個連線查詢完畢, 那這些連線去哪兒呢? 一部分去了連線池, 連線池放不下的, 多餘的部分就會直接關閉. 那麼maxopenconns呢? 如果你的maxopen設定成3, 那根本就不會有4個連線同時返回. 因為你最多只能開3個連線, 第四個起就需要排隊等.‌

多說一句, 所謂的排隊等, 本質上就是先(在乙個map裡)登記一下, 然後守著乙個chanel等. 等正在執行的請求結束了, 開始收尾了, 再去map裡檢視這個請求, 並往chanel塞上乙個連線.

wait_timeout : 乙個連線會有idle以及open兩種狀態, 那麼乙個長期處於idle的鏈結, mysql伺服器就會想要關掉它. 這個"長期"指的是多久? 就是這個引數指定的時長

我多說一句, 網上有人喜歡提interactive_timeout的概念, 這個引數對於你後端鏈結毫無作用, 什麼是interactive, 是你拿著鍵盤在mysql命令列下敲select, 這個叫interactive

//調整mysql資料庫設定

mysql > set global wait_timeout = 1

mysql > select @@global.wait_timeout

//伺服器: $goroot/src/database/sql/sql.go

func(db* db)query()

packets.go:122: closing bad idle connection: eof

packets.go:36: unexpected eof

panic: invalid connection

而上面的panic是我**中的:rows,err := db.query(), 也就是說在使用乙個被伺服器斷開的鏈結的情況下, 會報錯invalid connection , 至此, 我們已經知道了, 我們遇到的invalid connection到底是因為什麼而出現的, 也知到"無效鏈結",到底是什麼東西無效了

setconnmaxlifetime:如果是自己斷開的鏈結 setconnmaxlifetime是指你的go程式自己斷開鏈結, 需要多久. 我們嘗試一下這種情況下會發生什麼. 首先我們知道,在預設表現下, 你只要db := sql.open()就能獲得乙個連線, 快取起來,然後下次查詢的時候用起來. 就像下面一樣:

numfree = 0       # 這是你open的時候, 剛開資料庫, 還沒有可用連線 retry = 0             # 你準備開始查詢了, 三次重試, 這是第一次 numfree = 1       # 誒? 你發現你有乙個快取的連線, 直接拿來用
現在我們改一改, 把setconnmaxlifetime設定成1, 然後再睡10秒, 這樣你通過open快取的連線就無效了, 這樣會發生什麼?

db.err := sql.open()

db.setconnmaxlifetime(1)

time.sleep(10 * time.second)

results,err := db.query()

numfree = 0            # open快取乙個 retry = 0                   # 開始查詢 numfree = 0             # 超時, 無可用連線物件 here id = 239611      # 正確的輸出
雖然已經超時了, 但是我們的服務端正確識別了已經被關閉的鏈結(畢竟也是你自己關的嘛), 在沒有快取連線的情況下, 服務端建立了乙個新鏈結, 並使用起來, 沒有報錯

如果調整的是maxopen, 假設我們令它為1, 我們這個程式一次就只能發起乙個資料庫請求. 那也就是說如果我們併發的兩個資料庫請求, 第二個必然會等待. 會發生什麼呢?

// $goroot/database/sql/sql.go

dc, err := db.conn(ctx, strategy)

time.sleep(10 * time.second)

// main.go 我的程式

db.setmaxopenconns(1)

go db.query()

db.query()

select{}

這種情況下, 兩個查詢裡必然有乙個會先拿到鏈結物件, 並進入sleep, 那麼另乙個就會一直等到第乙個結束再拿到鏈結物件. 結果一切正常, 除了等待的時間長了一點以外, 沒有任何超時或者報錯的跡象

// 超時時間非常苛刻, 設定成1ms

read := "&readtimeout=1ms"

source := "user:password@tcp/localhost?root" + read

db,err = gorm.open("mysql", source)

packets.go:36: read tcp 127.0.0.1:64897->127.0.0.1:3306: i/o timeout packets.go:36: read tcp 127.0.0.1:64897->127.0.0.1:3306: i/o timeout packets.go:36: read tcp 127.0.0.1:64897->127.0.0.1:3306: i/o timeout
出現了因為沒有及時讀取到想要的資料, 而產生的i/o timeout報錯‌

讓你的go程式自己結束鏈結, 不要讓伺服器終端鏈結, 因為你自己中斷鏈結至少是安全的. 令: setconnmaxlifetime < wait_timeout‌

假設你的wait_timeout是8小時, 那麼你的鏈結起步就能存活8小時(從頭到尾idle), ,那麼你就設定setconnmaxlifetime為7小時, 那你就一定能在mysql中斷之前, 自己先中斷了, 安全的不行

連線池鏈結超時

資料庫連線池中的connection在八小時內沒有被用到,則會自動斷開連線,那麼怎麼處理資料庫連線超時的問題?我的 public class connectionfacory public static synchronized connectionfacorygetinstance string ...

mysql連線池 順序 Mysql 連線池

通常,如果我們的服務涉及到mysql的操作,當乙個新的請求進來的時候,可以先連線mysql,使用完之後再斷開連線即可。但這樣做有個弊端,當請求量巨大時,會在瞬間有大量的資料庫連線與斷開操作,這是非常影響 mysql 效能的做法。此時,我們就需要使用mysql連線池。在 python 服務中使用 my...

Proxool連線池設定

proxool連線池是sourceforge下的乙個開源專案,這個專案提供乙個健壯 易用的連線池,最為關鍵的是這個連線池提供監控的功能,方便易用,便於發現連線洩漏的情況。開源專案位址是 配置連線池比較的簡單 2 配置資料來源 在web info下建立檔案 proxool.xml,檔案內容如下 dev...