mysql、redis 客戶端連線池

KerryWu發表於2022-11-23

1.mysql

1.1. mysql 引數

透過下列命令可檢視mysql資料庫配置的系統引數:

-- 查詢所有系統引數
show variables;
--模糊匹配查詢系統引數,如:wait_timeout
show variables like '%wait_timeout%';

這裡介紹幾個和連線池有關聯的引數:

1. wait_timeout

非互動連線的最大存活時間,單位:秒。即空閒狀態下的連線,超過規定時間後,mysql 會自動斷開。

可透過下列命令檢視具體的連線的狀態:

show processlist;

如果 sleep 狀態的程式,佔用總比例過高,就可以考慮調小 wait_timeout 值了。

2. max_connections

全域性最大連線數。

可透過下列命令檢視最大使用的連線數量(Max_used_connections):

show status like 'max%connections%';

再透過下列命令檢視最大連線數(max_connections):

show variables like 'max%connections%';

透過 Max_used_connections/max_connections 的佔比來判斷設定的最大連線數是否合理,理想情況下這個比例應該在85%左右。

max_connections 預設值是100,如果伺服器的併發連線請求量比較大,建議調高此值,以增加並行連線數量,當然這建立在機器能支撐的情況下,因為如果連線數越多,介於MySQL會為每個連線提供連線緩衝區,就會開銷越多的記憶體,所以要適當調整該值,不能盲目提高設值。

1.2. druid 連線池配置

核心引數

1. initial-size

初始化時建立物理連線的個數。

2. max-active

連線池同時能維持的最大連線數。

3. min-idle

最多維持多少個空閒連線,即使客戶端沒有需求,也要至少維持多少個空閒連線,以應對客戶端的突發需求。

4. max-idle(已作廢)

5. max-wait

連線最大等待時間,單位毫秒。客戶端從連線池獲取(借出)一個連線後,規定時間內沒有歸還,則連線池會丟擲 GetConnectionTimeoutException 異常。

場景模擬

假設配置的值如下:

spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=10
spring.datasource.druid.max-active=50

專案啟動時,會自動建立5(initial-size)個連線,就算此時沒有資料庫訪問,也會建立這5個。並且當客戶端查詢資料庫的併發不大於5時,就一直是這5個。

當客戶端查詢資料庫的併發越來越大,超過5時,連線數也就往上增加,但不會超過最大連線數50(max-active)。當併發數超過50時,超過部分的請求就會在佇列中等待。

當峰值過去了,併發數降到50一下,多出來的連線空閒後就關閉了,連線數也就隨之下降。當連線數最小隻會降到10(min-idle),最多維持10個空閒連線。

1.3. hikari 連線池配置

下列翻譯自 HikariCP Github引數說明

1. connection-timeout

控制客戶端等待來自連線池連線的最大毫秒數。

如果超過此時間而沒有可用的連線,則會丟擲SQLException。可接受的最低連線超時為250 ms。 預設值:30000(30秒)

2. max-lifetime

控制連線池中連線的最大生存時間。

正在使用中的連線永遠不會停止使用,只有在連線關閉後,在達到最大生存週期後才將其刪除。值為0表示沒有最大生存期(無限生存期),當然這取決於idleTimeout設定。最小允許值是30秒,預設值:30分鐘。

建議:設定的時間要比資料庫中限制的連線(mysql對應引數 wait_timeout)最大生存時間小几秒鐘。

3. minimum-idle

此屬性控制HikariCP試圖在池中維護的最小空閒連線數。

如果空閒連線低於此值,並且池中的總連線小於最大池大小,HikariCP將盡最大努力快速高效地新增其他連線。預設值:與 maximum-pool-size 相同。

建議:為了最大限度地提高效能和響應峰值需求,我們建議不要設定此值,而是允許HikariCP充當固定大小的連線池。即保持和 maximum-pool-size 值相同。

4. idle-timeout

此屬性控制允許連線在池中空閒的最長時間。

僅當 minimum-idle 定義為小於 maximum-pool-size 時,此設定才適用。一旦池達到最小空閒連線數,空閒連線將不會失效。連線是否因空閒而失效取決於+30秒的最大變化和+15秒的平均變化。在此超時之前,連線永遠不會以空閒狀態退出。值為0表示從不從池中刪除空閒連線。最小允許值為10000ms(10秒)。預設值:600000(10分鐘)。

建議:因為是建議 minimum-idle 和 maximum-pool-size 保持一致,維護固定大小的連線池,則 idle-timeout 設定不會生效。建議就保持預設值,或者乾脆設為0。

5. maximum-pool-size

此屬性控制池允許達到的最大大小,包括空閒連線和正在使用的連線。基本上,該值將確定到資料庫後端的實際連線的最大數量。當池達到此大小且沒有空閒連線可用時,對getConnection() 的呼叫將在超時前阻塞最多 connection-timeout 毫秒。預設值:10。

建議:沒有絕對的值,因為是連線池的最大連線數,所以要根據產線業務 TPS 併發量,以及伺服器實際配置各種環境來靈活考量配置,影響因素如下:

  • CPU核心數:首先網上有這麼個公式:最大連線數 = ((CPU核心數 * 2) + 有效磁碟數)。可見,最大連線數是和CPU核心數是密切相關的。因為最大連線數是和最大併發執行緒相關的,當CPU核心數有限時,一味的擴大併發連線數,反而會因為上下文切換導致效能下降。
  • 資料庫總連線數: 應用連線池的配置是針對某個服務單例項的,但通常一個資料庫是多個服務共享的。假設有10個服務,每個服務平均有8個例項負載,單個連線池的最大連線數設為50。那麼總的連線數就是 10 8 50 = 4000。而如果mysql資料庫的 max_connections 不到4000,那麼必然會導致有些連線失效。

2. redis

2.1. redis 引數

1. 檢視允許最大連線數量

執行命令:

config get maxclients

返回結果示例,即最大連線數10000:

maxclients
10000
2. 檢視實時連線數量
info clients

返回結果示例,依次返回的內容有:(1)當前客戶端連線數、(2)當前所有輸出快取區中佇列物件個數的最大值、(3)當前所有輸出快取區中佔用的最大容量、(4)正在等待阻塞命令(如:BLPOP)的客戶端數量

# Clients
connected_clients:39
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:1

2.2. jedis 連線池配置

1. max-totalmax-active

資源池中的最大連線數。預設值:8。舊版本中是 max-active,jedis 2.4.x 以上都用 max-total 來替代。

想合理設定maxTotal(最大連線數)需要考慮的因素較多,如:

  • 業務希望的Redis併發量;
  • 客戶端執行命令時間;
  • Redis資源,例如 nodes * maxTotal 不能超過Redis的最大連線數;
  • 資源開銷,例如雖然希望控制空閒連線,但又不希望因為連線池中頻繁地釋放和建立連線造成不必要的開銷。

假設一次命令時間,即borrow|return resource加上Jedis執行命令 ( 含網路耗時)的平均耗時約為1ms,一個連線的QPS大約是1s/1ms = 1000,而業務期望的單個Redis的QPS是50000(業務總的QPS/Redis分片個數),那麼理論上需要的資源池大小(即MaxTotal)是50000 / 1000 = 50。

但事實上這只是個理論值,除此之外還要預留一些資源,所以maxTotal可以比理論值大一些。

這個值不是越大越好,一方面連線太多會佔用客戶端和服務端資源,另一方面對於Redis這種高QPS的伺服器,如果出現大命令的阻塞,即使設定再大的資源池也無濟於事。

綜上所述,在沒有達到資源瓶頸前,jedis 最大連線數和能實現併發量是成正比的。如果處於高併發的需求,可以多加連線數。

2. max-idle

資源池允許的最大空閒連線數。預設值:8。

maxIdle實際上才是業務需要的最大連線數,maxTotal 是為了給出餘量,所以 maxIdle 不要設定得過小,否則會有new Jedis(新連線)開銷,而minIdle是為了控制空閒資源檢測。

連線池的最佳效能是 maxTotal=maxIdle,這樣就避免了連線池伸縮帶來的效能干擾。如果您的業務存在突峰訪問,建議設定這兩個引數的值相等;如果併發量不大或者maxIdle設定過高,則會導致不必要的連線資源浪費。

可以根據實際總QPS和呼叫Redis的客戶端規模整體評估每個節點所使用的連線池大小。在實際環境中,比較可靠的方法是透過監控來嘗試獲取引數的最佳值。可以考慮透過JMX等方式實現監控,從而找到合理值。

3. min-idle

資源池允許的最小空閒連線數。預設值:0。

4. block-when-exhausted

當資源池用盡後,呼叫者是否要等待。只有當值為true時,下面的max-wait-millis才會生效。預設值:true。

5. max-wait-millismax-wait

當資源池連線用盡後,呼叫者的最大等待時間(單位為毫秒)。預設值:-1(表示永不超時)。舊版本中是 max-wait,jedis 2.4.x 以上都用 max-wait-millis 來替代。

2.3. lettuce 連線池配置

1. max-total

連線池最大連線數(使用負值表示沒有限制)。預設值:8。

推薦:cpu核數*2。

2. max-idle

連線池最大空閒連線數(使用負值表示沒有限制),僅當 min-idle 和 time-between-eviction-runs 的值都為正時有效。。預設值:8。

推薦:cpu核數*2。

3. min-idle

連線池最小空閒連線數,僅當 min-idle 和 time-between-eviction-runs 的值都為正時有效。預設值:0。

推薦:根據時間場景,是否需要初始化預熱等等。

4. time-between-eviction-runs

空閒連線逐出器(獨立執行緒)的執行間隔時間(單位為毫秒)。當值為正值時,空閒連線逐出器才啟動。

這個逐出器的任務一旦啟動後,不僅可以將連線池中超過 max-idle 數量的空閒連線逐出;還會在連線池中空閒連線數少於 min-idle 時,補齊空閒連線的建立。

推薦:正值,開啟任務。

5. max-wait

連線池資源耗盡時,連線嘗試分配阻塞時間(單位為毫秒),超時即丟擲異常。(使用負值表示沒有限制)。預設值:-1ms。

推薦:開啟,根據業務設定,不建議設定過大,否則耗盡業務執行緒池。

2.4. 場景模擬

Jedis 和 Lettuce 採用的連線池是 GenericObjectPoolConfig 所以通用的配置項是相同的,那麼就都基於統一配置做場景模擬。

場景一
xxx.max-total=30
xxx.max-idle=20
xxx.min-idle=10

當連線池剛啟動,且空閒連線數不超過10。如果需要使用連線時,連線池會一直建立新連線,而不會複用空閒連線。直到連線池中連線數量達到了10(min-idle)。

當連線數超過10,實際連線數又繼續增加,但由於總連線數 max-total 是30。當總連線數達到30後,不會建立新的連線,後續連線請求會在等待。

當實際使用的連線數從30降下來後,一部分連線轉為了空閒連線。即:在用連線數量在減少,空閒連線數量在增加。但當空閒連線數量大於20(max-idle)時,後續的空閒連線將不會放回連線池,而是直接扔掉。

2.5. jedis vs lettuce

簡單的說, Jedis連線池越大越好, Lettuce連線池越小越好, 為什麼會有這種差異?

Jedis採用傳統BIO網路模型, 在資源允許的範圍內, 這種模型下連線數(執行緒數)越多效能越好。

Lettuce採用NIO網路模型, 底層元件採用Netty, 這種模型下效能和CPU核數相關, 通常雲主機CPU核數都不大通常在2-16核, 因此Lettuce連線池配置普遍不宜過大, 過大範圍會影響效能。

相關文章