使用 ElasticContext EF 进行连接池管理

Connection Pool Management with ElasticContext EF

在遵循 Microsoft 的一些示例之后,我实现了 DbContext 的弹性版本,它根据当前用户的租户(或客户)Id 从 Elastic ShardMapManager 获取其连接字符串。

这在技术上可行,我已将其部署到我的 Azure 帐户。我现在关心的是连接池管理,因为我已经覆盖了默认的上下文连接创建机制。此外,我不确定每次调用 shardMap.OpenConnectionForKey 时如何管理连接(请参阅下面的 ninject 设置)。

昨天,在一些 light 测试后,我的网络应用程序失败并显示以下消息:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.`

这可能是一次性的,因为我今天无法重新创建它但是我想确保连接池被有效地使用作为最后一件事我想要的是当真正的用户开始攻击系统时发生的事情。

它失败的代码在我的 ElasticScaleContext 的完整代码中注释如下:

public class ElasticScaleContext<T> : DbContext
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="shardMapManager">This is injected - only one of these exists per Application (Singleton)</param>
    /// <param name="customerId">The Shard Key is the Customer Id</param>
    /// <param name="shardConnectionString">The connection string for the Shard - this should only have the credentials and NOT any datasource. The correct datasource and initial catalog are returned by the Shard Map</param>
    /// <param name="metadataWorkSpaceConnectionString">Metadata required by EF model first cannot be passed in the shard connection string, it is passed here and used to return the MetadataWorkspace - no actual connection is created</param>
    public ElasticScaleContext(ShardMapManager shardMapManager, IPrincipal user, string shardConnectionString, string metadataWorkSpaceConnectionString)
      : base(CreateEntityConnection(shardMapManager, user, shardConnectionString, metadataWorkSpaceConnectionString), true)
    {
    }

    private static DbConnection CreateEntityConnection(ShardMapManager shardMapManager, IPrincipal user, string shardConnectionString, string metadataWorkSpaceConnectionString)
    {

        int shardKey = 0; // Default just to get a valid connection string on login page (it's never actually used)

        if (user != null && user.Identity.IsAuthenticated)
        {
            shardKey = user.Identity.GetCustomerId();
        }

        // Loads the Shard Map from the Shard Manager
        // This has the details of which shards are located on which databases
        ListShardMap<T> shardMap = shardMapManager.GetListShardMap<T>(AppConfig.ShardMapName);

        // No initialization
        Database.SetInitializer<ElasticScaleContext<T>>(null);

        // Create Elastic Scale SqlConnection
        // ******* FAILED HERE *********
        var shardConnection = shardMap.OpenConnectionForKey(shardKey, shardConnectionString, ConnectionOptions.None);

        // Allocate metadata workspace via an EF connection 
        var efConnection = new EntityConnection(metadataWorkSpaceConnectionString);

        // Create Entity connection that holds the sharded SqlConnection and metadata workspace
        var workspace = efConnection.GetMetadataWorkspace();
        EntityConnection entcon = new EntityConnection(workspace, shardConnection);

        return entcon;

    }

}

我正在使用 Ninject 并将 ShardMapManager 作为单例注入:

// Only ever create one Shard Map Manager
kernel.Bind<ShardMapManager>().ToMethod(context =>
{
   return ShardMapManagerFactory.GetSqlShardMapManager(AppConfig.ConnectionString, ShardMapManagerLoadPolicy.Lazy);
}).InSingletonScope();

并且根据请求创建上下文:

kernel.Bind<DbContext>().ToMethod(ctx =>
{
   return new ElasticScaleContext<int>(kernel.Get<ShardMapManager>(), kernel.Get<IPrincipal>(), AppConfig.BaseConnectionString, AppConfig.SCSMetaDataConnectionString);
}}).InRequestScope();

所以有几个问题:

  1. Should the Connection I am creating within the Context be disposed off as normal?

  2. Does anyone know how the ShardMapManger connections are managed?

  3. Could the code below (necessary because of my Model First EF approach) be opening and then not closing connections?

UPDATE - 根据@Evk 的建议(见评论),我修改了对 EntityConnection 的构造函数调用,为 entityConnectionOwnsStoreConnection 传递 true,这应该允许它正确关闭使用后的商店连接,见下文。我真的需要一种监视连接池的方法,看看这是否有任何效果:

 var efConnection = new EntityConnection(metadataWorkSpaceConnectionString);

  // Create Entity connection that holds the sharded SqlConnection and metadata workspace
  var workspace = efConnection.GetMetadataWorkspace();
  EntityConnection entcon = new EntityConnection(workspace, shardConnection. true);

Finally, is there any way for me to monitor and view the current status of the connections on an Azure Elastic SQL Pool?

我知道有很多问题,但我正在寻找有关这方面的任何信息 - 网络上确实没有那么多现有信息。

Additional Info: The solution uses EF6, SQL Server 2014, MVC 5.0

如评论中所述,在 CreateEntityConnection 方法中,您从底层连接创建 EntityConnection,但不要将重要参数 "entityConnectionOwnsStoreConnection" 设置为 true。这意味着实体连接不负责管理您的商店连接并且不会关闭它,因此您的连接将会泄漏。要修复,请使用另一个 EntityConnection 构造函数:

var entcon = new EntityConnection(workspace, shardConnection, true);

然后,当上下文被释放时,它会释放你的 EntityConnection,这反过来会释放底层数据库连接。