談一談對象池SafeObjectPool能干什么


前言

首先從ado.net的連接池開始了解,數據庫操作通常是 new SqlConnection()、 Open()、 使用完后 Close(),整個過程相當耗時,特別是頻繁建議套字接連接的過程。ado.net 驅動已經現實了連接池管理,Open() 等於申請連接,Close() 即歸還資源。

Open() 的時候有幾種情況:

1、有資源直接返回;

2、無可用資源,且未超過池最大設置值時,創建資源並返回;

3、無可用資源,此時會等待設置秒數,若仍然未獲取資源則報錯;

連接的復用使性能成數倍提升,試想網站在某一時刻突然爆增10萬次,new 10萬個SqlConnection對象顯然會炸掉服務,創建,connect,disconnect,disponse,顯然開銷很大。

雖然ado.net自帶的連接池已經接近完美,但在某些場合還不夠用,先來一個壓力測試。

SafeObjectPool與dapper比武測試

[HttpGet("vs_gen")]
async public Task<object> vs_gen() {
	var select = Tag.Select;
	var count = await select.CountAsync();
	var items = await select.Page(page, limit).ToListAsync();

	return new { count, items };
}

[HttpGet("vs_dapper")]
async public Task<object> vs_dapper() {
	var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=11");
	conn.Open();
	var count = await conn.ExecuteScalarAsync<int>("SELECT count(1) FROM[dbo].[tag] a");
	//conn.Close();

	//conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=11");
	//conn.Open();
	var items = await conn.QueryAsync("SELECT TOP 20 a.[id], a.[parent_id], a.[name] FROM[dbo].[tag] a");
	conn.Close();

	return new { count, items };
}

連接池最大分別為:10,11

使用 apache ab 命令行測試上面兩個接口

ab -c 10 -n 1000 -s 6000 測試結果差不多。

-c 100 時,vs_dapper直接掛了,vs_gen沒影響(使用了SafeObjectPool)

實踐證明ado.net過於暴露,突然的高並發招架不住。

SafeObjectPool

它是一個對象池,可用於控制任何資源緊缺的對象,使用容器化管重復使用提升性能,有序的排隊獲取,使用完后歸還資源。

與ado.net連接池不同的地方,SafeObjectPool 解決池用盡后,再請求不報錯,進行排隊等待機制,並且適用任何對象不局限於數據庫連接對象。

SafeObjectPool 提供可用性檢查方法,比如 redisClient 不可用時,所有Get/GetAsync都將報錯,直到后台服務檢查並恢復狀態。

使用方法

Install-Package SafeObjectPool

var pool = new SafeObjectPool.ObjectPool<MemoryStream>(10, () => new MemoryStream(), obj => {
	if (DateTime.Now.Subtract(obj.LastGetTime).TotalSeconds > 5) {
		// 對象超過5秒未活動,進行操作
	}
});

var obj = pool.Get(); //借
pool.Return(obj); //歸還

//或者 using 自動歸還
using (var obj = pool.Get()) {
}

異常

  • 同步獲取資源時 pool.Get()

【連接池名稱】狀態不可用,等待后台檢查程序恢復方可使用。

SafeObjectPool.Get 獲取超時(10秒),設置 Policy.IsThrowGetTimeoutException 可以避免該異常。

  • 異步獲取資源時 pool.GetAsync()

【連接池名稱】狀態不可用,等待后台檢查程序恢復方可使用。

SafeObjectPool.GetAsync 無可用資源且隊列過長,Policy.AsyncGetCapacity =10000。

  • 后台服務檢查可用性時

CheckAvailable 無法獲得資源,Pool: 0/10, Get Wait: 0, GetAsync Wait: 0


擴展現實

SQLServer連接池

查看源碼

var pool = new System.Data.SqlClient.SqlConnectionPool("名稱", connectionString, 可用時觸發的委托, 不可用時觸發的委托);
var conn = pool.Get();

try {
	// 使用 ...
	pool.Return(conn); //正常歸還
} catch (Exception ex) {
	pool.Return(conn, ex); //發生錯誤時歸還
}

MySQL連接池

查看源碼

var pool = new MySql.Data.MySqlClient.MySqlConnectionPool("名稱", connectionString, 可用時觸發的委托, 不可用時觸發的委托);
var conn = pool.Get();

try {
	// 使用 ...
	pool.Return(conn); //正常歸還
} catch (Exception ex) {
	pool.Return(conn, ex); //發生錯誤時歸還
}

PostgreSQL連接池

查看源碼

var pool = new Npgsql.NpgsqlConnectionPool("名稱", connectionString, 可用時觸發的委托, 不可用時觸發的委托);
var conn = pool.Get();

try {
	// 使用 ...
	pool.Return(conn); //正常歸還
} catch (Exception ex) {
	pool.Return(conn, ex); //發生錯誤時歸還
}

結語

本文由 ado.net 連接池,衍生到 SafeObjectPool,基於 SafeObjectPool 現實了 SQLServer連接池、MySQL連接池、PostgreSQL連接池。還有很多連接對象,比如redis client、rpc client、各大消息隊列client,都可以封裝起來。

謝謝觀看,支持開源思想和奉獻。

SafeObjectPool github:https://github.com/2881099/SafeObjectPool


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM