gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 11:21:15 26 4
gpt4 key购买 nike

设置

我有一个通过 REST 接口(interface)获取输入的网络服务。 REST 调用不返回任何有意义的数据,因此传递到 Web 服务的任何内容都只记录在数据库中,仅此而已。这是一项分析服务,我的公司在内部使用它来对在其网页上收到的网络请求进行一些特殊处理。因此,响应尽可能短的返回时间非常重要。

我已经尽可能地优化了代码,以使响应尽可能快。但是,数据库保持打开状态的时间仍然使连接打开的时间比我想要的要长,然后才会将响应发送回 Web 客户端。

代码基本上是这样的,顺便说一句,它是 ASP.NET MVC,使用 Entity Framework ,在 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 block 中,以使数据库插入异步,但不知道这是否是将响应释放回客户。

如果您要实现这个目标,您会推荐什么?

最佳答案

如果请求必须可靠,那么您需要将其写入数据库。例如。如果您的返回意味着“我已经向商家付款”,那么在您实际提交到数据库之前您不能返回。如果处理时间很长,则有基于数据库的异步模式,使用表作为队列或使用内置队列,如 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 处理程序线程以尽快返回响应。但它有一些缺点:

  • 如果请求的传入速率超过线程池处理速率,则内存队列将增长,直到它触发应用程序池“回收”,从而丢失所有“进行中”的项目(以及热缓存和其他好东西).
  • 请求的顺序没有保留(可能重要也可能不重要)
  • 它消耗一个 CLR 池线程,除了等待来自 DB 的响应之外什么都不做

最后一个问题可以通过使用真正的异步数据库调用来解决,通过 SqlCommand.BeginExecuteXXX并设置 AsynchronousProcessing关于与真实的联系。不幸的是,AFAIK EF 还没有真正的异步执行,因此您必须求助于 SqlClient 层(SqlConnection、SqlCommand)。但此解决方案无法解决第一个问题,因为页面点击率如此之高以至于此日志记录(= 在每次页面点击时写入)成为关键瓶颈。

如果第一个问题是真实的,那么没有线程和/或生产者/消费者魔法可以减轻它。如果您真的有传入率与写入率可伸缩性问题(“待定”队列在内存中增长),则必须使 DB 层中的写入速度更快(更快的 IO、特殊的日志刷新 IO)和/或您必须聚合写的。无需记录每个请求,只需增加内存计数器并定期将它们作为聚合写入。

关于sql-server - 如何最好地卸载数据库插入,以便更快地返回 Web 响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1876457/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com