简体   繁体   English

通过 ASP.NET Core REST API 并发请求后来自 MongoDb 的响应缓慢

[英]Slow responses from MongoDb after concurrent requests via ASP.NET Core REST API

I'm running a web service based on ASP.NET Core 2.2.我正在运行基于 ASP.NET Core 2.2 的 Web 服务。 External clients call the REST API in regular intervalls.外部客户端定期调用 REST API。 So it is possible, that the API is hit with about 50 nearly concurrent requests (every 10 to 40 min.).因此,API 可能会遇到大约 50 个几乎并发的请求(每 10 到 40 分钟)。

Problem: Some minutes after the concurrent requests the service's response time is high.问题:并发请求几分钟后,服务的响应时间很长。 The response time increased from < 1 s (for single requests) to 40 sec.响应时间从 < 1 秒(对于单个请求)增加到 40 秒。

Remarks:评论:

  • The query retrieves items (< 100 in total) from about three different collections (filtering by a single property included in the index, some by id; holding < 5000 records).该查询从大约三个不同的集合中检索项目(总共 < 100 个)(按索引中包含的单个属性过滤,一些按 id 过滤;持有 < 5000 条记录)。
  • For persistence the MongoDB.Driver 2.9.1 and a single installation of MongoDB 4.0.12 are used.对于持久性,使用 MongoDB.Driver 2.9.1 和 MongoDB 4.0.12 的单一安装。
  • Updating to the latest driver and MongoDB 4.0 has not improved the situation.更新到最新的驱动程序和 MongoDB 4.0 并没有改善这种情况。
  • The MongoDB database profiler shows no slow queries. MongoDB 数据库分析器显示没有慢查询。
  • The output from mongostat shows about 90 open connections. mongostat的输出显示大约 90 个打开的连接。
  • The tests have been executed on an older machine (some Haswell Core i7, 32 GB RAM) running Windows 10 (db and application on same machine).测试是在运行 Windows 10(数据库和应用程序在同一台机器上)的旧机器(一些 Haswell Core i7,32 GB RAM)上执行的。
  • The MongoDB installation runs with default configuration. MongoDB 安装使用默认配置运行。
  • Continouus load tests (eg 3000 x 50 concurrent requests) have shown, that after the initial ramp-up phase (with slow requests) the response time drops to < 5 sec, what I would consider as normal.连续负载测试(例如 3000 x 50 并发请求)表明,在初始加速阶段(使用慢速请求)之后,响应时间下降到 < 5 秒,我认为这是正常的。
    • There are some write operations on those collections (only from one client eg 10 per hour).这些集合上有一些写操作(仅来自一个客户端,例如每小时 10 个)。

Questions:问题:

  • Any recommendations for performance tuning?对性能调优有什么建议吗?
  • Any performance indicators to check?有什么性能指标要检查吗?
  • Issue with the connection pooling?连接池问题?

EDIT: Using the ClusterConfigurator of the MongoClientSettings available from the MongoDB Driver package for C# I measured an increase of duration of a query up to 00:00:04.5022352 seconds (from 00:00:00.0005432).编辑:使用 C# 的 MongoDB 驱动程序包中可用的 MongoClientSettings 的 ClusterConfigurator 我测量了查询持续时间的增加,最多 00:00:04.5022352 秒(从 00:00:00.0005432)。

I noticed that opLatencies reads are increasing during 50 nearly concurrent requests: opLatencies.reads.latency: from 68723 to 202886, opLatencies.reads.ops: from 449 to 1053我注意到 opLatencies 读取在 50 个几乎并发的请求中增加:opLatencies.reads.latency:从 68723 到 202886,opLatencies.reads.ops:从 449 到 1053

Background:背景:

The MongoClient is created in following class: MongoClient在以下类中创建:

public class MongoDbContext : IContext {
    private readonly MongoUrl _url;
    private MongoClient _client;
    private IMongoDatabase _db;

    public MongoDbContext (string connectionString) {
        _url = MongoUrl.Create (connectionString);
    }

    public IMongoDatabase GetDatabase () {
        return _db ?? (_db = GetClient ().GetDatabase (_url.DatabaseName));
    }

    public MongoClient GetClient () {
        return _client ?? (_client = new MongoClient (_url));
    }
}

The context is injected in the Startup.cs and used in serveral repositories.上下文被注入 Startup.cs 并在多个存储库中使用。

//... Startup.cs
var context = new MongoDbContext(connectionString);    
services.AddSingleton<IContext>(context);
// Other services and repositories ...
services.AddTransient<IWeatherRepository, WeatherRepository>();

The repositories use following base class:存储库使用以下基类:

public abstract class MongoDbRepository<T> : IRepository<T> where T : Entity<long> {

    private IMongoCollection<T> _collection { get; set; }

    protected IContext Context { get; set; }

    protected abstract IMongoCollection<T> GetCollection ();

    protected IMongoCollection<T> Collection {
        get { return _collection ?? (_collection = GetCollection ()); }
        set { _collection = value; }
    }

    public MongoDbRepository (IContext context) {     
        Context = context;
    }

    /// ...

    public async Task<IEnumerable<T>> Find (Expression<Func<T, bool>> filter) {
        return await Collection.Find (filter).ToListAsync ();
    }
}

你有没有试过对这些操作使用异步方法可能会帮助你改善并发操作响应。(在数据库上下文中)

I would not recommend to use Singleton for DB Context.我不建议将Singleton用于 DB Context。 This object should be released as soon as it is not needed.该对象在不需要时应立即释放。 Use Scoped instead, it will be shared among your repositories within request and then will be released:改用Scoped ,它将在请求中的存储库之间共享,然后将被释放:

services.AddScoped<IContext, MongoDbContext>(provider => new MongoDbContext(connectionString));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM