小编Enr*_*one的帖子

MongoDB查找性能:单复合索引VS两个单字段索引

我正在寻找关于在MongoDb 3.4中使用哪种索引策略的建议.

假设我们有一个具有以下形状的人员文档集合:

{
    _id: 10,
    name: "Bob",
    age: 32,
    profession: "Hacker"
}
Run Code Online (Sandbox Code Playgroud)

让我们假设一个用于查询集合的web api被公开,并且唯一可能的过滤器是按名称或按年龄.
对api的示例调用将类似于: http://myAwesomeWebSite/people?name="Bob"&age=25

这样的调用将在以下查询中翻译:db.people.find({name: "Bob", age: 25}).

为了更好地阐明我们的场景,请考虑:

  • 字段已经在我们的文档中,我们已经有了该字段的索引
  • 由于我们的应用程序的一些新功能,我们将添加新的字段时代
  • 数据库只能通过上面提到的web api访问,最重要的要求是公开超快的web api
  • 所有对web api的调用都将对字段名称和年龄应用过滤器(换句话说,对web api的所有调用都将具有相同的模式,如上所示)

也就是说,我们必须决定以下哪个索引提供最佳性能:

  • 一个复合指数: {name: 1, age: 1}
  • 两个单字段索引:{name: 1}{age: 1}

根据一些简单的测试,似乎单一复合指数比两个单场指数更具性能.

通过mongo shell执行单个查询,explain()方法建议使用单个复合索引,您可以比使用两个单字段索引快10倍地查询数据库.

在更现实的情况下,这种差异似乎不那么剧烈,在这种情况下,不是通过mongo shell执行单个查询,而是对nodejs web应用程序的两个不同URL进行多次调用.两个URL都对数据库执行查询,并将获取的数据作为json数组返回,一个使用具有单个复合索引的集合,另一个使用具有两个单字段索引的集合(两个集合具有完全相同的文档).
在这个测试中,单一复合指数似乎仍然是性能方面的最佳选择,但这次差异不太明显.

根据测试结果,我们正在考虑使用单一复合指数方法.

有没有人有关于这个主题的经验?我们是否缺少任何重要的考虑因素(可能是大型复合指数的一些缺点)?

indexing performance mongodb mongodb-query

26
推荐指数
1
解决办法
6084
查看次数

事件采购:回滚聚合状态的正确方法

我正在寻找与在CQRS /事件采购应用程序中实现回滚功能的正确方法相关的建议.

该应用程序允许一组编辑者编辑和更新一些编辑内容,例如编辑新闻.我们实现了用户界面,以便每个字段都有自动保存功能,现在我们希望为用户提供撤消他们所做操作的可能性,以便可以将编辑新闻回滚到之前的已知状态.
基本上我们希望实现类似于Microsoft Word和类似文本编辑器中的撤消命令.在后端,编辑新闻是在我们的域中定义的聚合的实例,称为Story.

我们已经讨论了实现回滚的一些想法,我们正在寻找基于类似项目的实际经验的建议.以下是我们对此功能的考虑.

回滚如何在现实世界的业务领域中运行

首先,我们都知道,在现实世界的业务领域,我们所谓的回滚是通过某种形式的补偿事件获得的.

想象一下与可以购买订阅的某种服务相关的域:我们可以有一个代表用户订阅的聚合和一个描述费用已经与聚合实例相关联的事件(特定订阅一个客户).该事件的可能实施如下:

public class ChargeAssociatedToSubscriptionEvent: DomainEvent
{
  public Guid SubscriptionId {get; set;}
  public decimal Amount {get; set;}
  public string Description {get; set;}
  public DateTime DueDate {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

如果收费错误地与订阅相关联,则可以通过与相同订阅相关联且具有相同金额的认证来修复错误,从而使收费的效果完全平衡并且用户收回其钱.换句话说,我们可以定义以下补偿事件:

public class AccreditationAssociatedToSubscription: DomainEvent
{
  public Guid SubscriptionId {get; set;}
  public decimal Amount {get; set;}
  public string Description {get; set;}
  public DateTime AccreditationDate {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

因此,如果用户被错误地收取50美元的费用,我们可以通过对用户订阅的50美元的认证来补偿错误:这样,聚合的状态已经回滚到之前的状态.

为什么事情并不像看起来那么容易

根据前面的讨论,回滚似乎很容易实现.如果在聚合修订版B中有故事聚合的实例,并且您想将其回滚到先前的聚合修订版,例如A(使用A <B),则只需执行以下步骤:

  • 检查事件存储并获取修订版A和B之间的所有事件
  • 计算每个发生事件的补偿事件
  • 将补偿事件以相反的顺序应用于汇总

遗憾的是,前一过程的第二步并不总是可行的:给定一个通用域事件,并不总是可以计算其补偿事件,因为事件中包含的信息量不足以做到这一点.也许有可能明智地定义所有事件,以便它们包含足够的信息以便能够计算相应的补偿事件,但是在我们的应用程序的当前状态下,有几个事件无法计算补偿事件,我们会我宁愿避免改变事件的形状.

基于状态比较的可能解决方案

克服补偿事件问题的第一个想法是 …

domain-driven-design cqrs event-sourcing

9
推荐指数
1
解决办法
1744
查看次数

C# 7.0 独立丢弃混淆

我想更好地理解几个涉及 C# 7.0 丢弃功能使用的示例。

他们都利用了所谓的独立丢弃

这是第一个让我困惑的例子,可以在这里找到

public class EmailController
{
    public ActionResult SendEmail(string email)
    {
        var correlationId = HttpContext.Request.Headers["x-correlation-id"].ToString();

        // Starts sending an email, but doesn't wait for it to complete
        _ = SendEmailCore(correlationId);
        return View();
    }

    private async Task SendEmailCore(string correlationId)
    {
        // send the email
    }
}
Run Code Online (Sandbox Code Playgroud)

调用时使用的独立丢弃是否SendEmailCore有用?上面的代码和没有分配SendEmailCore(correlationId)给丢弃表达式的相同代码有什么区别_?运行时行为有什么不同吗?

这是第二个代码示例,可在此处获得

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      ExecuteAsyncMethods().Wait();
   } …
Run Code Online (Sandbox Code Playgroud)

c# c#-7.0

8
推荐指数
0
解决办法
430
查看次数

ASP.NET core 2.2 web api 记录与数据保护密钥相关的警告:我们应该如何处理这个问题?

我们有一个 ASP.NET core 2.2 web 应用程序,它暴露了一些 web api 控制器。我们的应用程序没有任何类型的身份验证机制,所有暴露的端点都可以由匿名用户调用。

当我们在 IIS 下托管应用程序时,我们会在应用程序启动时收到三个奇怪的警告消息。这些是我们得到的日志:

  1. 使用内存存储库。密钥不会被持久化到存储中。
  2. 用户配置文件和 HKLM 注册表都不可用。使用临时密钥存储库。应用程序退出时,受保护的数据将不可用。
  3. 未配置 XML 加密器。密钥 {GUID} 可以以未加密的形式保存在存储中。

所有这些日志都将 Microsoft.AspNetCore.DataProtection 作为日志上下文,并由 ASP.NET 核心框架内部编写。

这些日志的含义对我来说似乎很清楚:有一个“密钥”(无论它意味着什么),因为没有提供注册表存储(当然,它会在应用程序退出时丢失)将持久保存在内存中)。还有一个警告表明这个密钥,如果持续存在,将不会以任何方式加密。

此时我会问以下问题:

  • 日志中报告的名称为“key”的 GUID 是什么?用于什么?
  • 是否存在与此警告相关的任何安全风险?
  • 我应该采取什么行动?

一些附加信息:

一些在线博客建议这些类型的数据保护警告与 ASP.NET 身份的使用有关,但我们不在我们的应用程序中使用身份(我们没有启用身份验证)。其他博客建议设置托管应用程序池以加载用户配置文件:我已经尝试过,但警告仍然存在。

2019 年 4 月 2 日的重要更新

感谢 asp.net 核心开发团队的帮助,我解决了这个问题。完整参考见我昨天打开的github issue

简而言之,问题与我的开发机器上的 IIS 配置有关。为了使 ASP.NET 核心数据保护按预期工作,IIS 和托管应用程序池有一些特定配置(请参阅此处获取完整参考

2019 年 9 月 13 日更新

对于在其 ASP.NET core 2.2 web 应用程序中具有相同警告的那些,我建议查看此github 问题

我们现在已经为我们的产品添加了 cookie 身份验证,我们需要支持 kubernetes 托管。在具有 cookie 身份验证的 kubernetes 中,此 …

c# iis data-protection asp.net-core

7
推荐指数
1
解决办法
4087
查看次数

有没有办法在 JsonDocument 和 JsonNode 之间进行转换?

在 .NET 6 中,基本上有两种使用 JSON DOM 的方法:

有关这方面的更多信息可以在这里找到

我问自己是否可以从 的实例转换JsonDocument为 的实例JsonNode,反之亦然。基本上我正在寻找这样的东西:

using System.Text.Json;
using System.Text.Json.Nodes;

const string jsonText = "{\"name\": \"Bob\"}";

var jsonNode = JsonNode.Parse(jsonText);

// This code doesn't compile. This is just an example to illustrate what I'm looking for
JsonDocument jsonDocument = jsonNode!.ToJsonDocument();
Run Code Online (Sandbox Code Playgroud)

只是为了添加更多上下文,我问自己这个问题,因为JsonDocument它具有不可变的优点,同时JsonNode提供了一种改变 JSON DOM 片段的方法。

我喜欢尽可能使用不可变对象,但同时我需要改变我正在使用的 JSON DOM。执行此操作的可能策略如下:

  1. JsonDocument从字符串(或 JSON 的任何来源)获取 的实例
  2. JsonDocument在代码中始终使用不可变实例
  3. JsonNode从实例中获取 的实例JsonDocument …

c# json .net-core system.text.json

7
推荐指数
1
解决办法
4506
查看次数

读写 MongoDB(C# 驱动程序)时如何决定哪些异常值得重试?

通过查看这个官方文档, MongoDB C# 驱动程序基本上会抛出三种类型的错误:

  • 当驱动程序无法正确选择或连接到服务器来发出查询时抛出错误。这些错误导致TimeoutException
  • 当驱动程序成功选择要运行查询的服务器,但服务器在执行查询时出现故障时,会引发错误。这些错误表现为MongoConnectionException
  • 写操作期间抛出的错误。这些错误会导致MongoWriteExceptionMongoBulkWriteException取决于正在执行的写入操作的类型。

我正在尝试让使用 MongoDB 的软件对暂时性错误更具弹性,因此我想找出哪些异常值得重试。

问题不在于实施可靠的重试策略(我通常使用Polly .NET 来实现),而在于了解重试何时有意义。

我认为重试类型异常TimeoutException没有意义,因为驱动程序本身会在操作超时之前等待几秒钟(默认值为 30 秒,但您可以通过连接字符串选项更改它)。这个想法是,在超时之前等待 30 秒后重试该操作可能是浪费时间。例如,如果您决定实施 3 次重试,每次重试之间有 1 秒的等待时间,则最多需要 93 秒才能使操作失败 (30 + 30 + 30 + 1 + 1 + 1)。这是一个伟大的时刻。

如此处所述,仅在执行幂等操作时重试MongoConnectionException才是安全的。从我的角度来看,只要执行的操作是幂等的,总是重试此类错误是有意义的。

决定一个好的写入重试策略的难点是当您遇到类型MongoWriteException或的异常时MongoBulkWriteException

关于类型的异常MongoWriteException可能值得重试所有具有ServerErrorCategory DuplicateKey. 如此处所述,您可以使用对象的此属性来检测重复键错误MongoWriteException.WriteError

重试重复的键错误可能没有意义,因为您会再次遇到它们(这不是暂时性错误)。

我不知道如何安全地处理类型错误MongoBulkWriteException。在这种情况下,您要向 MongoDB 插入多个文档,完全有可能只有其中一些文档失败,而其他文档已成功写入 MongoDB。因此,重试完全相同的批量插入操作可能会导致将同一文档写入两次(批量写入本质上不是幂等的)。我该如何处理这种情况?

您有什么建议吗?

您是否知道有关在 MongoDB 上重试 …

.net c# mongodb resiliency polly

6
推荐指数
1
解决办法
2240
查看次数

Is iterating over an array with a for loop a thread safe operation in C# ? What about iterating an IEnumerable&lt;T&gt; with a foreach loop?

Based on my understanding, given a C# array, the act of iterating over the array concurrently from multiple threads is a thread safe operation.

By iterating over the array I mean reading all the positions inside the array by means of a plain old for loop. Each thread is simply reading the content of a memory location inside the array, no one is writing anything so all the threads read the same thing in a consistent manner.

This is …

.net c# arrays multithreading thread-safety

6
推荐指数
1
解决办法
141
查看次数

处理取消令牌源的正确模式

考虑这样一个场景,您需要完成一些异步工作,并且可以在即发即弃模式下运行它。这种异步工作能够侦听取消,因此您向它传递取消令牌以便能够取消它。

在给定的时刻,我们可以决定请求取消正在进行的活动,方法是使用我们从中获取取消令牌的取消令牌源对象。

因为取消令牌源实现了IDisposable,所以我们应该尽可能地调用它的Dispose方法。这个问题的重点是确定您何时完成给定的取消令牌源。

假设您决定通过调用Cancel取消令牌源上的方法来取消正在进行的工作:在调用之前是否需要等待正在进行的操作完成Dispose

换句话说,我应该这样做:

class Program 
{
  static void Main(string[] args) 
  {
    var cts = new CancellationTokenSource();
    var token = cts.Token;

    DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner

    // do some other stuff here 

    cts.Cancel();
    cts.Dispose(); // I call Dispose immediately after cancelling without waiting for the completion of ongoing work listening to the cancellation requests via the token

    // do some other …
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library async-await cancellationtokensource .net-core

6
推荐指数
2
解决办法
1289
查看次数

在托管服务中注入类型化 HTTP 客户端是否会创建强制依赖?

我对 ASP.NET 核心依赖注入容器有疑问。这个问题专门针对ASP.NET core 3.1

基本上,我问自己,是否注入类型的HTTP客户端内部托管服务创建一个所谓的俘虏依赖于依赖注入的条款。

我试图描绘的场景如下:

public interface IStudentsApiClient  
{
  Task<IEnumerable<Student>> GetAll(CancellationToken cancellationToken);
}

public class StudentsApiClient: IStudentsApiClient 
{
  private readonly HttpClient _httpClient;
  
  public StudentsApiClient(HttpClient httpClient)
  {
    _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
  }
  
  public async Task<IEnumerable<Student>> GetAll(CancellationToken cancellationToken)
  {
      // call a GET endpoint to retrieve all the students from a third party api...
  }
}

public class StudentsPollingHostedService: BackgroundService 
{
    private readonly IStudentsApiClient _apiClient;
    
    public StudentsPollingHostedService(IStudentsApiClient apiClient) 
    { …
Run Code Online (Sandbox Code Playgroud)

c# dependency-injection ioc-container .net-core asp.net-core

6
推荐指数
0
解决办法
920
查看次数

建议在 .NET 核心中使用 app.config 和 ConfigurationManager 吗?

我们正在将一些 .NET 应用程序从完整框架迁移到 .NET 核心,并且我们正在尝试找出这样做的最佳方法。

主要变化之一是与应用程序配置方式相关的变化。在 .NET 完整框架中,我们曾经将应用程序设置放在 app.config 文件中,并通过ConfigurationManager 类读取它们。

我知道 .NET 核心支持基于 nuget 包Microsoft.Extensions.Configuration和各种配置源包的新配置系统。但是,与此同时,Microsoft 通过 nuget 包System.Configuration.ConfigurationManager将对 ConfigurationManager 类的支持扩展到 .NET 核心。

以下是我的问题:

  • 配置 .NET 核心应用程序的预期最佳实践是什么?
  • 实现对 app.config 文件的支持只是为了向后兼容,以便移植到遗留应用程序的 .NET 核心更容易,或者它被认为是最佳实践,将来会维护?

c# app-config configuration-files .net-core

5
推荐指数
1
解决办法
1178
查看次数