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

Enr*_*one 6 .net c# mongodb resiliency polly

通过查看这个官方文档, 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 上重试 C# 驱动程序查询的任何工作示例或参考?

Pet*_*ala 3

重试

\n

让我们从重试的基础知识开始。

\n

在某些情况下,您请求的操作依赖于某个资源,而该资源在某个时间点可能无法访问。换句话说,可能存在一个暂时的问题,这个问题迟早会消失。此类问题可能会导致暂时性故障。通过重试,您可以通过尝试在未来的特定时刻重做相同的操作来克服这些问题。为了能够使用此机制,应满足以下标准组:

\n
    \n
  • 潜在引入的可观察影响是可以接受的
  • \n
  • 手术可以重做,没有任何不可逆的副作用
  • \n
  • 与承诺的可靠性相比,引入的复杂性可以忽略不计
  • \n
\n

让\xe2\x80\x99s一一回顾一下:

\n
    \n
  • “失败”一词表示请求者也可以观察到效果,例如通过更高的延迟/降低的吞吐量等。如果 \xe2\x80\x9cpenalty\xe2\x80\x9c (延迟或性能降低)不可接受,则重试不是您的选择。
  • \n
  • 此要求也称为幂等操作。如果我多次使用相同的输入调用该操作,那么它将产生完全相同的结果。换句话说,该操作的行为就像它仅取决于其参数,而没有其他因素影响结果(就像其他对象的状态一样)。
  • \n
  • 尽管这一条件是最重要的条件之一,但它却几乎总是被遗忘。一如既往,存在着权衡(如果我引入 Z,那么它会增加 X,但可能会减少 Y),我们应该充分意识到它们。\n除非它会在最不期望的时间内给我们带来一些不想要的惊喜。
  • \n
\n

蒙戈异常

\n

让我们继续讨论 MongoDb 的 C# 客户端可能抛出的异常。

\n

过去几年我没有使用过 MongoDb,所以这些知识可能已经过时了。但我希望本质从那时起就没有改变。

\n

我还鼓励您在尝试缓解问题(例如重试)之前首先引入检测逻辑(捕获和日志)。这将提供有关发生频率和数量的信息。它还将使您深入了解问题的本质。

\n
    \n
  • MongoConnectionException以 aSocketException作为内部\n
      \n
    • 时间:\n
        \n
      • 服务器选择有问题
      • \n
      • 连接超时
      • \n
      • 所选服务器不可用
      • \n
      \n
    • \n
    • 重试:\n
        \n
      • 如果问题是由于网络问题造成的,那么重试可能会有用
      • \n
      • 如果根本原因是配置错误,则重试将无济于事
      • \n
      \n
    • \n
    • 日志:\n\n
    • \n
    \n
  • \n
  • MongoWriteExceptionMongoWriteConcernException\n
      \n
    • 时间:\n
        \n
      • 存在持久性问题
      • \n
      \n
    • \n
    • 重试:\n
        \n
      • 这取决于,如果您执行创建操作并且服务器可以检测到重复项 ( DuplicateKeyError),那么最好尝试多次写入记录,然后进行一次失败的写入尝试
      • \n
      • 大多数时候更新不是幂等的,但如果您使用某种记录版本控制,那么您可以尝试执行重试并在乐观锁定期间失败
      • \n
      • 删除可以以幂等的方式实现。对于软删除和硬删除也是如此。
      • \n
      \n
    • \n
    • 日志:\n\n
    • \n
    \n
  • \n
\n