AWS Parameter Store:AWSSimpleSystemsManagementException:超出速率
AWS Parameter Store : AWSSimpleSystemsManagementException: Rate exceeded
目前,我需要检索 AWS Parameters Store 中某些参数的最后 10 个值
我在 kotlin 中使用以下代码:
val p1 = retrieveAllValidVersions("P1")
val p2 = retrieveAllValidVersions("P2")
val p3 = retrieveAllValidVersions("P3")
这是 retrieveAllValidVersions
的代码
private fun retrieveAllValidVersions(paramName: String): List<ParameterHistory> {
val res = mutableListOf<ParameterHistory>()
val ssmClient = AWSSimpleSystemsManagementClientBuilder.defaultClient()
var nextToken : String? = null
do {
val ssmParams = ssmClient.getParameterHistory(GetParameterHistoryRequest()
.withName(paramName)
.withWithDecryption(true)
.withNextToken(nextToken)
)
res.addAll(ssmParams.parameters)
nextToken = ssmParams.nextToken
} while (nextToken != null)
return validVersions.sortedByDescending { it.version }.take(10)
}
如https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#limits_ssm所述,一个参数的最大版本数为 100
并且如https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetParameterHistory.html所述,您只能在 maxResults 中检索 50 个值,因此我需要为每个参数调用 2 次(因为我有 50 多个版本)
所以每次检索我的 3 个参数都会花费 6 次 SSM 查询
我将每个参数的最后 10 个值缓存在内存中 5 分钟
问题是当我的 lambda 的多个实例同时过期它们的缓存时,它们会同时进行检索并且
com.amazonaws.services.simplesystemsmanagement.model.AWSSimpleSystemsManagementException: Rate exceeded (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: ThrottlingException; Request ID: xxx)
例如,如果涉及 3 个实例,那将在不到一秒的时间内执行 18 个请求,我会遇到错误(注意:我不知道是否有同时命中此代码的实例数量时间是 3,这只是一个猜测,说明你在某个时候遇到了错误)
所以我有 2 个问题:
首先,有没有办法先检索参数的最新版本?
那样的话,我会做一半的请求,这样我就不会经常遇到问题!
其次,如何自动重试节流错误?
我发现这个 AWS 博客 [1] post 说我必须解析错误消息,但这是一个旧的 post (2013),而且非常难看(AWS 的那一刻更改消息,所有机制崩溃)!
最后一点:我将参数存储与 "auto-encryption" 和 IAM 一起使用,我不想将参数存储在我自己的数据库中,也不想将它们缓存在像 redis 这样的共享内存缓存中!
我找到了一个解决方案/解决方法,我将在此处分享。
如果您发现更好的方法,请随时发表评论!
TL;DR:由于 GetParametersByPath 递归而不是 GetParameterHistory,它只对 SSM(每个 lambda)发出 1 个请求而不是 6 个请求,因此解决方法有效。
所以,为了简化,我的用例是存储一个秘密来加密令牌并能够使用它 10 小时。
注意:IRL,我使用了 3 个不同的秘密,因此问题中使用了 P1、P2、P3。在下文中,我将简化并只讨论 1 个秘密,因为它对任何数量的秘密都类似地工作(直到达到 SSM 中的最大参数数量,即 10K ...)
它以前是这样工作的:我每小时轮换一次秘密,我根据最近 10 个版本解密令牌 -> 如果用户发送一个 11 小时或更长时间的令牌,我就不能再解密了。
现在,我不再使用具有多个版本的单个参数,而是使用多个参数,每个参数只有最后一个版本可以安全使用。
我的 SSM Parameter Store 以前看起来像(对于每个参数)
/secret/P1
现在看起来像
/secrets/P1/s1 -> a secret
/secrets/P1/s2 -> a secret
...
/secrets/P1/s10 -> a secret
/secrets/P1/current -> s4
我的代码现在使用递归方式执行 GetParametersByPath("/secrets") 以在一个请求中检索所有参数(即 P1、P2、P3)的所有有效机密。
所以每个lambda做一个请求,很少有机会命中RateExceeded。
当客户端发送令牌时,我尝试根据当前的 10 个密钥进行解密。
秘密轮换已更改为:检索 /current 并更改下一个(即,如果当前为 s4,我们更改 s5 并将 /current 设置为 s5)
作为最后的说明,我还实施了一项改进,即将 /current 添加到令牌(未加密)中。
这样做,我不需要检查 10 个秘密,只需检查令牌中包含的一个。
请注意,我之前本可以进行该改进(通过在令牌中发送未加密的版本号),只是我之前没有想到。
希望对某人有所帮助
目前,我需要检索 AWS Parameters Store 中某些参数的最后 10 个值
我在 kotlin 中使用以下代码:
val p1 = retrieveAllValidVersions("P1")
val p2 = retrieveAllValidVersions("P2")
val p3 = retrieveAllValidVersions("P3")
这是 retrieveAllValidVersions
的代码 private fun retrieveAllValidVersions(paramName: String): List<ParameterHistory> {
val res = mutableListOf<ParameterHistory>()
val ssmClient = AWSSimpleSystemsManagementClientBuilder.defaultClient()
var nextToken : String? = null
do {
val ssmParams = ssmClient.getParameterHistory(GetParameterHistoryRequest()
.withName(paramName)
.withWithDecryption(true)
.withNextToken(nextToken)
)
res.addAll(ssmParams.parameters)
nextToken = ssmParams.nextToken
} while (nextToken != null)
return validVersions.sortedByDescending { it.version }.take(10)
}
如https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#limits_ssm所述,一个参数的最大版本数为 100
并且如https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetParameterHistory.html所述,您只能在 maxResults 中检索 50 个值,因此我需要为每个参数调用 2 次(因为我有 50 多个版本)
所以每次检索我的 3 个参数都会花费 6 次 SSM 查询
我将每个参数的最后 10 个值缓存在内存中 5 分钟
问题是当我的 lambda 的多个实例同时过期它们的缓存时,它们会同时进行检索并且
com.amazonaws.services.simplesystemsmanagement.model.AWSSimpleSystemsManagementException: Rate exceeded (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: ThrottlingException; Request ID: xxx)
例如,如果涉及 3 个实例,那将在不到一秒的时间内执行 18 个请求,我会遇到错误(注意:我不知道是否有同时命中此代码的实例数量时间是 3,这只是一个猜测,说明你在某个时候遇到了错误)
所以我有 2 个问题:
首先,有没有办法先检索参数的最新版本?
那样的话,我会做一半的请求,这样我就不会经常遇到问题!
其次,如何自动重试节流错误?
我发现这个 AWS 博客 [1] post 说我必须解析错误消息,但这是一个旧的 post (2013),而且非常难看(AWS 的那一刻更改消息,所有机制崩溃)!
最后一点:我将参数存储与 "auto-encryption" 和 IAM 一起使用,我不想将参数存储在我自己的数据库中,也不想将它们缓存在像 redis 这样的共享内存缓存中!
我找到了一个解决方案/解决方法,我将在此处分享。
如果您发现更好的方法,请随时发表评论!
TL;DR:由于 GetParametersByPath 递归而不是 GetParameterHistory,它只对 SSM(每个 lambda)发出 1 个请求而不是 6 个请求,因此解决方法有效。
所以,为了简化,我的用例是存储一个秘密来加密令牌并能够使用它 10 小时。
注意:IRL,我使用了 3 个不同的秘密,因此问题中使用了 P1、P2、P3。在下文中,我将简化并只讨论 1 个秘密,因为它对任何数量的秘密都类似地工作(直到达到 SSM 中的最大参数数量,即 10K ...)
它以前是这样工作的:我每小时轮换一次秘密,我根据最近 10 个版本解密令牌 -> 如果用户发送一个 11 小时或更长时间的令牌,我就不能再解密了。
现在,我不再使用具有多个版本的单个参数,而是使用多个参数,每个参数只有最后一个版本可以安全使用。
我的 SSM Parameter Store 以前看起来像(对于每个参数)
/secret/P1
现在看起来像
/secrets/P1/s1 -> a secret
/secrets/P1/s2 -> a secret
...
/secrets/P1/s10 -> a secret
/secrets/P1/current -> s4
我的代码现在使用递归方式执行 GetParametersByPath("/secrets") 以在一个请求中检索所有参数(即 P1、P2、P3)的所有有效机密。
所以每个lambda做一个请求,很少有机会命中RateExceeded。
当客户端发送令牌时,我尝试根据当前的 10 个密钥进行解密。
秘密轮换已更改为:检索 /current 并更改下一个(即,如果当前为 s4,我们更改 s5 并将 /current 设置为 s5)
作为最后的说明,我还实施了一项改进,即将 /current 添加到令牌(未加密)中。
这样做,我不需要检查 10 个秘密,只需检查令牌中包含的一个。
请注意,我之前本可以进行该改进(通过在令牌中发送未加密的版本号),只是我之前没有想到。
希望对某人有所帮助