最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang配制高性能sql.DB的使用

 更新時間:2021年12月10日 10:38:34   作者:Go語言由淺入深  
本文主要講述SetMaxOpenConns(),?SetMaxIdleConns()?和?SetConnMaxLifetime()方法,?您可以使用它們來配置sql.DB的行為并改變其性能,感興趣的可以了解一下

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

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

開放和空閑連接

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

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

SetMaxOpenConns方法

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

// 初始化一個新的連接池
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db")
if err != nil {
    log.Fatal(err)
}

// 設置當前最大開放連接數(shù)(包括空閑和正在使用的)為5。
// 如果設置為0代表連接數(shù)沒有限制,默認是沒有限制數(shù)量的。
db.SetMaxOpenConns(5)

在這個示例代碼中,連接池現(xiàn)在有5個并發(fā)打開的連接數(shù)。如果所有5個連接都已經被標記為正在使用,并且需要另一個新的連接,那么應用程序將被迫等待,直到5個連接中的一個被釋放并變?yōu)榭臻e。

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

BenchmarkMaxOpenConns1-8???????????????? 500?????? 3129633 ns/op???????? 478 B/op???????? 10 allocs/op
BenchmarkMaxOpenConns2-8??????????????? 1000?????? 2181641 ns/op???????? 470 B/op???????? 10 allocs/op
BenchmarkMaxOpenConns5-8??????????????? 2000??????? 859654 ns/op???????? 493 B/op???????? 10 allocs/op
BenchmarkMaxOpenConns10-8?????????????? 2000??????? 545394 ns/op???????? 510 B/op???????? 10 allocs/op
BenchmarkMaxOpenConnsUnlimited-8??????? 2000??????? 531030 ns/op???????? 479 B/op????????? 9 allocs/op
PASS

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

SetMaxIdleConns方法

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

//  初始化一個新的連接池
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db")
if err != nil {
    log.Fatal(err)
}

// 設置最大空閑連接數(shù)為5。 將此值設置為小于或等于0將意味著不保留空閑連接。
db.SetMaxIdleConns(5)

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

讓我們來看看相同的基準測試,最大空閑連接設置為none, 1,2,5和10:

BenchmarkMaxIdleConnsNone-8????????? 300?????? 4567245 ns/op?????? 58174 B/op??????? 625 allocs/op
BenchmarkMaxIdleConns1-8??????????? 2000??????? 568765 ns/op??????? 2596 B/op???????? 32 allocs/op
BenchmarkMaxIdleConns2-8??????????? 2000??????? 529359 ns/op???????? 596 B/op???????? 11 allocs/op
BenchmarkMaxIdleConns5-8??????????? 2000??????? 506207 ns/op???????? 451 B/op????????? 9 allocs/op
BenchmarkMaxIdleConns10-8?????????? 2000??????? 501639 ns/op???????? 450 B/op????????? 9 allocs/op
PASS

當MaxIdleConns設置為none時,必須為每個INSERT從頭創(chuàng)建一個新的連接,我們可以從基準測試中看到,平均運行時和內存使用量相對較高。

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

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

還有一種可能是,如果一個連接空閑時間太長,那么它可能會變得不可用。例如,MySQL的wait_timeout設置將自動關閉任何8小時(默認)內未使用的連接。

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

最后要指出的是,MaxIdleConns應該總是小于或等于MaxOpenConns。Go強制執(zhí)行此操作,并在必要時自動減少MaxIdleConns。

SetConnMaxLifetime方法

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

// 初始化一個新的連接池
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db")
if err != nil {
    log.Fatal(err)
}

// 將連接的最大生存期設置為1小時。將其設置為0意味著沒有最大生存期,連接將永遠可重用(這是默認行為)
db.SetConnMaxLifetime(time.Hour)

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

  • 這并不能保證連接將在池中存在整整一個小時;很有可能,由于某些原因,連接變得不可用,并在此之前自動關閉。
  • 一個連接在創(chuàng)建后一個多小時仍然可以被使用——它只是在這個時間之后不能被重用。
  • 這不是空閑超時。連接將在第一次創(chuàng)建后1小時過期——而不是在最后一次空閑后1小時。
  • 每隔一秒自動運行一次清理操作,從連接池中刪除“過期”的連接。

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

BenchmarkConnMaxLifetime100-8?????????????? 2000??????? 637902 ns/op??????? 2770 B/op???????? 34 allocs/op
BenchmarkConnMaxLifetime200-8?????????????? 2000??????? 576053 ns/op??????? 1612 B/op???????? 21 allocs/op
BenchmarkConnMaxLifetime500-8?????????????? 2000??????? 558297 ns/op???????? 913 B/op???????? 14 allocs/op
BenchmarkConnMaxLifetime1000-8????????????? 2000??????? 543601 ns/op???????? 740 B/op???????? 12 allocs/op
BenchmarkConnMaxLifetimeUnlimited-8???????? 3000??????? 532789 ns/op???????? 412 B/op????????? 9 allocs/op
PASS

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

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

連接數(shù)量超出

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

max_connections = 5

然后在無限連接的情況下重新運行基準測試……

BenchmarkMaxOpenConnsUnlimited-8??? --- FAIL: BenchmarkMaxOpenConnsUnlimited-8
??? main_test.go:14: pq: sorry, too many clients already
??? main_test.go:14: pq: sorry, too many clients already
??? main_test.go:14: pq: sorry, too many clients already
FAIL

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

// 初始化一個新的連接池
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db")
if err != nil {
    log.Fatal(err)
}

// 將打開的連接數(shù)(正在使用的連接+空閑的連接)設置為最大總數(shù)3。
 db.SetMaxOpenConns (3)

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

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

總結

1、根據經驗,應該顯式設置MaxOpenConns值。這應該小于數(shù)據庫和基礎設施對連接數(shù)量的硬性限制。
2、一般來說,更高的MaxOpenConns和MaxIdleConns值將帶來更好的性能。但你應該注意到效果是遞減的,連接池空閑連接太多(連接沒有被重用,最終會變壞)實際上會導致性能下降。
3、為了降低上面第2點帶來的風險,您可能需要設置一個相對較短的ConnMaxLifetime。但你也不希望它太短,導致連接被殺死或不必要地頻繁重建。
4、MaxIdleConns應該總是小于或等于MaxOpenConns。
對于中小型web應用程序,我通常使用以下設置作為起點,然后根據實際吞吐量水平的負載測試結果進行優(yōu)化。

db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5*time.Minute)

到此這篇關于golang配制高性能sql.DB的使用的文章就介紹到這了,更多相關golang配制高性能sql.DB內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關文章

  • go函數(shù)的參數(shù)設置默認值的方法

    go函數(shù)的參數(shù)設置默認值的方法

    Go語言不直接支持函數(shù)參數(shù)默認值,但可以通過指針、結構體、變長參數(shù)和選項模式等方法模擬,下面給大家分享幾種方式模擬函數(shù)參數(shù)的默認值功能,感興趣的朋友一起看看吧
    2025-01-01
  • go-zero使用goctl生成mongodb的操作使用方法

    go-zero使用goctl生成mongodb的操作使用方法

    mongodb是一種高性能、開源、文檔型的nosql數(shù)據庫,被廣泛應用于web應用、大數(shù)據以及云計算領域,goctl model 為 goctl 提供的數(shù)據庫模型代碼生成指令,目前支持 MySQL、PostgreSQL、Mongo 的代碼生成,本文給大家介紹了go-zero使用goctl生成mongodb的操作使用方法
    2024-06-06
  • 深入理解Golang channel的應用

    深入理解Golang channel的應用

    channel是用于 goroutine 之間的同步、通信的數(shù)據結構。它為程序員提供了更高一層次的抽象,封裝了更多的功能,這樣并發(fā)編程變得更加容易和安全。本文通過示例為大家詳細介紹了channel的應用,需要的可以參考一下
    2022-10-10
  • Goland IDEA項目多開設置方式

    Goland IDEA項目多開設置方式

    這篇文章主要介紹了Goland IDEA項目多開設置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Go語言的變量定義詳情

    Go語言的變量定義詳情

    這篇文章主要介紹了Go語言的變量定義詳情,go定義變量的方式和c,c++,java語法不一樣,var?變量名類型,var在前,變量名在中間,類型在后面,下文更多詳細內容需要的小伙伴可以參考一下
    2022-03-03
  • Golang中互斥鎖和讀寫互斥鎖原理及示例代碼

    Golang中互斥鎖和讀寫互斥鎖原理及示例代碼

    在Golang中,互斥鎖是一種基本的同步原語,用于實現(xiàn)對共享資源的互斥訪問,讀寫互斥鎖是一種特殊類型的互斥鎖,它允許多個協(xié)程同時讀取某個共享資源,本文將通過過示例代碼詳細介紹Golang中互斥鎖和讀寫互斥鎖,需要的朋友可以參考下
    2023-05-05
  • Golang打包配置文件的實現(xiàn)示例

    Golang打包配置文件的實現(xiàn)示例

    本文主要介紹了Golang打包配置文件的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Golang如何自定義logrus日志保存為日志文件

    Golang如何自定義logrus日志保存為日志文件

    這篇文章主要給大家介紹了關于Golang如何自定義logrus日志保存為日志文件的相關資料,logrus是目前Github上star數(shù)量最多的日志庫,logrus功能強大,性能高效,而且具有高度靈活性,提供了自定義插件的功能,很多開源項目都是用了logrus來記錄其日志,需要的朋友可以參考下
    2024-02-02
  • go 語言字符類型 byte 與 rune案例詳解

    go 語言字符類型 byte 與 rune案例詳解

    這篇文章主要介紹了go 語言字符類型 byte 與 rune案例詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • 聊聊Golang的語言結構和變量問題

    聊聊Golang的語言結構和變量問題

    這篇文章主要介紹了Golang的語言結構和變量問題,在golang中定義變量的一般形式是使用 var 關鍵字,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2021-11-11

最新評論

迁西县| 三江| 四平市| 曲麻莱县| 安乡县| 福贡县| 石阡县| 姚安县| 雅江县| 佛冈县| 枣庄市| 洪洞县| 聂拉木县| 潼关县| 郧西县| 沙坪坝区| 孝感市| 崇州市| 广水市| 上思县| 剑河县| 封开县| 崇阳县| 舟曲县| 保康县| 稷山县| 吴忠市| 西平县| 清徐县| 桃源县| 惠水县| 湛江市| 福建省| 塔城市| 合肥市| 阜康市| 阿尔山市| 荥经县| 合肥市| 栾城县| 绿春县|