Вставьте EF DatabaseContext в пользовательский ScopedService
Мне кажется, что производительность внедренного 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
Благодарю.
Действия по воспроизведению
- Клонировать текущий репозиторий с: https://github.com/suchoss/uServiceChasis
- Установите RabbitMQ с: https://www.rabbitmq.com/
- Установить MSSQL
- Измените соединитель на БД в EasyRabbit / startup.cs (строка 31)
- Перейдите в папку RandomNumberPairGenerator и выполните команду dotnet run на несколько секунд, затем вы можете отменить ее с помощью ctrl+c (она создает несколько сообщений в очереди RabbitMQ)
- Запустите проект EasyRabbit и посмотрите, сколько сообщений в секунду обрабатывается *. Если у вас установлено управление RabbitMQ, вы можете наблюдать за производительностью по http://localhost:15672/ (логин по умолчанию: guest; пароль: guest)
Отредактировано:
Вот текущие измеренные характеристики:
- EF асинхронный внутри adder.cs - 230/ с
- EF без асинхронности внутри adder.cs - 100/ с
- ADO.NET async - 1300/ с
- ADO.NET без асинхронности - 150/ с
- EF вставляет контекст асинхронно - 40/ с
- EF вставленный контекст без асинхронности - 65/ с
сценарии 1.,2.,3.,4. иметь adder.cs как синглтон
сценарии 5.,6. у них есть adder.cs в качестве сервиса