使用JMeter测试Lambda函数时出现间歇性签名过期错误求助
解决高负载下AWS Sig4签名过期导致的间歇性403错误
在对AWS部署的应用进行千万级并发负载测试时,应用链路为API Gateway调用Lambda函数、Lambda再与S3交互。设置约1500 RPS限流后,出现间歇性403禁止错误,错误信息如下:
{"message":"Signature expired: 20221104T181501Z is now earlier than 20221104T182505Z (20221104T183005Z - 5 min.)"}
该错误仅在高负载及特定RPS下出现,正常负载时无异常。根因是Blazemeter的RPS限流机制会让请求先进入等待队列,当前流程是预处理器生成Sig4签名→等待限流延迟→发送HTTP请求,导致签名生成时的x-amz-date时间与实际请求发送时间差超过AWS Sig4默认的5分钟有效期,触发签名过期判断。
以下是可行的解决方法:
方法1:调整执行顺序,让限流等待在签名生成前完成
放弃Blazemeter自带的全局RPS限流,改用JMeter的Constant Throughput Timer(恒定吞吐量定时器)控制RPS,并将定时器和Sig4预处理器都设为HTTP请求采样器的直接子节点。这样执行顺序会变为:
- 启动HTTP请求采样器
- 先触发Constant Throughput Timer完成等待(满足RPS要求)
- 再执行预处理器生成实时Sig4签名(此时
x-amz-date与实际请求时间几乎无差) - 最后发送HTTP请求
方法2:在请求发送前实时生成签名
如果必须保留Blazemeter的RPS限流,修改原Groovy预处理器逻辑,将签名生成延迟到请求即将发送的时刻:
- 把AWS密钥、请求路径等固定参数提前存在JMeter变量中
- 用JSR223 Sampler替代原HTTP请求采样器,在Sampler内部完成签名生成与请求发送。示例代码框架:
// 从JMeter变量获取配置参数 def accessKey = vars.get("AWS_ACCESS_KEY") def secretKey = vars.get("AWS_SECRET_KEY") def apiEndpoint = vars.get("API_GATEWAY_ENDPOINT") // 实时生成UTC时间作为x-amz-date def utcTimeZone = TimeZone.getTimeZone("UTC") def currentDate = new Date().format("yyyyMMdd'T'HHmmss'Z'", utcTimeZone) def dateStamp = new Date().format("yyyyMMdd", utcTimeZone) // 复用原预处理器的Sig4签名生成逻辑,使用currentDate作为时间参数 // ... 此处插入原预处理器中的签名计算代码,生成Authorization头内容 // 构建并发送HTTP请求 def httpClient = org.apache.http.impl.client.HttpClients.createDefault() def httpRequest = new org.apache.http.client.methods.HttpPost(apiEndpoint) httpRequest.setHeader("x-amz-date", currentDate) httpRequest.setHeader("Authorization", generatedSignature) // 添加请求体、其他必要头信息 // 执行请求并处理响应 def response = httpClient.execute(httpRequest) vars.put("RESPONSE_STATUS", response.getStatusLine().getStatusCode().toString()) httpClient.close()
方法3:临时延长签名有效期(不推荐)
AWS Sig4支持通过X-Amz-Expires参数设置签名有效期,最长可设为7天。但此方法会降低签名安全性,仅适合临时测试场景:
- 在请求中添加
X-Amz-Expires: 3600(设置1小时有效期) - 修改预处理器代码,将该参数纳入Sig4的签名计算流程(确保签名包含该参数的哈希值)
内容的提问来源于stack exchange,提问作者Kaushlendra Jha
相关产品推荐
相关产品推荐

