具有持久 HTTP 连接的 IDbConnection 生命周期管理

     2023-04-12     205

关键词:

【中文标题】具有持久 HTTP 连接的 IDbConnection 生命周期管理【英文标题】:IDbConnection lifecycle management with persistent HTTP connections 【发布时间】:2012-10-28 15:19:28 【问题描述】:

当我的 ASP.NET MVC 应用程序(如 SignalR 集线器)中存在持久 HTTP 连接时,我在管理具有范围为 HttpContext 的 StructureMap 的打开数据库连接的生命周期时遇到问题。

我的 DI 容器 StructureMap 将打开的 IDbConnection 注入到多个服务中。为确保这些数据库连接已关闭并正确处理,我在 EndRequest 事件上调用 ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()

这对 MVC 控制器非常有用,直到需要数据库连接的服务被注入到 SignalR 集线器中,该集线器为每个客户端保持持久的 HTTP 连接打开并最终使连接池饱和。

如果我将IDbConnection 限定为单例,则每个应用程序只会打开一个连接并且池不会饱和,但这是a bad idea,以防连接被锁定或超时。

那么也许有一种方法可以为我的 SignalR 集线器自定义数据库连接的范围?我尝试在每个 Hub 方法中解析一个服务实例,但这仍然会在 HttpContext 范围内实例化一个数据库连接,并在调用客户端的集线器连接期间保持打开状态。

当周围有持久的 HTTP 连接时,我应该如何在 HTTP 范围的上下文中使用 StructureMap 管理数据库连接的生命周期?

示例代码

典型服务

public class MyService

    private IDbConnection _con;
    public MyService(IDbConnection con)
    
        _con = con;
    

    public IEnumerable<string> GetStuff()
    
        return _con.Select<string>("SELECT someString FROM SomeTable").ToList();
    

典型的 SignalR 集线器

public class MyHub : Hub

    private MyService _service;
    public MyHub(MyService service)
    
        _service = service; // Oh Noes! This will open a database connection
                            // for each Client because of HttpContext scope
    

    public Task AddMessage()
    
        var result = _service.GetStuff();
        // ...
    

结构图配置

For<IDbConnection>()
    .HybridHttpOrThreadLocalScoped()
    .Use(() => BaseController.GetOpenConnection(MyConnectionString));

Global.asax.cs

public class GlobalApplication : System.Web.HttpApplication

    public GlobalApplication()
    
        EndRequest += delegate
        
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        ;
    
    // ...
 

【问题讨论】:

在每个集线器方法上创建您的服务是一个解决方案吗?没有足够的信息来回答。 SignalR 将管理多少客户?他们多久通信/调用一次服务器方法? 嘿@VladCiobanu,我用关于在每个集线器方法中解析服务实例的注释更新了我的问题。对于这个特定的应用程序,SignalR 管理大约 10-40 个持久客户端(目前),但是如果负载在高峰时间翻倍,这很容易使连接池最大化。我希望对我的问题有一个规范的答案。 我想我已经解决了这个问题,方法是使用GetNestedContainer() 来显式处理服务并打开它使用的连接,从而解决每个 SignalR 集线器方法中的服务实例。 不,看起来嵌套容器只显式处理瞬态实例,而IDbConnection 不能是瞬态的,因为服务层中的 LINQ 查询实现。 已使用瞬态 IDbConnection 的命名实例解决!很快就会发布答案。 【参考方案1】:

在 SignalR 1.0.0 Alpha 中,Hub 的实现 IDisposable。 SignalR Hub 实例与HttpContext 不同,它是短暂的,因此如果您在HubDispose 方法中关闭您的IDbConnection,您不应该不必要地使您的连接池饱和。

【讨论】:

谢谢@halter73。默认注入的IDbConnection 实例的范围为HttpContext,如果集线器关闭它会影响其他服务。我的解决方案是使用IDbConnection 的瞬态命名实例,该实例在每个 SignalR 方法的嵌套 StructureMap 容器中解析和处置。我不确定这是否是最好的方法,但它可以确保我的连接池永远不会饱和。 这绝对不是最好的方法。当您使用 websockets 时,每次调用都会获得一个集线器实例,但需要一个长时间运行的 http 请求。所以你会泄漏。 用我的解决方案查看新答案,@dfowler。【参考方案2】:

使用临时数据库连接和嵌套 StructureMap 容器的解决方案

首先,在 StructureMap 中配置一个命名的临时数据库连接实例:

For<IDbConnection>()
    .Transient() // scope
    .Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging()))
    .Named("Transient");

确保在您的默认实例之前配置此,否则它将覆盖默认实例。

其次,将IContainer 注入您的 SignalR 集线器,以便您可以构建嵌套的 StructureMap 容器:

public class JobHub : Hub

    private readonly IContainer _container;

    public JobHub(IContainer container)
    
        _container = container;
    

    public Task DoStuff(string input)
    
        // ...

在您的 SignalR 方法中实例化一个嵌套容器并解析您命名的临时数据库连接:

        using (var httpRequestScope = _container.GetNestedContainer())
        
            var transientConnection =
                    httpRequestScope.GetInstance<IDbConnection>("Transient");

使用.With&lt;IDbConnection&gt;(transientConnection) 确保嵌套容器实例化的服务和存储库使用此连接:

            var myService = httpRequestScope
                .With<IDbConnection>(transientConnection)
                .GetInstance<MyService>();

            var result = myService.DoStuff(input);

            return Clients.addResult(result);
        
    

最后,作用域using (...) 语句将确保您的嵌套容器自行清理,包括数据库连接。

这里的缺点是您为每个 SignalR 方法调用打开和关闭数据库连接,但由于连接是池化的,因此提前释放可能不是那么糟糕。您的里程数应取决于您的 SignalR 请求量。

您也许可以放弃嵌套容器,只需向DependencyResolver.Current 询问命名的连接实例,但您可能必须记住显式关闭每个连接以防止泄漏。

【讨论】:

来自 Java 服务器的持久 http 连接

...和Android客户端之间创建一个持久连接。我需要的是一种具有持久(长期HTTP)连接的推送机制,一旦可用,它会将所有信息从服务器流式传输到客户端。是否有任何可用的框架支持这一点,最好是JavaSpring。将帮助我 查看详情

具有持久性的 HTTP POST 请求的非阻塞队列

】具有持久性的HTTPPOST请求的非阻塞队列【英文标题】:Non-blockingqueueofHTTPPOSTrequestswithpersistence【发布时间】:2012-07-1912:24:11【问题描述】:在我们开发自定义解决方案之前,我正在寻找某种库,它提供:HTTP请求的非阻塞队列具... 查看详情

具有持久连接的 PHP PDO dblib (mssql) 不起作用

】具有持久连接的PHPPDOdblib(mssql)不起作用【英文标题】:PHPPDOdblib(mssql)withpersistentconnectionsnotworking【发布时间】:2015-12-0416:04:02【问题描述】:按照在线示例和PDO文档,我有这一行用于使用持久连接创建PDO对象:$p=newPDO(\'dblib:host... 查看详情

java创建HTTP持久连接

】java创建HTTP持久连接【英文标题】:javacreateHTTPpersistentconnection【发布时间】:2012-05-1111:20:39【问题描述】:我正在尝试编写一个java程序,它会自动下载并命名一些我最喜欢的网络漫画。由于我将从同一个域请求多个对象,因... 查看详情

http协议学习笔记---http持久连接和如何正确地关闭http连接

一,持久连接什么是持久连接?对于HTTP协议而言,它是基于请求响应模型,Client向Server发请求时,先建立一条HTTP连接,Server给Client响应数据后,连接关闭。当Client发送下一个请求时,需要重新再建立HTTP连接,这种方式就是:一... 查看详情

【小白学爬虫笔记】持久连接、非持久连接

...正的并发请求,降低延时,提高了带宽的利用率。 在持久连接或者HTTPpipelining出现之前,每个连接的获取都需要创建一个独立的TCP连接。2. 非持久连接示意每个WEB对象都要建立新的连接。假设某简单页面包含1个HTML,2个PN... 查看详情

与没有 GCM 的推送服务器的持久 http 连接

】与没有GCM的推送服务器的持久http连接【英文标题】:persistanthttpconnectiontoapushserverwithoutGCM【发布时间】:2014-10-3112:17:11【问题描述】:问题很简单:连接到HTTP服务器并保持连接打开几分钟。每次接收数据时触发回调函数,而... 查看详情

面试题:每发送一个http请求就要建立一个tcp连接吗(非持久连接/持久连接)

文章目录一、非持久连接和持久连接二、TCP连接中多个HTTP请求可以并行发送吗?三、一个TCP连接可以发送多少个HTTP请求问题?一、非持久连接和持久连接非持久连接:HTTP/1.0中的首部字段Connection默认值为close,即... 查看详情

Web 服务器 HTTP1.1 上的持久连接

】Web服务器HTTP1.1上的持久连接【英文标题】:PersistentConnectiononawebserverHTTP1.1【发布时间】:2013-06-2116:54:50【问题描述】:我正在尝试使用协议HTTP1.1在Linux下用C语言编写Web服务器。我已经为多个请求使用了select,并且我想实现持... 查看详情

与 TCPServer 保持另一个持久的 TCP 连接

】与TCPServer保持另一个持久的TCP连接【英文标题】:MaintaininganotherpersistentTCPconnectionwithTCPServer【发布时间】:2019-05-1311:33:02【问题描述】:我正在使用slixmpp连接到XMPP服务器,我需要在提供HTTP协议时访问此连接,我试图保持持久... 查看详情

http1.0和http1.1以及http2.0的区别

HTTP1.0和HTTP1.1区别版本HTTP1.0HTTP1.1连接方面使用非持久连接,即在非持久连接下,一个tcp连接只传输一个web对象。每次请求和响应都需要建立一个单独的连接,每次连接只是传输一个对象,严重影响客户机和服务器的性能默认使... 查看详情

[日常]http连接管理

...串行化的时延并行连接:多条TCP连接发起并发的HTTP请求持久连接:重用TCP连接,消除连接和关闭时延管道化连接:通过并发的TCP连接发起并发的HTTP请求3.打开少量的并行连接,每一个连接都是持久连接HTTP/1.0 查看详情

http/1.1"persistent"连接

...接(1)HTTP/1.1逐渐停止了对keep-alive连接的支持,用一种名为持久连接(persistentconnection)的改进型设计取代了它,持久连接的目的与keep-alive连接的目的相同,但工作机制更优一些。(2)HTTP/1.1持久连接默认是激活的,应用程序必须添... 查看详情

http协议入门

简单的HTTP协议持久连接在HTTP/1.1中,所有的连接默认都是持久连接。管线化持久连接使得多数请求以管线化(pipelining)方式发送成为可能。以前发送请求后需要等待并受到响应,才能发送下一个请求。Cookie响应报文中,Set-Cookie... 查看详情

持久的数据库连接——是还是否?

...行数据访问,我一直在阅读它,发现它对持久数据库连接具有良好的先天支持。我想知道何时/是否应该使用它们。我会在重CRUD的应用程序中看到性能优势吗?是否有缺点需要考虑,可能与安全性有关?如果这对你很重要 查看详情

有关[http持久连接]的一切,卷给你看(代码片段)

...TPKeep-Alive,今天我们从底层TCP连接和排障角度撕碎HTTP持久连接。“我只是一个写web程序的猿,我为什么要知道这么多😂😂😂”。使用go语言倒腾一个httpServer/httpClient,粗略聊一聊go的使用风格。使用go语... 查看详情

计算机网络原理-3

...往返时间HTTP连接分类根据使用TCP连接的策略不同:分为非持久连接的HTTP,和持久连接的HTTP.HTTP报文请求报文:起始行是请求行:<URL>HTTP请求方法get:请求读取,最常见.post,head,option,putsmtp通过三个阶段交互完成邮件传输:握手阶段,邮... 查看详情

websocket是什么原理?为什么可以实现持久连接?(代码片段)

...HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个࿰ 查看详情