在执行长时间运行的数据库任务时处理Web服务超时
我们的产品之一的架构是典型的3层解决方案:
- C#客户端
- WCF Web服务
- SQL Server数据库
客户端从Web服务请求信息。 Web服务命中数据库以获取信息并将其返回给客户端。
这是问题所在。 其中一些查询可能需要很长时间,而且我们不知道哪些查询会很慢。 我们知道一些通常比其他人慢,但即使是最简单的请求,如果有足够的数据,也会很慢。 有时使用查询或运行大量数据的报告。 只有在大量数据减慢之前,才能优化查询。
如果数据库中的查询在SQL Server中达到最大查询超时,则数据库查询将终止,并且Web服务会向客户端返回错误。 这是理解的。 我们可以处理这些错误。
客户端正在等待Web服务调用完成。 如果数据库调用需要很长时间,则客户端可能会在调用Web服务时超时。 客户端放弃,但数据库请求继续处理。 此时,客户端与数据库不同步。 数据库调用可能成功也可能不成功。 可能有错误。 客户永远不会知道。 在某些情况下,我们不希望我们的用户发起另一个请求,如果完成上一个请求,可能会导致无效状态。
我很想知道其他人是如何处理这个问题的。 您使用了哪些策略来防止Web服务超时影响数据库调用?
我能提出的最好的想法包括在某个地方创建一个实际的数据库层 – 在Web服务内部,附加到消息队列 – 某些东西。 将每个查询卸载到另一个进程似乎过多。 (然后,我们并不总是知道给定的请求是快还是慢。)
如果我们可以将发出HTTP请求的行为与启动和运行数据库进程的行为分开,那就太好了。 我已经在之前的公司看到过使用自定义服务器,但它使用的是直接套接字通信,而我宁愿避免使用某些自定义应用程序替换Web服务。
请注意,鉴于我们处理的数据量,我们都在进行查询优化。 查询优化,索引等只会在数据量很大时才将您带到目前为止。 有时事情需要很长时间。
我以前遇到过类似的问题,并使用以下3种方法之一来解决它:
- 将所有长时间运行的查询添加到队列中,并按顺序处理它们。
在我的情况下,这些都是复杂的报告,然后通过电子邮件发送给客户,或者存储在永久的“临时”表中,供客户在收到通知后查看。 - 我们使用JQuery调用调用了一个web服务,然后在完成时调用了一个javascript回发方法。
当我们不想让页面加载与Web服务正在执行的操作同步时,这很有效。
但是,它确实意味着在长时间运行的过程完成之前,该function不可用。 - 最复杂的一个。
我们弹出另一个显示进度条的窗口,该窗口还定期轮询服务器。
这使用会话变量来确定显示进度条的距离。
启动进度条后,启动了一个新线程,它定期更新同一个会话变量。
会话变量值设置为100后,弹出窗口将自行关闭。
客户喜欢这种方法。
无论如何,我希望其中一个对你有所帮助。
Web服务可以在线程池中运行查询,如果线程没有完成,比如5秒(参见Thread.Join()),Web服务调用会返回客户端JobID而不是客户端可以的结果集用于每隔几秒轮询服务器以查看其查询是否已完成。 当线程完成时,结果可以存储在哈希表中,直到客户端再次轮询。
我们最近使用的解决方案之一是将大型数据库进程分解为单独的并行操作。 每个操作都要小得多,并且设计得尽可能高效。 客户端启动操作,生成几个线程,并且可以并行执行任何操作。
例如,我们将一些重要的过程拆分为一系列步骤,如“开始”,“处理1工作块”,“完成”和“收集报告数据”。 Process Work步骤可以并行运行,但在Start步骤完成之前无法启动。 完成步骤需要等待所有Process Work步骤完成。
由于客户端正在控制流程,因此客户端可以报告其确切步骤的进度。
把问题分解成小块肯定是个好主意。
除了那个以及其他人所说的(并且只有你在webservice的实现上有所帮助)我一直在使用传递给webservice的回调url。 WS必须使用错误调用它或者生成查询字符串或发布数据。
URL通常包含一个令牌,用于允许回调重新进入客户端,并映射到接收回调(存储在数据库或内存中)后执行操作所需的任何相关信息。
它有点沉重(特别是如果你没有在webserver中运行)但是在客户端超时的情况下保证成功的往返但是webservice正确接收了指令并且处理速度很慢。
一旦设置完毕,您的Web服务实际上更接近于准备异步运行并因此快速回复客户端:通常,如果可以,则执行任何检查以回答,并在单独的循环上生成慢速操作,回调url,以便它可以向客户端报告。
我不确定这是多么正统,BTW,但确实解决了实际问题。