在 policies 下定义超时、重试和断路器策略。每个策略都有一个名称,以便您可以从弹性规范中的 targets 部分引用它们。
This is the multi-page printable view of this section. Click here to print.
弹性策略
1 - 超时弹性策略
网络调用可能因多种原因失败,导致应用程序无限期等待响应。通过设置超时时长,您可以切断那些无响应的服务,释放资源以处理新请求。
超时是可选策略,可用于提前终止长时间运行的操作。设置一个现实的超时时长,反映生产环境中的实际响应时间。如果超出了超时时长:
- 正在进行的操作将被终止(如果可能)。
- 返回错误。
超时策略格式
spec:
policies:
# 超时是指定的时长。
timeouts:
timeoutName: timeout1
general: 5s
important: 60s
largeResponse: 10s
规范元数据
| 字段 | 详情 | 示例 |
| timeoutName | 超时策略的名称 | timeout1 |
| general | 标记为"general"的超时时长。使用 Go 的 time.ParseDuration 格式。没有设置最大值。 | 15s、2m、1h30m |
| important | 标记为"important"的超时时长。使用 Go 的 time.ParseDuration 格式。没有设置最大值。 | 15s、2m、1h30m |
| largeResponse | 等待大型响应的超时时长。使用 Go 的 time.ParseDuration 格式。没有设置最大值。 | 15s、2m、1h30m |
如果未指定超时值,策略不会强制执行时间,默认为您根据请求客户端设置的值。
后续步骤
- 了解更多关于默认弹性策略
- 了解更多关于:
相关链接
试用其中一个弹性快速入门:
2 - 重试和退避弹性策略
2.1 - 重试弹性策略
请求可能因瞬时错误而失败,例如遇到网络拥塞、重新路由到过载实例等。有时,请求也可能因已设置的其他弹性策略而失败,例如触发了定义的超时或熔断器策略。
在这些情况下,配置 retries 可以:
- 将相同请求发送到不同的实例,或
- 在条件清除后重试发送请求。
重试和超时协同工作,超时确保您的系统在需要时快速失败,而重试从临时故障中恢复。
Dapr 提供默认弹性策略,您可以使用用户定义的重试策略覆盖它们。
重要
每个发布订阅组件都有自己的内置重试行为。显式应用 Dapr 弹性策略不会覆盖这些隐式重试策略。相反,弹性策略会增强内置重试,这可能导致消息重复聚集。重试策略格式
示例 1
spec:
policies:
# Retries are named templates for retry configurations and are instantiated for life of the operation.
retries:
pubsubRetry:
policy: constant
duration: 5s
maxRetries: 10
retryForever:
policy: exponential
maxInterval: 15s
maxRetries: -1 # Retry indefinitely
示例 2
spec:
policies:
retries:
retry5xxOnly:
policy: constant
duration: 5s
maxRetries: 3
matching:
httpStatusCodes: "429,500-599" # retry the HTTP status codes in this range. All others are not retried.
gRPCStatusCodes: "1-4,8-11,13,14" # retry gRPC status codes in these ranges and separate single codes.
规范元数据
以下重试选项是可配置的:
| 重试选项 | 描述 |
|---|---|
policy | 确定退避和重试间隔策略。有效值为 constant 和 exponential。默认为 constant。 |
duration | 确定重试之间的时间间隔。仅适用于 constant 策略。有效值为 200ms、15s、2m 等格式。默认为 5s。 |
maxInterval | 确定exponential 退避策略可以增长到的重试之间的最大间隔。额外的重试总是在 maxInterval 的持续时间后发生。默认为 60s。有效值为 5s、1m、1m30s 等格式。 |
maxRetries | 要尝试的最大重试次数。-1 表示无限次重试,而 0 表示不会重试请求(本质上表现为未设置重试策略)。默认为 -1。 |
matching.httpStatusCodes | 可选:逗号分隔的要重试的 HTTP 状态码或状态码范围字符串。未列出的状态码不会被重试。 有效值:100-599,参考 格式: <code> 或范围 <start>-<end>示例:“429,501-503” 默认:空字符串 "" 或未设置字段。重试所有 HTTP 错误。 |
matching.gRPCStatusCodes | 可选:逗号分隔的要重试的 gRPC 状态码或状态码范围字符串。未列出的状态码不会被重试。 有效值:0-16,参考 格式: <code> 或范围 <start>-<end>示例:“4,8,14” 默认:空字符串 "" 或未设置字段。重试所有 gRPC 错误。 |
指数退避策略
指数退避窗口使用以下公式:
BackOffDuration = PreviousBackOffDuration * (Random value from 0.5 to 1.5) * 1.5
if BackOffDuration > maxInterval {
BackoffDuration = maxInterval
}
重试状态码
当应用程序跨越多个服务时,特别是在像 Kubernetes 这样的动态环境中,服务可能因各种原因而消失,网络调用可能会开始挂起。状态码提供了对我们操作的洞察以及它们在生产中可能失败的位置。
HTTP
下表包含您可能收到的一些 HTTP 状态码示例,以及您是否应该或不应该重试某些操作。
| HTTP 状态码 | 建议重试? | 描述 |
|---|---|---|
| 404 Not Found | ❌ 否 | 资源不存在。 |
| 400 Bad Request | ❌ 否 | 您的请求无效。 |
| 401 Unauthorized | ❌ 否 | 尝试获取新凭据。 |
| 408 Request Timeout | ✅ 是 | 服务器等待请求超时。 |
| 429 Too Many Requests | ✅ 是 | (如果存在,请遵守 Retry-After 头)。 |
| 500 Internal Server Error | ✅ 是 | 服务器遇到意外情况。 |
| 502 Bad Gateway | ✅ 是 | 网关或代理接收到无效响应。 |
| 503 Service Unavailable | ✅ 是 | 服务可能会恢复。 |
| 504 Gateway Timeout | ✅ 是 | 临时网络问题。 |
gRPC
下表包含您可能收到的一些 gRPC 状态码示例,以及您是否应该或不应该重试某些操作。
| gRPC 状态码 | 建议重试? | 描述 |
|---|---|---|
| Code 1 CANCELLED | ❌ 否 | N/A |
| Code 3 INVALID_ARGUMENT | ❌ 否 | N/A |
| Code 4 DEADLINE_EXCEEDED | ✅ 是 | 使用退避重试 |
| Code 5 NOT_FOUND | ❌ 否 | N/A |
| Code 8 RESOURCE_EXHAUSTED | ✅ 是 | 使用退避重试 |
| Code 14 UNAVAILABLE | ✅ 是 | 使用退避重试 |
基于状态码的重试过滤器
重试过滤器允许通过指定应应用重试的 HTTP 和 gRPC 状态码或范围,对重试策略进行细粒度控制。
spec:
policies:
retries:
retry5xxOnly:
# ...
matching:
httpStatusCodes: "429,500-599" # retry the HTTP status codes in this range. All others are not retried.
gRPCStatusCodes: "4,8-11,13,14" # retry gRPC status codes in these ranges and separate single codes.
注意
状态码的字段值必须遵循上述指定的格式。格式错误的值会产生错误日志(“Could not read resiliency policy”),并且daprd 启动序列将继续。演示
观看 Diagrid 的 Dapr v1.15 庆祝活动期间演示的演示,了解如何使用 Diagrid Conductor 设置重试状态码过滤器。
后续步骤
相关链接
尝试其中一个弹性快速入门:
2.2 - 覆盖默认重试弹性策略
Dapr 为任何不成功的请求(如故障和临时错误)提供默认重试。在弹性规范中,您可以通过使用保留的命名关键字定义策略来覆盖 Dapr 的默认重试逻辑。例如,定义一个名为 DaprBuiltInServiceRetries 的策略可以覆盖通过服务间请求在边车之间发生故障时的默认重试。策略覆盖不会应用于特定目标。
注意:虽然您可以使用更稳健的重试来覆盖默认值,但不能使用低于提供的默认值的值进行覆盖,也不能完全移除默认重试。这可以防止意外的停机。
下表描述了 Dapr 的默认重试以及用于覆盖它们的策略关键字:
| 功能 | 覆盖关键字 | 默认重试行为 | 描述 |
|---|---|---|---|
| 服务调用 | DaprBuiltInServiceRetries | 每次调用重试的退避间隔为 1 秒,最多重试 3 次。 | 边车对边车的请求(服务调用方法调用)失败并导致 gRPC 代码 Unavailable 或 Unauthenticated |
| Actors | DaprBuiltInActorRetries | 每次调用重试的退避间隔为 1 秒,最多重试 3 次。 | 边车对边车的请求(Actor 方法调用)失败并导致 gRPC 代码 Unavailable 或 Unauthenticated |
| Actor 提醒 | DaprBuiltInActorReminderRetries | 每次调用重试采用指数退避,初始间隔为 500ms,最大间隔为 60s,持续时间为 15 分钟 | 向状态存储持久化 Actor 提醒失败的请求 |
| 初始化重试 | DaprBuiltInInitializationRetries | 每次调用执行 3 次重试,采用指数退避,初始间隔为 500ms,持续时间为 10 秒 | 向应用程序发出请求以检索给定规范时的故障。例如,检索订阅、组件或弹性规范失败 |
下面的弹性规范示例展示了如何使用保留的命名关键字 ‘DaprBuiltInServiceRetries’ 来覆盖_所有_服务调用请求的默认重试。
同时还定义了一个名为 ‘retryForever’ 的重试策略,该策略仅应用于 appB 目标。appB 使用 ‘retryForever’ 重试策略,而所有其他应用程序服务调用重试故障则使用被覆盖的 ‘DaprBuiltInServiceRetries’ 默认策略。
spec:
policies:
retries:
DaprBuiltInServiceRetries: # 覆盖服务间调用的默认重试行为
policy: constant
duration: 5s
maxRetries: 10
retryForever: # 用户定义的重试策略会替换默认重试。目标仅依赖于应用的策略。
policy: exponential
maxInterval: 15s
maxRetries: -1 # 无限期重试
targets:
apps:
appB: # 目标服务的 app-id
retry: retryForever
相关链接
尝试其中一个弹性快速入门:
3 - 断路器弹性策略
当其他应用程序/服务/组件出现较高的故障率时,会使用断路器策略。断路器通过监控请求并在满足特定条件时切断到受影响服务的所有流量来减少负载。
在一定数量的请求失败后,断路器会"跳闸"或打开以防止级联故障。通过这样做,断路器为服务提供从故障中恢复的时间,而不是用事件淹没它。
断路器还可以进入"半开"状态,允许部分流量通过以查看系统是否已恢复。
一旦请求恢复成功,断路器将进入"关闭"状态,并允许流量完全恢复。
断路器策略格式
spec:
policies:
circuitBreakers:
pubsubCB:
maxRequests: 1
interval: 8s
timeout: 45s
trip: consecutiveFailures > 8
规格元数据
| 重试选项 | 描述 |
|---|---|
maxRequests | 断路器处于半开状态(从故障中恢复)时允许通过的最大请求数。默认为 1。 |
interval | 断路器用于清除其内部计数的循环时间周期。如果设置为 0 秒,则永远不会清除。默认为 0s。 |
timeout | 打开状态的持续时间(直接在故障之后),直到断路器切换到半开状态。默认为 60s。 |
trip | 由断路器评估的 Common Expression Language (CEL) 表达式。当表达式评估为 true 时,断路器跳闸并变为打开状态。默认为 consecutiveFailures > 5。其他可能的值是 requests 和 totalFailures,其中 requests 表示电路打开之前成功或失败调用的数量,totalFailures 表示电路打开之前失败尝试的总数(不一定是连续的)。示例:requests > 5 和 totalFailures >3。 |
后续步骤
相关链接
尝试以下弹性快速入门之一:
4 - 默认弹性策略
在弹性中,您可以设置具有广泛范围的默认策略。这是通过保留关键字完成的,让 Dapr 知道何时应用该策略。有 3 种默认策略类型:
DefaultRetryPolicyDefaultTimeoutPolicyDefaultCircuitBreakerPolicy
如果定义了这些策略,它们将用于对服务、应用程序或组件的每个操作。它们还可以通过附加额外关键字来修改以更加具体。具体策略遵循以下模式,Default%sRetryPolicy、Default%sTimeoutPolicy 和 Default%sCircuitBreakerPolicy。其中 %s 被替换为策略的目标。
下表列出了所有可能的默认策略关键字以及它们如何转换为策略名称。
| 关键字 | 目标操作 | 示例策略名称 |
|---|---|---|
App | 服务调用。 | DefaultAppRetryPolicy |
Actor | Actor 调用。 | DefaultActorTimeoutPolicy |
Component | 所有组件操作。 | DefaultComponentCircuitBreakerPolicy |
ComponentInbound | 所有入站组件操作。 | DefaultComponentInboundRetryPolicy |
ComponentOutbound | 所有出站组件操作。 | DefaultComponentOutboundTimeoutPolicy |
StatestoreComponentOutbound | 所有状态存储组件操作。 | DefaultStatestoreComponentOutboundCircuitBreakerPolicy |
PubsubComponentOutbound | 所有出站发布订阅(发布)组件操作。 | DefaultPubsubComponentOutboundRetryPolicy |
PubsubComponentInbound | 所有入站发布订阅(订阅)组件操作。 | DefaultPubsubComponentInboundTimeoutPolicy |
BindingComponentOutbound | 所有出站绑定(调用)组件操作。 | DefaultBindingComponentOutboundCircuitBreakerPolicy |
BindingComponentInbound | 所有入站绑定(读取)组件操作。 | DefaultBindingComponentInboundRetryPolicy |
SecretstoreComponentOutbound | 所有密钥存储组件操作。 | DefaultSecretstoreComponentTimeoutPolicy |
ConfigurationComponentOutbound | 所有配置组件操作。 | DefaultConfigurationComponentOutboundCircuitBreakerPolicy |
LockComponentOutbound | 所有锁组件操作。 | DefaultLockComponentOutboundRetryPolicy |
策略层次解析
如果正在执行的操作匹配策略类型,并且没有针对它的更具体的策略,则会应用默认策略。对于每个目标类型(app、actor 和 component),优先级最高的策略是命名策略,即专门针对该构造的策略。
如果不存在,则策略从最具体到最广泛应用。
默认策略与内置重试如何协同工作
在内置重试的情况下,默认策略不会阻止内置重试策略运行。两者一起使用,但仅在特定情况下。
对于服务和 Actor 调用,内置重试专门处理连接到远程边车时的问题(在需要时)。由于这些对 Dapr 运行时的稳定性很重要,因此它们不会被禁用,除非为操作专门引用了命名策略。在某些情况下,可能会同时从内置重试和默认重试策略进行额外重试,但这可以防止过于薄弱的默认策略降低边车的可用性/成功率。
应用程序的策略解析层次,从最具体到最广泛:
- App 目标中的命名策略
- 默认 App 策略 / 内置服务重试
- 默认策略 / 内置服务重试
Actor 的策略解析层次,从最具体到最广泛:
- Actor 目标中的命名策略
- 默认 Actor 策略 / 内置 Actor 重试
- 默认策略 / 内置 Actor 重试
组件的策略解析层次,从最具体到最广泛:
- 组件目标中的命名策略
- 默认组件类型 + 组件方向策略 / 内置 Actor 提醒重试(如果适用)
- 默认组件方向策略 / 内置 Actor 提醒重试(如果适用)
- 默认组件策略 / 内置 Actor 提醒重试(如果适用)
- 默认策略 / 内置 Actor 提醒重试(如果适用)
作为一个示例,考虑以下解决方案,其中包含三个应用程序、三个组件和两个 Actor 类型:
应用程序:
- AppA
- AppB
- AppC
组件:
- Redis Pubsub:pubsub
- Redis statestore:statestore
- CosmosDB Statestore:actorstore
Actor:
- EventActor
- SummaryActor
以下是使用默认和命名策略并将其应用于目标的策略。
spec:
policies:
retries:
# 全局重试策略
DefaultRetryPolicy:
policy: constant
duration: 1s
maxRetries: 3
# 应用程序的全局重试策略
DefaultAppRetryPolicy:
policy: constant
duration: 100ms
maxRetries: 5
# 应用程序的全局重试策略
DefaultActorRetryPolicy:
policy: exponential
maxInterval: 15s
maxRetries: 10
# 入站组件操作的全局重试策略
DefaultComponentInboundRetryPolicy:
policy: constant
duration: 5s
maxRetries: 5
# 状态存储的全局重试策略
DefaultStatestoreComponentOutboundRetryPolicy:
policy: exponential
maxInterval: 60s
maxRetries: -1
# 命名策略
fastRetries:
policy: constant
duration: 10ms
maxRetries: 3
# 命名策略
retryForever:
policy: exponential
maxInterval: 10s
maxRetries: -1
targets:
apps:
appA:
retry: fastRetries
appB:
retry: retryForever
actors:
EventActor:
retry: retryForever
components:
actorstore:
retry: fastRetries
下表详细分解了在尝试调用此解决方案中的各种目标时应用哪些策略。
| 目标 | 使用的策略 |
|---|---|
| AppA | fastRetries |
| AppB | retryForever |
| AppC | DefaultAppRetryPolicy / DaprBuiltInActorRetries |
| pubsub - 发布 | DefaultRetryPolicy |
| pubsub - 订阅 | DefaultComponentInboundRetryPolicy |
| statestore | DefaultStatestoreComponentOutboundRetryPolicy |
| actorstore | fastRetries |
| EventActor | retryForever |
| SummaryActor | DefaultActorRetryPolicy |
后续步骤
相关链接
尝试其中一个弹性快速入门: