AWS参数存储:AWSSimpleSystemsManagementException:超出速率

问题描述 投票:1回答:1

目前,我需要在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个参数的每次检索都需要对SSM进行6次查询

我将每个参数的最后10个值缓存在内存中5分钟

问题是当我的lambdas的多个实例同时到期时,他们会同时进行检索。

com.amazonaws.services.simplesystemsmanagement.model.AWSSimpleSystemsManagementException: Rate exceeded (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: ThrottlingException; Request ID: xxx)

例如,如果涉及3个实例,那将在不到一秒的时间内完成18个请求,我将发现错误(注意:我不确切地知道同时命中此代码的实例数是否为3,这个只是猜测,在某些时候你会遇到错误)

所以我有两个问题:

首先,有没有办法首先检索参数的最新版本?

这样,我会做一半的请求,所以我会不经常遇到问题!

其次,如何自动重试限制错误?

我发现这个AWS博客[1]帖子说我必须解析错误消息,但这是一篇旧帖子(2013),这非常难看(当AWS更改消息时,所有机制都崩溃了)!

[1]:https://aws.amazon.com/fr/blogs/messaging-and-targeting/how-to-handle-a-throttling-maximum-sending-rate-exceeded-error/

最后一点:我使用带有“自动加密”和IAM的参数存储,我不想将参数存储在我自己的数据库中,也不想将它们缓存在像redis这样的共享内存缓存中!

amazon-web-services aws-sdk aws-parameter-store
1个回答
0
投票

我找到了一个解决方案/解决方法,我将在这里分享。

如果您找到更好的方法,请随时评论!

TL; DR:解决方法有效,因为它只对SSM(每个lambda)发出1个请求而不是6个,这要归功于GetParametersByPath递归而不是GetParameterHistory。

因此,为了简化,我的用例是存储一个秘密来加密令牌并能够使用它10个小时。

注意:IRL,我使用3个不同的秘密,因此问题中的P1,P2,P3。在下文中,我将简化并仅讨论1个秘密,因为它对于任何数量的秘密都是类似的(直到你达到SSM中10K的最大参数数量......)

它之前的工作原理如下:我每小时轮换一次秘密,我对最后10个版本的令牌进行解密 - >如果用户发送了11个小时或更长时间的令牌,我就不能再解密了。

现在,我没有一个具有多个版本的参数,而是有多个参数,每个参数只能安全使用。

我的SSM参数存储以前看起来像(对于每个参数)

/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个当前机密。

秘密轮换已更改为:检索/当前并更改下一个(即如果当前是s4,我们更改s5并将/ current设置为s5)

最后,我还实现了一项改进,即在令牌中添加/当前(未加密)。

这样做,我不需要检查10个秘密,只针对令牌中包含的秘密。

请注意,我之前可以完成这项改进(通过在令牌中发送未加密的版本号),我之前没想过。

希望能帮助别人

© www.soinside.com 2019 - 2024. All rights reserved.