Сервер отправил недопустимый одноразовый номер при выполнении нескольких быстрых подключений из драйвера C# - PullRequest
1 голос
/ 03 августа 2020

Недавно я добавил аутентификацию в свою базу данных разработки, аутентификацию по базе данных «admin» и использование комбинации имени пользователя и пароля в строке подключения, например, mongodb://username:password@server:27017. Почти сразу я начал видеть, что соединения не открываются, за исключением сообщения «Сервер отправил недопустимый одноразовый номер». Чтобы попытаться смягчить проблему, я посмотрел на время жизни моих объектов IMongoClient и перешел от создания множества таких объектов к использованию синглтона, внедренного в мои бизнес-службы с помощью библиотек Microsoft.Extensions.DependencyInjection. Это не решило проблему. Я установил MongoClient в моем Startup.cs, используя .AddSingleton<IMongoClient>(factory => new MongoClient(Configuration["Storage:MongoConnectionString"])). Я знаю, что строка подключения верна, поскольку она работает в MongoDB Compass, а также потому, что первая пара вызовов через драйвер работает успешно; проблема начинается, когда выполняется несколько одновременных вызовов.

Я использую MongoDB. NET драйвер, версия 2.11.0, под. NET Core 3.1.2. Проблема возникает в моей локальной среде с Windows 10, а также в моей промежуточной среде, работающей внутри Docker на VMware Photon.

В приложении есть два компонента, которые подключаются к MongoDB, оба из которых являются ASP. Net Основные приложения, одно из которых обслуживает API для интерактивного использования моего приложения, а другое запускает планировщик Quartz для фоновой обработки. Я использую MongoDB 4.4.0 Community внутри контейнера Docker.

Мои ссылки на включение драйвера:

<PackageReference Include="MongoDB.Bson" Version="2.11.0" />
<PackageReference Include="MongoDB.Driver" Version="2.11.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.11.0" />

Согласно этот пост в MongoDB Jira site Я не первый, кто столкнулся с этой проблемой. Матиас Лоренцен предположил в вопросе о Jira, что он уменьшил количество ошибок, с которыми он сталкивается, с помощью различных исправлений, включая воссоздание пользователя, использование SCRAM-SHA-1 и увеличение максимального количества подключений, разрешенных на сервере. После внесения этих изменений проблема все еще возникает у меня.

Я предполагаю, что проблема связана с потоковой передачей при использовании в сочетании с аутентификацией базы данных. По очевидным причинам я не могу использовать этот код в производственной среде, отключив аутентификацию, чтобы обойти проблему, и в равной степени использование синхронной модели вместо asyn c кажется контрпродуктивным. Какие шаги я могу предпринять, чтобы попытаться решить проблемы с аутентификацией? Вероятно, это ошибка драйвера Mon go C#, или я просто неправильно его использую? 1018 *

Изменить: Минимальный воспроизводимый пример по запросу:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;

namespace MongoDbIssueExample
{
    internal class Program
    {
        private static IServiceProvider services;

        private static IServiceProvider BuildDependencyInjector()
        {
            services = new ServiceCollection()
                .AddSingleton<TestThingsService>()
                .AddSingleton<IMongoClient>(factory => new MongoClient("mongodb://username:password@server:27017"))
                .BuildServiceProvider();

            return services;
        }

        private static async Task DoSeed()
        {
            var service = services.GetService<TestThingsService>();
            // Don't do these async as we'll never get any data in...
            service.CreateTestThings().Wait();
            service.CreateOtherTestThings().Wait();
        }

        private static async Task DoTest()
        {
            var service = services.GetService<TestThingsService>();

            var things = service.GetTestThings();
            var otherThings = service.GetOtherTestThings();

            Task.WaitAll(things, otherThings);
        }

        private static async Task Main(string[] args)
        {
            BuildDependencyInjector();

            await DoTest();
        }
    }

    public class TestThingsService
    {
        private readonly IMongoClient _client;
        private readonly IMongoDatabase _database;
        private readonly IMongoCollection<OtherTestThing> _otherTestThingsCollection;
        private readonly IMongoCollection<TestThing> _testThingsCollection;

        public TestThingsService(IMongoClient client)
        {
            _client = client;
            _database = _client.GetDatabase("Things");
            _testThingsCollection = _database.GetCollection<TestThing>("TestThings");
            _otherTestThingsCollection = _database.GetCollection<OtherTestThing>("OtherTestThings");
        }

        public async Task CreateOtherTestThings()
        {
            for (var item = 1; item <= 10000; item++)
            {
                var testThing = new OtherTestThing {Id = item, Name = $"Other thing no. {item}", WhenCreated = DateTime.UtcNow};
                await _otherTestThingsCollection.ReplaceOneAsync(f => f.Id == item, testThing, new ReplaceOptions {IsUpsert = true});
            }
        }

        public async Task CreateTestThings()
        {
            for (var item = 1; item <= 10000; item++)
            {
                var testThing = new TestThing {Id = item, Name = $"Thing no. {item}", WhenCreated = DateTime.UtcNow};
                await _testThingsCollection.ReplaceOneAsync(f => f.Id == item, testThing, new ReplaceOptions {IsUpsert = true});
            }
        }


        public async Task<List<OtherTestThing>> GetOtherTestThings()
        {
            return await _otherTestThingsCollection.Find(_ => true).ToListAsync();
        }

        public async Task<List<TestThing>> GetTestThings()
        {
            return await _testThingsCollection.Find(_ => true).ToListAsync();
        }
    }

    public class OtherTestThing
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime WhenCreated { get; set; }
    }

    public class TestThing
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime WhenCreated { get; set; }
    }
}

Требуются следующие ссылки:

        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" />
        <PackageReference Include="MongoDB.Bson" Version="2.11.0" />
        <PackageReference Include="MongoDB.Driver" Version="2.11.0" />
        <PackageReference Include="MongoDB.Driver.Core" Version="2.11.0" />

Ответы [ 2 ]

1 голос
/ 04 сентября 2020

Недавно я тоже столкнулся с этой проблемой и смог использовать ваш тестовый код для локального воспроизведения проблемы. Я отладил драйвер mon go c# и обнаружил, что проблема связана с состоянием гонки, используя функцию, предназначенную для совмещения части протокола аутентификации с запросом начального обнаружения сервера (isMaster) - часть этого состояния аутентификации оказывается хранится в глобальном объекте аутентификатора, и несколько одновременных запросов аутентификации используют последнее увиденное состояние, что означает, что один запрос видит одноразовый номер, сгенерированный для другого запроса, который не соответствует ответу сервера, что приводит к возникновению исключения.

Есть более свежий отчет об ошибке в трекере ошибок mon go, который содержит подробную информацию. Я также исправил проблему в этой вилке драйвера mon go c#, связав состояние аутентификации с запросом на обнаружение. Я использую сборку разветвленного драйвера mon go, чтобы обойти эту проблему (вы можете создать один из них, запустив build --target = Package в разветвленном репозитории).

0 голосов
/ 19 августа 2020

Минимальный код:

var client = new MongoClient(_connection_string);;
var database = client.GetDatabase(Database_name);
var collection = database.GetCollection<T>(Collection_name);
var document_count = collection.EstimatedDocumentCount();

удалите последнюю строку, она работает правильно.

среда:. Net Core SDK 3.1.401, Mongodb.Driver 2.11 .0, используя Sharding Mongodb 4.4.

...