【问题标题】:MongoDB connection problems on AzureAzure 上的 MongoDB 连接问题
【发布时间】:2015-04-26 01:56:31
【问题描述】:

我们有一个 ASP.NET MVC 应用程序部署到连接到 MongoDB 并执行读写操作的 Azure 网站。应用程序迭代地执行此操作。每分钟几千次。

我们使用 Autofac 初始化 C# 驱动程序,并将 MaxConnectionIdleTime 设置为 45 秒,如 https://groups.google.com/forum/#!topic/mongodb-user/_Z8YepNHnbI 和其他一些地方所建议的那样。

我们仍然收到大量以下错误:

无法从传输连接中读取数据:连接 尝试失败,因为连接方没有正确响应 一段时间后,或建立连接失败,因为 连接的主机未能响应。方法 消息:":{"ClassName":"System.IO.IOException","Message":"无法 从传输连接读取数据:连接尝试失败 因为连接方在一段时间后没有正确响应 时间,或建立连接失败,因为连接的主机有 没有回应。

在连接到部署在 Azure 上同一数据中心/区域的 VM 上的 MongoDB 实例以及连接到外部 PaaS MongoDB 提供程序时,我们会收到此错误。

我在本地计算机上运行相同的代码并连接到相同的数据库,但没有收到这些错误。只有当我将代码部署到 Azure 网站时。 有什么建议吗?

【问题讨论】:

  • 您的服务器似乎没有连接?
  • 我喜欢比特币...但是否允许在问题上设置 BTC 赏金?
  • 你每分钟打开一个到 MongoDB 服务器的新连接几千次?我没看错吗?
  • 你能发布异常的整个堆栈跟踪吗?
  • @MattJohnson 没问题。我以为它会被删除。但是您的参考资料是关于使此功能成为 SO 而不是 SO 规则的功能。拒绝功能请求并不意味着不允许手动执行此操作。可以?我在网站的 Ts&Cs 上看不到它,但我也没有看得太深。介意提供参考吗?

标签: c# mongodb azure


【解决方案1】:

每分钟几千个请求是一个负载,唯一正确的方法是控制和限制任何时候可以运行的最大线程数。

由于没有太多关于您如何实现此功能的信息发布。我将介绍几种可能的情况。


实验时间...

常量:

  • 要处理的项目:
    • 50 每秒,或者换句话说......
    • 3,000 每分钟,还有另一种查看方式...
    • 180,000 每小时

变量:

  • 数据传输率:

    • 无论我们做什么,您每秒可以传输多少数据都将发挥作用,这将在一天中根据一天中的时间而有所不同。

      我们唯一能做的就是从不同的 cpu 发出更多请求,以分配我们向后发送的流量的权重。

  • 处理能力:

    • 我假设您在 WebJob 中有这个,而不是在 MVC 站点中编码它本身。它效率极低,不适合您要达到的目的。通过使用 WebJob,我们可以 排队 工作项以由其他 WebJobs 处理。有问题的队列Azure Queue Storage

      Azure 队列存储是一种用于存储大量消息的服务 可以通过身份验证从世界任何地方访问 使用 HTTP 或 HTTPS 调用。单个队列消息最大为 64 KB 在大小上,一个队列可以包含数百万条消息,最多 存储帐户的容量限制。一个存储帐户可以包含最多 最多 200 TB 的 blob、队列和表数据。请参阅 Azure 存储 有关存储帐户的详细信息的可扩展性和性能目标 容量。

      队列存储的常见用途包括:

      • 创建工作积压以异步处理
      • 将消息从 Azure Web 角色传递到 Azure Worker 角色

问题:

  • 我们尝试每秒完成 50 个事务,因此如果我们使用 50 个线程,每个事务应该在 1 秒内完成。在这一点上,我们 45 秒的暂停没有任何意义。
  • 我们期望 50 个线程同时运行,并且在单个 CPU 上每秒都在不到一秒的时间内完成。 (我在这里夸大了一点,只是为了说明一点……但想象一下每秒下载 50 个文本文件。处理它,然后尝试将其发送给同事,希望他们甚至准备好抓住它)
  • 我们需要有一个重试逻辑,如果在 3 次尝试后项目没有得到处理,则需要将它们放回队列中。理想情况下,我们应该为服务器提供更多的时间来响应每个故障,而不是仅仅一秒钟,假设我们在第一次故障时给了它 2 秒的休息时间,然后是 4 秒,然后是 10 秒,这将大大增加我们坚持的几率/ 检索我们需要的数据。
  • 我们假设我们的 MongoDb 每秒可以处理此数量的请求。如果您还没有,请开始寻找扩展它的方法,问题不在于它是 MongoDb,数据层可能是任何东西,而是我们正在从最有可能导致问题的单一来源。

解决办法:

  1. 设置WebJob 并将其命名为EnqueueJob。这个WebJob 将有一个唯一目的,将要在Queue Storage 中处理的工作项排队。
  2. 创建一个名为WorkItemQueueQueue Storage Container,此队列将作为下一步的触发器并开始我们的横向扩展操作。
  3. 创建另一个名为DequeueJobWebJob。这个WebJob 也有一个唯一目的,即从WorkItemQueue 中取出工作项并将请求发送到您的数据存储。
  4. DequeueJob 配置为在将项目放入WorkItemQueue 后启动,在每个线程上启动5 个单独的线程,当队列不为空时,将每个线程的工作项出列并尝试执行出列作业.
    1. 尝试 1,如果失败,请等待并重试。
    2. 尝试 2,如果失败,请等待并重试。
    3. 尝试 3,如果失败,将项目排回WorkItemQueue
  5. 将您的网站配置为自动扩展到 x 数量的 cpu(请注意,您的网站和网络作业共享相同的资源)

Here's a short 10 minute video 概述了如何利用队列存储和网络作业。


编辑:

您可能会收到这些错误的另一个原因可能是其他两个因素,同样是由于它位于 MVC 应用程序中...

如果您在编译应用程序时应用了DEBUG 属性但推送的是RELEASE 版本,那么您可能会因为web.config 中的设置而遇到问题,而没有DEBUG 属性, ASP.NET Web 应用程序将运行一个请求最多 90 秒,如果请求时间超过此时间,它将处理该请求。

要将超时时间增加到超过 90 秒,您需要更改 web.config 中的 [httpRuntime][3] 属性...

<!-- Increase timeout to five minutes -->
<httpRuntime executionTimeout="300" />

您需要注意的另一件事是浏览器 > Web 应用程序的请求超时设置,我想说的是,如果您坚持将代码保留在 MVC 中,而不是将其提取并放入 WebJob ,然后您可以使用以下代码向您的网络应用发出请求并抵消请求的超时时间。

string html = string.Empty;
string uri = "http://google.com";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Timeout = TimeSpan.FromMinutes(5);

using (HttpWebResponse response = (HttpWebResonse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
    html = reader.ReadToEnd();
}

【讨论】:

  • 问题不在于限制。我在本地计算机上运行相同的代码并连接到相同的数据库,但没有收到这些错误。只有当我将代码部署到 Azure 网站时。
  • 在您的本地机器上,您是如何执行查询的?是在控制台应用程序中还是在 ASP.NET MVC 站点中
【解决方案2】:

您是否在虚拟机中使用 mongoDB?好像是网络问题。应该会发生这种暂时性故障,因此您可以做的最好的事情是实现重试模式或使用诸如 Polly 之类的库来做到这一点:

Policy
    .Handle<IOException>()
    .Retry(3, (exception, retryCount) =>
    {
        // do something 
    });

https://github.com/michael-wolfenden/Polly

【讨论】:

  • 我们在连接到 VM 上的 mongodb 实例以及连接到另一个数据中心的 PaaS mongo 提供程序时遇到这些错误
  • 如何在 MVC 应用程序中使用 mongodb 2.0 和 Polly?您是否必须将它包裹在每个调用中,或者它是否注入一些东西来处理所有套接字连接错误。
  • @runxc1BretFerrier 他已经在使用 mongo 并且收到了这些错误。 Polly 只会包装对 mongodb 客户端的调用。
  • 啊,我明白了,我使用了类似的代码,但是不必在每次调用中都包含一个库会非常方便
  • @runxc1BretFerrier 那么你只需要使用 try /catch 和 for。这是一个重试模式:msdn.microsoft.com/en-us/library/dn589788.aspx
猜你喜欢
  • 2021-02-09
  • 2023-02-01
  • 2016-10-14
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-22
相关资源
最近更新 更多