使用Go Aurora SDK偶连至只读实例的问题排查求助
解决Lambda中Go连接Serverless Aurora的只读模式错误问题
核心原因
Serverless Aurora缩容至0再恢复后,集群的读写端点映射会重置;同时Lambda执行环境的容器复用会导致RDS Data API客户端被缓存,旧客户端可能仍指向只读实例,而默认SDK配置没有自动处理这种路由切换的情况。
解决方案
1. 避免复用RDS Data客户端
Lambda容器复用会让全局的客户端实例长期存在,缓存旧的集群路由信息。将客户端创建逻辑放到每次查询的函数内部,确保每次请求使用全新的客户端:
func runWriteQuery(ctx context.Context, clusterARN, secretARN, dbName, sql string) error { region := "eu-west-2" cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region)) if err != nil { return err } // 每次查询创建新客户端 auroraClient := rdsdata.NewFromConfig(cfg) input := &rdsdata.ExecuteStatementInput{ ResourceArn: &clusterARN, SecretArn: &secretARN, Database: &dbName, Sql: &sql, FormatRecordsAs: types.RecordsFormatTypeJson, } _, err = auroraClient.ExecuteStatement(ctx, input) return err }
2. 针对只读错误添加重试机制
当遇到错误代码1836的只读异常时,触发重试,让SDK重新路由到可用的读写实例:
import ( "context" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/rdsdata" "github.com/aws/aws-sdk-go-v2/service/rdsdata/types" "github.com/aws/smithy-go" ) func createRetryEnabledConfig(ctx context.Context) (aws.Config, error) { cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("eu-west-2")) if err != nil { return aws.Config{}, err } // 自定义重试逻辑,匹配只读错误 cfg.Retryer = aws.RetryerFunc(func(ctx context.Context, attempt int, err error) (aws.RetryToken, bool) { if apiErr, ok := err.(smithy.APIError); ok { if apiErr.ErrorCode() == "DatabaseErrorException" { if dbErr, ok := apiErr.(*types.DatabaseErrorException); ok && dbErr.ErrorCode == "1836" { // 允许重试该只读错误 return nil, true } } } // 其他错误使用默认重试规则 return aws.NoRetryToken, false }) return cfg, nil } // 使用带重试的客户端执行查询 func executeWithRetry(ctx context.Context, clusterARN, secretARN, dbName, sql string) error { cfg, err := createRetryEnabledConfig(ctx) if err != nil { return err } auroraClient := rdsdata.NewFromConfig(cfg) input := &rdsdata.ExecuteStatementInput{ ResourceArn: &clusterARN, SecretArn: &secretARN, Database: &dbName, Sql: &sql, FormatRecordsAs: types.RecordsFormatTypeJson, } _, err = auroraClient.ExecuteStatement(ctx, input) return err }
3. 可选:指定读写实例ARN(不推荐)
如果集群有固定的读写实例,可以直接将ResourceArn设置为读写实例的ARN,跳过集群路由。但此方案会丢失集群自动故障转移的能力,仅适用于读写实例固定不变的场景:
input := &rdsdata.ExecuteStatementInput{ ResourceArn: &writerInstanceARN, // 替换为你的读写实例ARN SecretArn: &auroraSecretsStoreARN, Database: &auroraDatabaseName, Sql: &sqlStatement, FormatRecordsAs: types.RecordsFormatTypeJson, }
最优实践
结合每次请求创建新客户端和只读错误重试,既能解决Lambda容器复用导致的缓存问题,又能应对集群恢复后的路由切换,是最稳定的解决方案。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

