Вставьте EF DatabaseContext в пользовательский ScopedService - PullRequest
0 голосов
/ 16 мая 2018

мне кажется, что производительность внедренного EF внутри сервисной области действительно низкая.

Существует высокая вероятность того, что я неправильно использую EF в этом случае, но я не смог найти правильное описание / документацию о том, как использовать EF в этом случае (добавить его в настраиваемую размещенную службу).

В EasyRabbit / startup.cs (ConfigureServices) зарегистрированы следующие сервисы:

// db
services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer("Server=localhost; Database=RabbitTest; MultipleActiveResultSets=true; User ID=sa; Password=Admin1234");
});

// default REST Api
services.AddMvc();
// Configuration for Rabbit connector
services.Configure<RabbitConfig>(Configuration.GetSection("RabbitConfig"));
// Rabbit Connector
services.AddSingleton<RabbitConnector>();
// Subscriber which listens if some new message arrives
services.AddSingleton<IHostedService, GenericHostedSubscriber<CalculatorInputs>>();

// Every arival message is then processed in following scope
// ApplicationDbContext dbContext is injected into this RabbitSubscribers.Adder
services.AddScoped<IScopedProcessingService<CalculatorInputs>, RabbitSubscribers.Adder>();

Теперь, если я правильно понимаю, он должен автоматически создавать область контекста БД для каждой новой области RabbitSubscribeers.Adder.

Проблема в том, что таким образом он может потреблять / обрабатывать в среднем только около 50 сообщений в секунду.

Когда я комментирую все операции с db (AddAsync и SaveChangesAsync) из следующего кода, тогда он может обрабатывать около 2000 сообщений в секунду, что неплохо, но без db для меня бесполезно: (

namespace EasyRabbit.RabbitSubscribers
{
    public class Adder : IScopedProcessingService<CalculatorInputs>
    {
        private ILogger<Adder> _logger;
        private ApplicationDbContext _db;

        public Adder(ApplicationDbContext dbContext, ILogger<Adder> logger)
        {
            _logger = logger;
            _db = dbContext;

        }

        public async Task HandleMessageAsync(CalculatorInputs message)
        {

            Console.WriteLine($"Calculator: [{message.FirstNumber}] + [{message.SecondNumber}] = {message.FirstNumber + message.SecondNumber}");
            await _db.Calculations.AddAsync(new Calculation()
            {
                FirstNumber = message.FirstNumber,
                SecondNumber = message.SecondNumber,
                Result = message.FirstNumber + message.SecondNumber
            });

            await _db.SaveChangesAsync();

        }
    }
}

Когда я попытался заменить EF на System.Data.SqlClient (следующий фрагмент кода, непосредственно используемый в Adder.cs), он мог обрабатывать в среднем 1100 сообщений в секунду. Но работать с БД, как это, действительно неудобно: - /

public static class DB
{
    private static string _connectionString = "Server=localhost; Database=RabbitTest; MultipleActiveResultSets=true; User ID=sa; Password=Admin1234";


    public static void AddRecord(MyDBObject myDBObject)
    {
        using (SqlConnection con = new SqlConnection(_connectionString))
        {
            using (SqlCommand cmd = new SqlCommand("insert into test (FirstNumber, SecondNumber, Result) values (@FirstNumber, @SecondNumber, @Result)", con))
            {
                cmd.CommandType = CommandType.Text;
                cmd.Parameters.AddWithValue("@FirstNumber", myDBObject.FirstNumber);
                cmd.Parameters.AddWithValue("@SecondNumber", myDBObject.SecondNumber);
                cmd.Parameters.AddWithValue("@Result", myDBObject.Result);
                con.Open();
                cmd.ExecuteNonQuery();
                con.Close();
            }

        }
    }
}

public class MyDBObject
{
    public int FirstNumber { get; set; }
    public int SecondNumber { get; set; }
    public int Result { get; set; }
}

Весь код можно найти на https://github.com/suchoss/uServiceChasis

Спасибо.

Шаги для воспроизведения

  1. Текущий репозиторий клонов из: https://github.com/suchoss/uServiceChasis
  2. Установить RabbitMQ из: https://www.rabbitmq.com/#getstarted
  3. Установить MSSQL
  4. Измените соединитель на DB в EasyRabbit / startup.cs (строка 31)
  5. Перейдите в папку RandomNumberPairGenerator и выполните команду dotnet run на несколько секунд, затем вы можете отменить ее с помощью ctrl + c (она создает некоторые сообщения в очередь RabbitMQ)
  6. Запустите проект EasyRabbit и посмотрите, сколько сообщений в секунду обрабатывается *. Если у вас установлено управление RabbitMQ, вы можете посмотреть производительность на http://localhost:15672 (логин по умолчанию: гость; пароль: гость)

Отредактировано:

Вот текущие измеренные характеристики:

  1. EF async внутри adder.cs - 230 / с
  2. EF без асинхронности внутри adder.cs - 100 / с
  3. ADO.NET async - 1300 / с
  4. ADO.NET без асинхронной работы - 150 / с
  5. EF вставляет контекст асинхронно - 40 / с
  6. Внедренный EF контекст без асинхронности - 65 / с

сценарии 1., 2., 3., 4. иметь adder.cs как синглтон

сценарии 5., 6. у них есть adder.cs в качестве сервиса

...