使用aws-sdk-go-v2操作DynamoDB仍触发ProvisionedThroughputExceededException的疑问
解决DynamoDB ProvisionedThroughputExceededException问题
为什么SDK默认重试没自动处理?
aws-sdk-go-v2确实自带指数退避,但有两个核心原因导致你遇到的问题:
- 令牌桶流量控制:DynamoDB的预置容量不是严格每秒重置,而是用令牌桶机制管理。比如你配置了100个写入容量单位(WCU),令牌桶初始有100个令牌,每秒补充100个。如果你的脚本请求速度极快(哪怕是顺序执行,比如每个请求耗时1ms,1秒就能发1000次),会瞬间耗尽令牌桶,直接触发异常。SDK的默认重试可能在令牌桶还没补充足够令牌时就重试,依然会失败,最终抛出异常。
- 默认重试限制:SDK默认的重试次数和退避窗口有限(比如默认最多重试3次,总退避时间远不到20秒),如果短时间内请求量远超容量,几次重试后还是会触发限流。
正确的处理方式
- 自定义重试策略
调整SDK的重试配置,增加重试次数、延长退避时间,给令牌桶足够的补充周期。示例代码:
import ( "context" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/aws/retry" ) func main() { cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryer(func() aws.Retryer { // 最多重试10次,搭配默认指数退避 return retry.AddWithMaxAttempts(retry.NewStandard(), 10) // 也可以自定义退避区间 // return retry.NewAdaptiveRetryer(retry.AdaptiveRetryerOptions{ // MaxAttempts: 10, // MinBackoff: *aws.Duration(500 * time.Millisecond), // MaxBackoff: *aws.Duration(30 * time.Second), // }) }), ) if err != nil { panic(err) } client := dynamodb.NewFromConfig(cfg) // 后续DynamoDB操作... }
- 客户端侧速率限制
用限流器严格控制请求速率,确保不超过预置WCU。可以用golang.org/x/time/rate实现:
import "golang.org/x/time/rate" // 假设预置容量是100WCU,设置限流器为90次/秒,留缓冲空间 limiter := rate.NewLimiter(rate.Limit(90), 1) // 每个DynamoDB请求前先等待令牌 err := limiter.Wait(context.TODO()) if err != nil { // 处理等待错误 } // 执行UpdateItem/PutItem/DeleteItem操作...
批量操作优化
把多个单条操作合并成BatchWriteItem调用,每个Batch最多可处理25个条目,大幅减少请求次数,降低吞吐量消耗。调整DynamoDB容量配置
如果经常需要处理大量数据,可选择:
- 临时提高预置WCU,处理完成后再调回
- 切换到按需模式(On-Demand),DynamoDB会自动根据流量扩容,无需手动配置容量
内容的提问来源于stack exchange,提问作者Steve Han
相关产品推荐
相关产品推荐

