Проблемы с соединением MongoDB на Azure

У нас есть приложение ASP.NET MVC, развернутое на Azure Website, который подключается к MongoDB и выполняет операции чтения и записи. Приложение делает это итеративно. Несколько тысяч раз в минуту.

Мы инициализируем драйвер С# с помощью Autofac, и мы устанавливаем MaxConnectionIdleTime на 45 секунд, как предлагается в https://groups.google.com/forum/#!topic/mongodb-user/_Z8YepNHnbI и в нескольких других местах.

Мы все еще получаем большое количество ошибок ниже:

Невозможно прочитать данные из транспортного соединения: соединение попытка не удалась, потому что связанная сторона неправильно ответила после определенного периода времени, или установленное соединение не выполнено, потому что подключенный хост не смог ответить. метод Сообщение: ": {" ClassName ":" System.IO.IOException "," Сообщение ":" Невозможно чтение данных из транспортного соединения: попытка подключения не выполнена потому что связанная сторона не отвечала должным образом после периода времени или установленного соединения, поскольку подключенный хост не удалось ответить.

Мы получаем эту ошибку при подключении к экземпляру MongoDB, развернутому на виртуальной машине в одном и том же центре данных/области на Azure, а также при подключении к внешнему провайдеру PaaS MongoDB.

Я запускаю тот же код на своем локальном компьютере и подключаюсь к той же БД, и я не получаю эти ошибки. Это только при развертывании кода на Azure Website. Любые предложения?

Ответ 1

Несколько тысяч запросов в минуту - это большая загрузка, и единственный способ сделать это правильно - это контролировать и ограничивать максимальное количество потоков, которые могут быть запущены в любой момент времени.

Как не так много информации о том, как вы это сделали. Я собираюсь прикрыть несколько возможных обстоятельств.


Время эксперимента...

Константы:

  • Элементы для обработки:
    • 50 в секунду, или другими словами...
    • 3000 в минуту и ​​еще один способ взглянуть на него...
    • 180 000 в час

Переменные:

  • Скорость передачи данных:

    • Сколько данных, которые вы можете перенести в секунду, будет играть роль независимо от того, что мы делаем, и это будет меняться в течение дня в зависимости от времени суток.

      Единственное, что мы можем сделать, это слить больше запросов с разных процессоров, чтобы распределить вес трафика, который мы отправляем обратно.

  • Мощность обработки:

    • Я предполагаю, что у вас есть это в WebJob, а не на том, что это закодировано внутри сайта MVC. Он очень неэффективен и не подходит для цели, которую вы пытаетесь достичь. Используя WebJob, мы можем поставить в очередь рабочие элементы, которые будут обрабатываться другими WebJobs. В очереди находится Azure Queue Storage.

      Хранилище очереди Azure - это служба для хранения большого количества сообщений к которым можно получить доступ из любой точки мира посредством аутентификации звонки с использованием HTTP или HTTPS. Одно сообщение о очереди может быть до 64 КБ в размере, и очередь может содержать миллионы сообщений, вплоть до общей суммы ограничение емкости учетной записи хранения. Аккаунт хранилища может содержать до 200 ТБ данных blob, queue и table. См. Лазурное хранилище Масштабируемость и целевые показатели производительности для получения подробной информации об учетной записи хранилища емкость.

      Общее использование хранилища очереди включает:

      • Создание отставания в работе для асинхронного процесса
      • Передача сообщений с роли Azure Web в роль Azure Worker

Проблемы:

  • Мы пытаемся выполнить 50 транзакций в секунду, поэтому каждая транзакция должна выполняться менее чем за 1 секунду, если мы используем 50 потоков. Наш 45-й тайм-аут не имеет никакой цели на данный момент.
  • Мы ожидаем, что 50 потоков будут выполняться одновременно, и все будет выполнено через секунду, каждую секунду, на одном процессоре. (Я преувеличиваю точку здесь, просто чтобы понять... но представьте, что вы загружаете 50 текстовых файлов каждую секунду. Обработайте ее, а затем попытайтесь отдать ее обратно коллеге в надежде, что они даже будут готовы к поймать его)
  • Нам нужно иметь логику повтора, если после трех попыток элемент не обрабатывается, их нужно поместить обратно в очередь. В идеале мы должны уделять больше времени серверу, чтобы ответить, чем одна секунда с каждой неудачей, скажем, что мы дали ему 2-секундный перерыв при первом провале, затем 4 секунды, затем 10, это значительно увеличит шансы на то, что мы продолжим/получение необходимых нам данных.
  • Мы полагаем, что наш MongoDb может обрабатывать это количество запросов в секунду. Если вы еще этого не сделали, начните смотреть на способы его масштабирования, проблема заключается не в том, что это MongoDb, слой данных мог быть чем угодно, это тот факт, что мы делаем это количество запросов от единственный источник, который будет наиболее вероятной причиной ваших проблем.

Решение:

  • Настройте WebJob и назовите его EnqueueJob. Этот WebJob будет иметь одну единственную цель - поставить в очередь элементы работы, которые будут выполняться в Queue Storage.
  • Создайте Queue Storage Container с именем WorkItemQueue, эта очередь будет действовать как триггер следующего шага и начнет выполнять операции масштабирования.
  • Создайте еще один WebJob с именем DequeueJob. Этот WebJob также будет иметь одну единственную цель - отключить рабочие элементы из WorkItemQueue и запустить запросы в хранилище данных.
  • Сконфигурируйте DequeueJob, чтобы разворачиваться, как только элемент был помещен внутри WorkItemQueue, запустите по 5 отдельных потоков на каждом и пока очередь не пуста, деактивируйте рабочие элементы для каждого потока и попытайтесь выполнить заданное задание,
    • Попытка 1, если вы не можете, подождите и повторите попытку.
    • Попытка 2, если вы не можете, подождите и повторите попытку.
    • Попытка 3, если не удается, вернуть объект обратно в WorkItemQueue
  • Настройте свой веб-сайт на автоматическое масштабирование до x объема процессора (обратите внимание, что ваш веб-сайт и веб-задания имеют одни и те же ресурсы).

Вот короткое 10-минутное видео, в котором дается обзор использования хранилищ очередей и веб-заданий.


Edit:

Другая причина, по которой вы можете получить эти ошибки, может быть связана с двумя другими факторами, опять-таки вызванными тем, что она находится в приложении MVC...

Если вы компилируете приложение с приложенным атрибутом DEBUG, но вместо этого нажимаете версию RELEASE, вы можете столкнуться с проблемами из-за настроек в вашем web.config, без атрибута DEBUG, Веб-приложение ASP.NET выполнит запрос в течение не более 90 секунд, если запрос займет больше времени, он избавится от запроса.

Чтобы увеличить тайм-аут дольше, чем 90 секунд, вам нужно будет изменить свойство [httpRuntime][3] в web.config...

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

Другая вещь, о которой вам нужно знать, - это настройки тайм-аута запроса вашего браузерa > веб-приложения, я бы сказал, что если вы настаиваете на сохранении кода в 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();
}

Ответ 2

Используете ли вы mongoDB в виртуальной машине? Кажется, это проблема сети. Должны возникать такие кратковременные сбои, так что лучше всего вы можете реализовать шаблон повтора или использовать lib, например Polly, для этого:

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

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