The project used Coldairarrow/EFCore.Sharding: Database Sharding For EFCore (github.com) This component , At first, it was used because the sub table was well made .
Because the project has been developing and testing , So there is a service memory has been soaring , Just restart , I got up after a long time . I have to say that Microsoft documents are really awesome
dotnet-counters Diagnostic tools - .NET CLI | Microsoft Docs
I first read this article , Without it , I won't go deep into Microsoft's diagnostic tools .
The picture above shows System.Diagnostics.StackFrame The memory consumption is the highest , All the output information is analyzed later , It is found that the database outputs a lot of information ,... Locate that the sub table cannot be released, resulting in .
By downloading the sample code :
using EFCore.Sharding; using EFCore.Sharding.Tests; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; namespace Demo.DateSharding { class Program { static async Task Main(string[] args) { DateTime startTime = DateTime.Now.AddMinutes(-5); ServiceCollection services = new ServiceCollection(); // Configuration initialization services.AddLogging(x => { x.AddConsole(); }); services.AddEFCoreSharding(config => { config.SetEntityAssemblies(typeof(Base_UnitTest).Assembly); // Add data sources config.AddDataSource(Config.CONSTRING1, ReadWriteType.Read | ReadWriteType.Write, DatabaseType.SqlServer); // By minute config.SetDateSharding<Base_UnitTest>(nameof(Base_UnitTest.CreateTime), ExpandByDateMode.PerMinute, startTime); }); var serviceProvider = services.BuildServiceProvider(); new EFCoreShardingBootstrapper(serviceProvider).StartAsync(default).Wait(); for (int i = 0; i < 2000; i++) { using var scop = serviceProvider.CreateScope(); var db = scop.ServiceProvider.GetService<IShardingDbAccessor>(); var logger = scop.ServiceProvider.GetService<ILogger<Program>>(); await db.InsertAsync(new Base_UnitTest { Id = Guid.NewGuid().ToString(), Age = 1, UserName = Guid.NewGuid().ToString(), CreateTime = DateTime.Now }); DateTime time = DateTime.Now.AddMinutes(-2); var count = await db.GetIShardingQueryable<Base_UnitTest>() .Where(x => x.CreateTime >= time) .CountAsync(); logger.LogWarning(" Current data volume :{Count}", count); } Console.ReadKey(); } } }
using var scop = serviceProvider.CreateScope() If you create more than once , This memory continues to rise , Don't release .
If you move this line of code out , Memory will be stable . Although inherited idisposiable , It was used using But it still won't release , It's a headache . But if the following code is transformed into the above one, there will be no memory guarantee .
using EFCore.Sharding; using EFCore.Sharding.Tests; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; namespace Demo.HelloWorld { class Program { static async Task Main(string[] args) { ServiceCollection services = new ServiceCollection(); services.AddLogging(config => { config.AddConsole(); }); services.AddEFCoreSharding(config => { config.SetEntityAssemblies(typeof(Base_UnitTest).Assembly); config.UseDatabase(Config.SQLITE1, DatabaseType.SQLite); }); var serviceProvider = services.BuildServiceProvider(); new EFCoreShardingBootstrapper(serviceProvider).StartAsync(default).Wait(); using var scop = serviceProvider.CreateScope(); // Get the injection IDbAccessor You can perform all database operations var db = scop.ServiceProvider.GetService<IDbAccessor>(); var logger = scop.ServiceProvider.GetService<ILogger<Program>>(); while (true) { await db.InsertAsync(new Base_UnitTest { Age = 100, CreateTime = DateTime.Now, Id = Guid.NewGuid().ToString(), UserId = Guid.NewGuid().ToString(), UserName = Guid.NewGuid().ToString() }); var count = await db.GetIQueryable<Base_UnitTest>().CountAsync(); logger.LogWarning(" Current quantity :{Count}", count); await Task.Delay(1000); } } } }
It turned out IDbAccessor It was created through the factory , Don't pass service Inject . however IShardingDbAccessor It's through services.AddScoped<IShardingDbAccessor, ShardingDbAccessor>() Injected into the service .
The solution to the project is to put
services.AddScoped<IShardingDbAccessor, ShardingDbAccessor>() Change to simple interest injection .