概述
為何要池化RabbitMq的連接?這就涉及到了兩個基本的RabbitMq概念:Connection
和Channel
。
Connection
Connection對象,就是一個TCP連接對象。
Channel
虛擬連接。虛擬連接建立在上面Connection對象的TCP連接中。數據流動都是在Channel中進行的。每個Connection對象的虛擬連接也是有限的,如果單個Connnection的Channel對象超出指定范圍了,也會有性能問題,另外一個TCP連接上的多個虛擬連接,實際在傳輸數據時,傳輸數據的虛擬連接還是獨占了TCP連接,其它虛擬連接在排隊等待。
池化設計
參考線程池、DB連接池的設計,同樣抽象一個池化對象來管理Connection以及Channel兩個對象,回收復用連接。
實現落地
ObjectPool實現
其實是基於微軟官方實現的池擴展庫來做的,描述請見 ObjectPool對象池設計模式。
具體實現見 Publishing RabbitMQ Message In ASP.NET Core
代碼請見 https://github.com/anehir/PooledRabbitClient
ABP中的IConnectionPool
在ABP的Volo.Abp.RabbitMQ庫中也實現了IConnection以及IChannel兩者的池化管理。
在ABP中,通過一個簡單的並發字典來緩存已有的RabbitMq連接,如果連接有的話,就直接返回否則就創建。
GetOrAdd方法並不是線程安全的,但如果是基於lazy來實現則是線程安全。

var lazyConnection = Connections.GetOrAdd( connectionName, () => new Lazy<IConnection>(() => { var connection = Options.Connections.GetOrDefault(connectionName); var hostnames = connection.HostName.TrimEnd(';').Split(';'); // Handle Rabbit MQ Cluster. return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames); }) ); return lazyConnection.Value;