c# - 读写MongoDB(C#驱动)时,如何判断哪些异常值得重试?
问题描述
通过查看这个官方文档,似乎 MongoDB C# 驱动程序基本上抛出了三种类型的错误:
- 当驱动程序无法正确选择或连接到服务器以发出查询时引发的错误。这些错误会导致
TimeoutException
- 当驱动程序成功选择了一个服务器来运行查询时抛出的错误,但是在执行查询时服务器关闭了。这些错误表现为
MongoConnectionException
- 写操作期间抛出的错误。这些错误会导致
MongoWriteException
或MongoBulkWriteException
取决于正在执行的写入操作的类型。
我正在尝试使使用 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# 驱动程序重试查询的任何工作示例或参考?
解决方案
重试
让我们从重试的基础开始。
在某些情况下,您请求的操作依赖于在某个时间点可能无法访问的资源。换句话说,可能存在一个时间问题,它迟早会消失。这类问题可能会导致暂时性故障。通过重试,您可以通过尝试在未来的特定时刻重做相同的操作来克服这些问题。为了能够使用此机制,应满足以下标准组:
- 潜在引入的可观察影响是可以接受的
- 该操作可以重做,没有任何不可逆转的副作用
- 与承诺的可靠性相比,引入的复杂性可以忽略不计
让我们一一回顾:
- 失败一词表示请求者也可以观察到效果,例如通过更高的延迟/降低的吞吐量等。如果“惩罚”(延迟或降低的性能)是不可接受的,那么重试不是您的选择。
- 此要求也称为幂等操作。如果我多次使用相同的输入调用该操作,那么它将产生完全相同的结果。换句话说,操作的行为就像它只取决于它的参数,而没有其他任何东西会影响结果(就像其他对象的状态一样)。
- 这个条件虽然是最关键的条件之一,但几乎总是被遗忘。与往常一样,存在权衡(如果我引入 Z,那么它将增加 X,但可能会减少 Y),我们应该充分意识到它们。除非它会在最意想不到的时间内给我们一些不想要的惊喜。
蒙哥异常
让我们继续讨论 MongoDb 的 C# 客户端可以抛出的异常。
过去几年我没有使用过 MongoDb,所以这些知识可能已经过时了。但我希望本质没有改变。
我还鼓励您在尝试缓解问题(例如重试)之前先引入检测逻辑(捕获和日志)。这将提供有关发生频率和数量的信息。它还将让您深入了解问题的性质。
MongoConnectionException
与SocketException
作为内部- 什么时候:
- 有服务器选择问题
- 连接已超时
- 选择的服务器不可用
- 重试:
- 如果问题是由于网络问题,那么重试可能会很有用
- 如果根本原因是配置错误,那么重试将无济于事
- 日志:
- ConnectionId 和消息
- ToJson 也可能有用
- 什么时候:
MongoWriteException
或者MongoWriteConcernException
- 什么时候:
- 存在持久性问题
- 重试:
- 这取决于,如果您执行创建操作并且服务器可以检测到重复项(
DuplicateKeyError
),那么最好尝试多次写入记录,然后尝试一次失败的写入尝试 - 大多数时候更新不是幂等的,但是如果您使用某种记录版本控制,那么您可以尝试在乐观锁定期间执行重试并失败
- 删除可以以幂等方式实现。这对于软删除和硬删除也是如此。
- 这取决于,如果您执行创建操作并且服务器可以检测到重复项(
- 日志:
- WriteError、WriteConcernError 和消息
- 在 MongoWriteConcernExpcetion 的情况下:代码、命令和结果
- 什么时候:
推荐阅读
- angular - 如何在 Typescript 中获取泛型类型的属性
- javascript - 如何加载数据以在 ReduxForm 上进行编辑?
- arduino - 在 Arduino 中创建库时出现预期的 unqualified-id 错误
- sql - CTE 是否实现了计算?
- python - Python中的多级分组X轴
- line - openlayers 3中如何根据飞机当前的速度和航向预测未来的轨迹位置并画线?
- bash - 为什么 Ansible 对这些管道命令感到窒息?
- assembly - 为什么更多的数字在 2 的恭维中小于 0
- python - 如何填满树枝?
- ios - UIButton 内的 UIImageView 具有默认填充 - 如何删除?