代码之家  ›  专栏  ›  技术社区  ›  Nick Berardi

如何最好地卸载数据库插入,以便更快地返回web响应?

  •  3
  • Nick Berardi  · 技术社区  · 16 年前

    安装程序

    代码基本上是这样的,顺便说一句,它是ASP.NET MVC,使用实体框架,在IIS 7上运行,如果这很重要的话。

    public ActionResult Add(/*..bunch of parameters..*/) {
    
        using (var db = new Entities()) {
            var log = new Log {
                // populate Log from parameters
            }
            db.AddToLogs(log);
            db.SaveChanges();
        }
    
        return File(pixelImage, "image/gif");
    }
    

    问题:

    是否有办法将数据库插入卸载到另一个进程中,以便几乎立即返回对客户端的响应?

    using 块,使数据库插入异步,但不知道这是否是将响应释放回客户端的最佳方法。

    如果你想实现这个目标,你会推荐什么?

    5 回复  |  直到 16 年前
        1
  •  3
  •   Remus Rusanu    16 年前

    如果请求必须可靠,则需要将其写入数据库。如果您的返回意味着“我已向商户付款”,那么在您在数据库中实际提交之前,您不能返回。如果处理时间长,则存在基于数据库的异步模式,使用表作为队列或使用内置队列,如 Asynchronous procedure execution . 但是,当需要进行繁重而冗长的处理时,而不是简单的日志插入时,这些方法适用。

    当您只想插入日志记录(访问者/url跟踪内容)时,最简单的解决方案是使用CLR的线程池,只需 queue the work ,例如:

    ...
    var log = new Log {// populate Log from parameters}
    ThreadPool.QueueUserWorkItem(stateInfo=>{
      var queueLog = stateInfo as Log;
      using (var db = new Entities()) 
      { 
         db.AddToLogs(queuedLog);
         db.SaveChanges(); 
      }
    }, log);
    ...
    

    这是快速而简单的,它释放了ASP处理程序线程以尽快返回响应。但它也有一些缺点:

    • 如果请求的输入速率超过线程池处理速率,则内存队列将增长,直到触发应用程序池“回收”,从而丢失所有“进行中”项目(以及热缓存和其他物品)。
    • 请求顺序未保留(可能重要,也可能不重要)

    SqlCommand.BeginExecuteXXX 以及设置 AsynchronousProcessing 关于与true的连接。不幸的是,AFAIK EF还没有真正的异步执行,因此您必须求助于SqlClient层(SqlConnection,SqlCommand)。但这种解决方案无法解决第一个问题,因为页面点击率太高,日志记录(即每次点击页面时写入)成为一个关键瓶颈。

        2
  •  1
  •   Nathan Wheeler    16 年前

    过去一年左右,我一直在研究多层解决方案,这些解决方案需要这种功能,而我就是这样做的。

    我有一个单身汉,负责在后台基于 ITask 接口。然后我就注册一个新的 使用我的singleton并将控制权从主线程传递回客户端。

        3
  •  1
  •   Will Hartung    16 年前

    创建一个监视全局内存队列的单独线程。让您的请求将其信息放在队列中并返回,然后线程将该项从队列中取出并将其发布到DB。

    在重载情况下,如果线程延迟请求,那么队列将增长。

    此外,如果您丢失了计算机,您将丢失所有未处理的队列条目。

        4
  •  0
  •   Shiraz Bhaiji    16 年前

    这取决于:当您返回到客户端时,是否需要100%确保数据存储在数据库中?

    以这种情况为例:

    • 请求进来了
    • 启动一个线程以保存到数据库
    • 响应被发送到客户端
    • 服务器崩溃

    您还需要通过启动新线程而不是保存到数据库来检查节省了多少毫秒。

    与节省响应时间相比,增加的复杂性和维护成本可能过高。而且响应时间的节省可能非常少,以至于不会被注意到。

        5
  •  0
  •   n8wrl    16 年前

    在我花费大量时间进行优化之前,我会确定时间的去向。像这样的连接具有显著的延迟开销(请检查 this 出局)。只是为了微笑,让你的服务成为NOP,看看它的表现如何。

    我还怀疑,如果你的局域网上的NOP性能好到可以忍受,那么在野外情况就不同了。

    推荐文章