開源go語言數(shù)據(jù)庫連接池 gorm數(shù)據(jù)庫連接池

如何在go語言中使用redis連接池

1.在創(chuàng)建連接池之后,起一個(gè) go routine,每隔一段 idleTime 發(fā)送一個(gè) PING 到 Redis server。其中,idleTime 略小于 Redis server 的 timeout 配置。

專注于為中小企業(yè)提供做網(wǎng)站、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)尋甸免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了數(shù)千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

2.連接池初始化部分代碼如下:

p, err := pool.New("tcp", u.Host, concurrency) errHndlr(err) go func() { for { p.Cmd("PING") time.Sleep(idelTime * time.Second) } }()

3.使用 redis 傳輸數(shù)據(jù)部分代碼如下:

func redisDo(p *pool.Pool, cmd string, args ...interface{}) (reply *redis.Resp, err error) { reply = p.Cmd(cmd, args...) if err = reply.Err; err != nil { if err != io.EOF { Fatal.Println("redis", cmd, args, "err is", err) } } return }

4.其中,Radix.v2 連接池內(nèi)部進(jìn)行了連接池內(nèi)連接的獲取和放回,代碼如下:

// Cmd automatically gets one client from the pool, executes the given command // (returning its result), and puts the client back in the pool func (p *Pool) Cmd(cmd string, args ...interface{}) *redis.Resp { c, err := p.Get() if err != nil { return redis.NewResp(err) } defer p.Put(c) return c.Cmd(cmd, args...) }

這樣,就有了系統(tǒng) keep alive 的機(jī)制,不會(huì)出現(xiàn) time out 的連接了,從 redis 連接池里面取出的連接都是可用的連接了??此坪?jiǎn)單的代碼,卻完美的解決了連接池里面超時(shí)連接的問題。同時(shí),就算 Redis server 重啟等情況,也能保證連接自動(dòng)重連。

golang配制高性能sql.DB

有很多教程是關(guān)于Go的sql.DB類型和如何使用它來執(zhí)行SQL數(shù)據(jù)庫查詢的。但大多數(shù)內(nèi)容都沒有講述 SetMaxOpenConns() , SetMaxIdleConns() 和 SetConnMaxLifetime()方法, 您可以使用它們來配置sql.DB的行為并改變其性能。

轉(zhuǎn)自:

整理:go語言中文文檔:

在本文我將詳細(xì)解釋這些設(shè)置的作用,并說明它們所能產(chǎn)生的(積極和消極)影響。

一個(gè)sql.DB對(duì)象就是一個(gè)數(shù)據(jù)庫連接池,它包含“正在用”和“空閑的”連接。一個(gè)正在用的連接指的是,你正用它來執(zhí)行數(shù)據(jù)庫任務(wù),例如執(zhí)行SQL語句或行查詢。當(dāng)任務(wù)完成連接就是空閑的。

當(dāng)您創(chuàng)建sql.DB執(zhí)行數(shù)據(jù)庫任務(wù)時(shí),它將首先檢查連接池中是否有可用的空閑連接。如果有可用的連接,那么Go將重用現(xiàn)有連接,并在執(zhí)行任務(wù)期間將其標(biāo)記為正在使用。如果池中沒有空閑連接,而您需要一個(gè)空閑連接,那么Go將創(chuàng)建一個(gè)新的連接。

默認(rèn)情況下,在同一時(shí)間打開連接的數(shù)量是沒有限制(包含使用中+空閑)。但你可以通過SetMaxOpenConns()方法實(shí)現(xiàn)自定義限制,如下所示:

在這個(gè)示例代碼中,連接池現(xiàn)在有5個(gè)并發(fā)打開的連接數(shù)。如果所有5個(gè)連接都已經(jīng)被標(biāo)記為正在使用,并且需要另一個(gè)新的連接,那么應(yīng)用程序?qū)⒈黄鹊却?,直?個(gè)連接中的一個(gè)被釋放并變?yōu)榭臻e。

為了說明更改MaxOpenConns的影響,我運(yùn)行了一個(gè)基準(zhǔn)測(cè)試,將最大打開連接數(shù)設(shè)置為1、2、5、10和無限?;鶞?zhǔn)測(cè)試在PostgreSQL數(shù)據(jù)庫上執(zhí)行并行的INSERT語句,您可以在這里找到代碼。測(cè)試結(jié)果:

對(duì)于這個(gè)基準(zhǔn)測(cè)試,我們可以看到,允許打開的連接越多,在數(shù)據(jù)庫上執(zhí)行INSERT操作所花費(fèi)的時(shí)間就越少(打開的連接數(shù)為1時(shí),執(zhí)行速度3129633ns/op,而無限連接:531030ns/op——大約快了6倍)。這是因?yàn)樵试S打開的連接越多,可以并發(fā)執(zhí)行的數(shù)據(jù)庫查詢就越多。

默認(rèn)情況下,sql.DB允許連接池中最多保留2個(gè)空閑連接。你可以通過SetMaxIdleConns()方法改變它,如下所示:

從理論上講,允許池中有更多的空閑連接將提高性能,因?yàn)檫@樣就不太可能從頭開始建立新連接——因此有助于提升數(shù)據(jù)庫性能。

讓我們來看看相同的基準(zhǔn)測(cè)試,最大空閑連接設(shè)置為none, 1,2,5和10:

當(dāng)MaxIdleConns設(shè)置為none時(shí),必須為每個(gè)INSERT從頭創(chuàng)建一個(gè)新的連接,我們可以從基準(zhǔn)測(cè)試中看到,平均運(yùn)行時(shí)和內(nèi)存使用量相對(duì)較高。

只允許保留和重用一個(gè)空閑連接對(duì)基準(zhǔn)測(cè)試影響特別明顯——它將平均運(yùn)行時(shí)間減少了大約8倍,內(nèi)存使用量減少了大約20倍。繼續(xù)增加空閑連接池的大小會(huì)使性能變得更好,盡管改進(jìn)并不明顯。

那么,您應(yīng)該維護(hù)一個(gè)大的空閑連接池嗎?答案取決于應(yīng)用程序。重要的是要意識(shí)到保持空閑連接是有代價(jià)的—它占用了可以用于應(yīng)用程序和數(shù)據(jù)庫的內(nèi)存。

還有一種可能是,如果一個(gè)連接空閑時(shí)間太長,那么它可能會(huì)變得不可用。例如,MySQL的wait_timeout設(shè)置將自動(dòng)關(guān)閉任何8小時(shí)(默認(rèn))內(nèi)未使用的連接。

當(dāng)發(fā)生這種情況時(shí),sql.DB會(huì)優(yōu)雅地處理它。壞連接將自動(dòng)重試兩次,然后放棄,此時(shí)Go將該連接從連接池中刪除,并創(chuàng)建一個(gè)新的連接。因此,將MaxIdleConns設(shè)置得太大可能會(huì)導(dǎo)致連接變得不可用,與空閑連接池更小(使用更頻繁的連接更少)相比,會(huì)占有更多的資源。所以,如果你很可能很快就會(huì)再次使用,你只需保持一個(gè)空閑的連接。

最后要指出的是,MaxIdleConns應(yīng)該總是小于或等于MaxOpenConns。Go強(qiáng)制執(zhí)行此操作,并在必要時(shí)自動(dòng)減少M(fèi)axIdleConns。

現(xiàn)在讓我們看看SetConnMaxLifetime()方法,它設(shè)置連接可重用的最大時(shí)間長度。如果您的SQL數(shù)據(jù)庫也實(shí)現(xiàn)了最大連接生命周期,或者—例如—您希望方便地在負(fù)載均衡器后交換數(shù)據(jù)庫,那么這將非常有用。

你可以這樣使用它:

在這個(gè)例子中,所有的連接都將在創(chuàng)建后1小時(shí)“過期”,并且在過期后無法重用。但注意:

從理論上講,ConnMaxLifetime越短,連接過期的頻率就越高——因此,需要從頭創(chuàng)建連接的頻率就越高。為了說明這一點(diǎn),我運(yùn)行了將ConnMaxLifetime設(shè)置為100ms、200ms、500ms、1000ms和無限(永遠(yuǎn)重用)的基準(zhǔn)測(cè)試,默認(rèn)設(shè)置為無限打開連接和2個(gè)空閑連接。這些時(shí)間段顯然比您在大多數(shù)應(yīng)用程序中使用的時(shí)間要短得多,但它們有助于很好地說明行為。

在這些特定的基準(zhǔn)測(cè)試中,我們可以看到,與無限生存期相比,在100ms生存期時(shí)內(nèi)存使用量增加了3倍以上,而且每個(gè)INSERT的平均運(yùn)行時(shí)也稍微長一些。

如果您在代碼中設(shè)置了ConnMaxLifetime,那么一定要記住連接將過期(隨后重新創(chuàng)建)的頻率。例如,如果您總共有100個(gè)連接,而ConnMaxLifetime為1分鐘,那么您的應(yīng)用程序可能每秒鐘殺死和重新創(chuàng)建1.67個(gè)連接(平均值)。您不希望這個(gè)頻率太大,最終會(huì)阻礙性能,而不是提高性能。

最后,如果不說明超過數(shù)據(jù)庫連接數(shù)量的硬限制將會(huì)發(fā)生什么,那么本文就不完整了。 為了說明這一點(diǎn),我將修改postgresql.conf文件,這樣總共只允許5個(gè)連接(默認(rèn)是100個(gè))…

然后在無限連接的情況下重新運(yùn)行基準(zhǔn)測(cè)試……

一旦達(dá)到5個(gè)連接的硬限制,數(shù)據(jù)庫驅(qū)動(dòng)程序(pq)立即返回一個(gè)太多客戶端連接的錯(cuò)誤消息,而無法完成INSERT。為了防止這個(gè)錯(cuò)誤,我們需要將sql.DB中打開連接的最大總數(shù)(正在使用的+空閑的)設(shè)置為低于5。像這樣:

現(xiàn)在,sql.DB在任何時(shí)候最多只能創(chuàng)建3個(gè)連接,基準(zhǔn)測(cè)試運(yùn)行時(shí)應(yīng)該不會(huì)出現(xiàn)任何錯(cuò)誤。但是這樣做需要注意:當(dāng)達(dá)到開放連接數(shù)限制,并且所有連接都在使用時(shí),應(yīng)用程序需要執(zhí)行的任何新的數(shù)據(jù)庫任務(wù)都將被迫等待,直到連接標(biāo)記為空閑。例如,在web應(yīng)用程序的上下文中,用戶的HTTP請(qǐng)求看起來會(huì)“掛起”,甚至在等待數(shù)據(jù)庫任務(wù)運(yùn)行時(shí)可能會(huì)超時(shí)。

為了減輕這種情況,你應(yīng)該始終在一個(gè)上下文中傳遞。在調(diào)用數(shù)據(jù)庫時(shí),啟用上下文的方法(如ExecContext()),使用固定的、快速的超時(shí)上下文對(duì)象。

總結(jié)

1、根據(jù)經(jīng)驗(yàn),應(yīng)該顯式設(shè)置MaxOpenConns值。這應(yīng)該小于數(shù)據(jù)庫和基礎(chǔ)設(shè)施對(duì)連接數(shù)量的硬性限制。

2、一般來說,更高的MaxOpenConns和MaxIdleConns值將帶來更好的性能。但你應(yīng)該注意到效果是遞減的,連接池空閑連接太多(連接沒有被重用,最終會(huì)變壞)實(shí)際上會(huì)導(dǎo)致性能下降。

3、為了降低上面第2點(diǎn)帶來的風(fēng)險(xiǎn),您可能需要設(shè)置一個(gè)相對(duì)較短的ConnMaxLifetime。但你也不希望它太短,導(dǎo)致連接被殺死或不必要地頻繁重建。

4、MaxIdleConns應(yīng)該總是小于或等于MaxOpenConns。

對(duì)于中小型web應(yīng)用程序,我通常使用以下設(shè)置作為起點(diǎn),然后根據(jù)實(shí)際吞吐量水平的負(fù)載測(cè)試結(jié)果進(jìn)行優(yōu)化。

Golang 建立TCP時(shí)使用連接池

程序輸出如下,相比不用連接池,單次操作時(shí)間少了一個(gè)數(shù)量級(jí)。

go語言TCP連接池rocket049/connpool使用

安裝:

go get -v -u github.com/rocket049/connpool

go get -v -u gitee.com/rocket049/connpool

rocket049/connpool 包是本人用go語言開發(fā)的,提供一個(gè)通用的TCP連接池,初始化參數(shù)包括最高連接數(shù)、超時(shí)秒數(shù)、連接函數(shù),放回連接池的連接被重新取出時(shí),如果已經(jīng)超時(shí),將會(huì)自動(dòng)重新連接;如果沒有超時(shí),連接將被復(fù)用。

可調(diào)用的函數(shù):

調(diào)用示例:

如何在 Go 語言中使用 Redis 連接池

一、關(guān)于連接池

一個(gè)數(shù)據(jù)庫服務(wù)器只擁有有限的資源,并且如果你沒有充分使用這些資源,你可以通過使用更多的連接來提高吞吐量。一旦所有的資源都在使用,那么你就不 能通過增加更多的連接來提高吞吐量。事實(shí)上,吞吐量在連接負(fù)載較大時(shí)就開始下降了。通??梢酝ㄟ^限制與可用的資源相匹配的數(shù)據(jù)庫連接的數(shù)量來提高延遲和吞 吐量。

如何在Go語言中使用Redis連接池

如果不使用連接池,那么,每次傳輸數(shù)據(jù),我們都需要進(jìn)行創(chuàng)建連接,收發(fā)數(shù)據(jù),關(guān)閉連接。在并發(fā)量不高的場(chǎng)景,基本上不會(huì)有什么問題,一旦并發(fā)量上去了,那么,一般就會(huì)遇到下面幾個(gè)常見問題:

性能普遍上不去

CPU 大量資源被系統(tǒng)消耗

網(wǎng)絡(luò)一旦抖動(dòng),會(huì)有大量 TIME_WAIT 產(chǎn)生,不得不定期重啟服務(wù)或定期重啟機(jī)器

服務(wù)器工作不穩(wěn)定,QPS 忽高忽低

要想解決這些問題,我們就要用到連接池了。連接池的思路很簡(jiǎn)單,在初始化時(shí),創(chuàng)建一定數(shù)量的連接,先把所有長連接存起來,然后,誰需要使用,從這里取走,干完活立馬放回來。 如果請(qǐng)求數(shù)超出連接池容量,那么就排隊(duì)等待、退化成短連接或者直接丟棄掉。

二、使用連接池遇到的坑

最近在一個(gè)項(xiàng)目中,需要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Web Server 提供 Redis 的 HTTP interface,提供 JSON 形式的返回結(jié)果。考慮用 Go 來實(shí)現(xiàn)。

首先,去看一下 Redis 官方推薦的 Go Redis driver。官方 Star 的項(xiàng)目有兩個(gè):Radix.v2 和 Redigo。經(jīng)過簡(jiǎn)單的比較后,選擇了更加輕量級(jí)和實(shí)現(xiàn)更加優(yōu)雅的 Radix.v2。

Radix.v2 包是根據(jù)功能劃分成一個(gè)個(gè)的 sub package,每一個(gè) sub package 在一個(gè)獨(dú)立的子目錄中,結(jié)構(gòu)非常清晰。我的項(xiàng)目中會(huì)用到的 sub package 有 redis 和 pool。

由于我想讓這種被 fork 的進(jìn)程最好簡(jiǎn)單點(diǎn),做的事情單一一些,所以,在沒有深入去看 Radix.v2 的 pool 的實(shí)現(xiàn)之前,我選擇了自己實(shí)現(xiàn)一個(gè) Redis pool。(這里,就不貼代碼了。后來發(fā)現(xiàn)自己實(shí)現(xiàn)的 Redis pool 與 Radix.v2 實(shí)現(xiàn)的 Redis pool 的原理是一樣的,都是基于 channel 實(shí)現(xiàn)的, 遇到的問題也是一樣的。)

不過在測(cè)試過程中,發(fā)現(xiàn)了一個(gè)詭異的問題。在請(qǐng)求過程中經(jīng)常會(huì)報(bào) EOF 錯(cuò)誤。而且是概率性出現(xiàn),一會(huì)有問題,一會(huì)又好了。通過反復(fù)的測(cè)試,發(fā)現(xiàn) bug 是有規(guī)律的,當(dāng)程序空閑一會(huì)后,再進(jìn)行連續(xù)請(qǐng)求,會(huì)發(fā)生3次失敗,然后之后的請(qǐng)求都能成功,而我的連接池大小設(shè)置的是3。再進(jìn)一步分析,程序空閑300秒 后,再請(qǐng)求就會(huì)失敗,發(fā)現(xiàn)我的 Redis server 配置了 timeout 300,至此,問題就清楚了。是連接超時(shí) Redis server 主動(dòng)斷開了連接??蛻舳诉@邊從一個(gè)超時(shí)的連接請(qǐng)求就會(huì)得到 EOF 錯(cuò)誤。

然后我看了一下 Radix.v2 的 pool 包的源碼,發(fā)現(xiàn)這個(gè)庫本身并沒有檢測(cè)壞的連接,并替換為新server{location/pool{content_by_lua_block{localredis=require"resty.redis"localred=redis:new()localok,err=red:connect("127.0.0.1",6379)ifnotokthenngx.say("failedtoconnect:",err)returnendok,err=red:set("hello","world")ifnotokthenreturnendred:set_keepalive(10000,100)}}}

發(fā)現(xiàn)有個(gè) set_keepalive 的方法,查了一下官方文檔,方法的原型是 syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size) 貌似 max_idle_timeout 這個(gè)參數(shù),就是我們所缺少的東西,然后進(jìn)一步跟蹤源碼,看看里面是怎么保證連接有效的。

function_M.set_keepalive(self,...)localsock=self.sockifnotsockthenreturnnil,"notinitialized"endifself.subscribedthenreturnnil,"subscribedstate"endreturnsock:setkeepalive(...)end

至此,已經(jīng)清楚了,使用了 tcp 的 keepalive 心跳機(jī)制。

于是,通過與 Radix.v2 的作者一些討論,選擇自己在 redis 這層使用心跳機(jī)制,來解決這個(gè)問題。

四、最后的解決方案

在創(chuàng)建連接池之后,起一個(gè) goroutine,每隔一段 idleTime 發(fā)送一個(gè) PING 到 Redis server。其中,idleTime 略小于 Redis server 的 timeout 配置。連接池初始化部分代碼如下:

p,err:=pool.New("tcp",u.Host,concurrency)errHndlr(err)gofunc(){for{p.Cmd("PING")time.Sleep(idelTime*time.Second)}}()

使用 redis 傳輸數(shù)據(jù)部分代碼如下:

funcredisDo(p*pool.Pool,cmdstring,args...interface{})(reply*redis.Resp,errerror){reply=p.Cmd(cmd,args...)iferr=reply.Err;err!=nil{iferr!=io.EOF{Fatal.Println("redis",cmd,args,"erris",err)}}return}

其中,Radix.v2 連接池內(nèi)部進(jìn)行了連接池內(nèi)連接的獲取和放回,代碼如下:

//Cmdautomaticallygetsoneclientfromthepool,executesthegivencommand//(returningitsresult),andputstheclientbackinthepoolfunc(p*Pool)Cmd(cmdstring,args...interface{})*redis.Resp{c,err:=p.Get()iferr!=nil{returnredis.NewResp(err)}deferp.Put(c)returnc.Cmd(cmd,args...)}

這樣,我們就有了 keepalive 的機(jī)制,不會(huì)出現(xiàn) timeout 的連接了,從 redis 連接池里面取出的連接都是可用的連接了。看似簡(jiǎn)單的代碼,卻完美的解決了連接池里面超時(shí)連接的問題。同時(shí),就算 Redis server 重啟等情況,也能保證連接自動(dòng)重連。

使用Go實(shí)現(xiàn)一個(gè)數(shù)據(jù)庫連接池

開始本文之前,我們看一段Go連接數(shù)據(jù)庫的代碼:

本文內(nèi)容我們將解釋連接池背后是如何工作的,并 探索 如何配置數(shù)據(jù)庫能改變或優(yōu)化其性能。

轉(zhuǎn)自:

整理:地鼠文檔:

那么sql.DB連接池是如何工作的呢?

需要理解的最重要一點(diǎn)是,sql.DB池包含兩種類型的連接——“正在使用”連接和“空閑”連接。當(dāng)您使用連接執(zhí)行數(shù)據(jù)庫任務(wù)(例如執(zhí)行SQL語句或查詢行)時(shí),該連接被標(biāo)記為正在使用,任務(wù)完成后,該連接被標(biāo)記為空閑。

當(dāng)您使用Go執(zhí)行數(shù)據(jù)庫操作時(shí),它將首先檢查池中是否有可用的空閑連接。如果有可用的連接,那么Go將重用這個(gè)現(xiàn)有連接,并在任務(wù)期間將其標(biāo)記為正在使用。如果在您需要空閑連接時(shí)池中沒有空閑連接,那么Go將創(chuàng)建一個(gè)新的連接。

當(dāng)Go重用池中的空閑連接時(shí),與該連接有關(guān)的任何問題都會(huì)被優(yōu)雅地處理。異常連接將在放棄之前自動(dòng)重試兩次,這時(shí)Go將從池中刪除異常連接并創(chuàng)建一個(gè)新的連接來執(zhí)行該任務(wù)。

連接池有四個(gè)方法,我們可以使用它們來配置連接池的行為。讓我們一個(gè)一個(gè)地來討論。

SetMaxOpenConns()方法允許您設(shè)置池中“打開”連接(使用中+空閑連接)數(shù)量的上限。默認(rèn)情況下,打開的連接數(shù)是無限的。

一般來說,MaxOpenConns設(shè)置得越大,可以并發(fā)執(zhí)行的數(shù)據(jù)庫查詢就越多,連接池本身成為應(yīng)用程序中的瓶頸的風(fēng)險(xiǎn)就越低。

但讓它無限并不是最好的選擇。默認(rèn)情況下,PostgreSQL最多100個(gè)打開連接的硬限制,如果達(dá)到這個(gè)限制的話,它將導(dǎo)致pq驅(qū)動(dòng)返回”sorry, too many clients already”錯(cuò)誤。

為了避免這個(gè)錯(cuò)誤,將池中打開的連接數(shù)量限制在100以下是有意義的,可以為其他需要使用PostgreSQL的應(yīng)用程序或會(huì)話留下足夠的空間。

設(shè)置MaxOpenConns限制的另一個(gè)好處是,它充當(dāng)一個(gè)非?;镜南蘖髌?,防止數(shù)據(jù)庫同時(shí)被大量任務(wù)壓垮。

但設(shè)定上限有一個(gè)重要的警告。如果達(dá)到MaxOpenConns限制,并且所有連接都在使用中,那么任何新的數(shù)據(jù)庫任務(wù)將被迫等待,直到有連接空閑。在我們的API上下文中,用戶的HTTP請(qǐng)求可能在等待空閑連接時(shí)無限期地“掛起”。因此,為了緩解這種情況,使用上下文為數(shù)據(jù)庫任務(wù)設(shè)置超時(shí)是很重要的。我們將在書的后面解釋如何處理。

SetMaxIdleConns()方法的作用是:設(shè)置池中空閑連接數(shù)的上限。缺省情況下,最大空閑連接數(shù)為2。

理論上,在池中允許更多的空閑連接將增加性能。因?yàn)樗鼫p少了從頭建立新連接發(fā)生概率—,因此有助于節(jié)省資源。

但要意識(shí)到保持空閑連接是有代價(jià)的。它占用了本來可以用于應(yīng)用程序和數(shù)據(jù)庫的內(nèi)存,而且如果一個(gè)連接空閑時(shí)間過長,它也可能變得不可用。例如,默認(rèn)情況下MySQL會(huì)自動(dòng)關(guān)閉任何8小時(shí)未使用的連接。

因此,與使用更小的空閑連接池相比,將MaxIdleConns設(shè)置得過高可能會(huì)導(dǎo)致更多的連接變得不可用,浪費(fèi)資源。因此保持適量的空閑連接是必要的。理想情況下,你只希望保持一個(gè)連接空閑,可以快速使用。

另一件要指出的事情是MaxIdleConns值應(yīng)該總是小于或等于MaxOpenConns。Go會(huì)強(qiáng)制保證這點(diǎn),并在必要時(shí)自動(dòng)減少M(fèi)axIdleConns值。

SetConnMaxLifetime()方法用于設(shè)置ConnMaxLifetime的極限值,表示一個(gè)連接保持可用的最長時(shí)間。默認(rèn)連接的存活時(shí)間沒有限制,永久可用。

如果設(shè)置ConnMaxLifetime的值為1小時(shí),意味著所有的連接在創(chuàng)建后,經(jīng)過一個(gè)小時(shí)就會(huì)被標(biāo)記為失效連接,標(biāo)志后就不可復(fù)用。但需要注意:

理論上,ConnMaxLifetime為無限大(或設(shè)置為很長生命周期)將提升性能,因?yàn)檫@樣可以減少新建連接。但是在某些情況下,設(shè)置短期存活時(shí)間有用。比如:

如果您決定對(duì)連接池設(shè)置ConnMaxLifetime,那么一定要記住連接過期(然后重新創(chuàng)建)的頻率。例如,如果連接池中有100個(gè)打開的連接,而ConnMaxLifetime為1分鐘,那么您的應(yīng)用程序平均每秒可以殺死并重新創(chuàng)建多達(dá)1.67個(gè)連接。您不希望頻率太大而最終影響性能吧。

SetConnMaxIdleTime()方法在Go 1.15版本引入對(duì)ConnMaxIdleTime進(jìn)行配置。其效果和ConnMaxLifeTime類似,但這里設(shè)置的是:在被標(biāo)記為失效之前一個(gè)連接最長空閑時(shí)間。例如,如果我們將ConnMaxIdleTime設(shè)置為1小時(shí),那么自上次使用以后在池中空閑了1小時(shí)的任何連接都將被標(biāo)記為過期并被后臺(tái)清理操作刪除。

這個(gè)配置非常有用,因?yàn)樗馕吨覀兛梢詫?duì)池中空閑連接的數(shù)量設(shè)置相對(duì)較高的限制,但可以通過刪除不再真正使用的空閑連接來周期性地釋放資源。

所以有很多信息要吸收。這在實(shí)踐中意味著什么?我們把以上所有的內(nèi)容總結(jié)成一些可行的要點(diǎn)。

1、根據(jù)經(jīng)驗(yàn),您應(yīng)該顯式地設(shè)置MaxOpenConns值。這個(gè)值應(yīng)該低于數(shù)據(jù)庫和操作系統(tǒng)對(duì)連接數(shù)量的硬性限制,您還可以考慮將其保持在相當(dāng)?shù)偷乃?,以充?dāng)基本的限流作用。

對(duì)于本書中的項(xiàng)目,我們將MaxOpenConns限制為25個(gè)連接。我發(fā)現(xiàn)這對(duì)于小型到中型的web應(yīng)用程序和API來說是一個(gè)合理的初始值,但理想情況下,您應(yīng)該根據(jù)基準(zhǔn)測(cè)試和壓測(cè)結(jié)果調(diào)整這個(gè)值。

2、通常,更大的MaxOpenConns和MaxIdleConns值會(huì)帶來更好的性能。但是,效果是逐漸降低的,而且您應(yīng)該注意,太多的空閑連接(連接沒有被復(fù)用)實(shí)際上會(huì)導(dǎo)致性能下降和不必要的資源消耗。

因?yàn)镸axIdleConns應(yīng)該總是小于或等于MaxOpenConns,所以對(duì)于這個(gè)項(xiàng)目,我們還將MaxIdleConns限制為25個(gè)連接。

3、為了降低上面第2點(diǎn)的風(fēng)險(xiǎn),通常應(yīng)該設(shè)置ConnMaxIdleTime值來刪除長時(shí)間未使用的空閑連接。在這個(gè)項(xiàng)目中,我們將設(shè)置ConnMaxIdleTime持續(xù)時(shí)間為15分鐘。

4、ConnMaxLifetime默認(rèn)設(shè)置為無限大是可以的,除非您的數(shù)據(jù)庫對(duì)連接生命周期施加了硬限制,或者您需要它協(xié)助一些操作,比如優(yōu)雅地交換數(shù)據(jù)庫。這些都不適用于本項(xiàng)目,所以我們將保留這個(gè)默認(rèn)的無限制配置。

與其硬編碼這些配置,不如更新cmd/api/main.go文件通過命令行參數(shù)讀取配置。

ConnMaxIdleTime值比較有意思,因?yàn)槲覀兿M鼈鬟f一段時(shí)間,最終需要將其轉(zhuǎn)換為Go的time.Duration類型。這里有幾個(gè)選擇:

1、我們可以使用一個(gè)整數(shù)來表示秒(或分鐘)的數(shù)量,并將其轉(zhuǎn)換為time.Duration。

2、我們可以使用一個(gè)表示持續(xù)時(shí)間的字符串——比如“5s”(5秒)或“10m”(10分鐘)——然后使用time.ParseDuration()函數(shù)解析它。

3、兩種方法都可以很好地工作,但是在這個(gè)項(xiàng)目中我們將使用選項(xiàng)2。繼續(xù)并更新cmd/api/main.go文件如下:

File: cmd/api/main.go

本文題目:開源go語言數(shù)據(jù)庫連接池 gorm數(shù)據(jù)庫連接池
網(wǎng)頁網(wǎng)址:http://muchs.cn/article2/hgigic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)小程序開發(fā)、網(wǎng)站導(dǎo)航網(wǎng)站建設(shè)、云服務(wù)器、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司