Хранилище параметров AWS: AWSSimpleSystemsManagementException: превышена скорость

На данный момент мне нужно получить последние 10 значений некоторых параметров в AWS Parameters Store.

Я использую в котлине следующий код:

    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, вы можете получить только 50 значений в maxResults, поэтому мне нужно сделать 2 вызова для каждого параметра (потому что у меня более 50 версий)

Таким образом, каждое получение трех моих параметров стоит 6 запросов к SSM.

Я кэширую последние 10 значений каждого параметра в памяти на 5 минут

Проблема в том, что когда несколько экземпляров моих лямбда-выражений одновременно истекают из своего кеша, они выполняют извлечение одновременно и

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], в котором говорится, что мне нужно проанализировать сообщение об ошибке, но это старый пост (2013 г.), и это очень уродливо (в момент, когда AWS меняет сообщение, весь механизм рушится)!

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

Последнее замечание: я использую хранилище параметров с «автоматическим шифрованием» и IAM, я не хочу ни хранить параметры в моей собственной базе данных, ни кэшировать их в кеш-памяти общего доступа, например Redis!


person Christophe Blin    schedule 01.04.2019    source источник
comment
Похоже, вы используете SSM как базу данных, и они не хотят, чтобы она использовалась таким образом. Вам следует подумать о другом способе хранения такой информации.   -  person John Rotenstein    schedule 01.04.2019
comment
@JohnRotenstein Как было сказано в моей последней заметке, я уже рассматривал возможность реализации своего собственного механизма, но интеграция с ролями IAM и шифрованием (например, KMS) будет таким кошмаром! Кстати, хранение секретов рекламируется как функция SSM (требование извлечения нескольких версий исходит из того факта, что пользователь может использовать старый секрет в течение небольшого промежутка времени, а не только последний)   -  person Christophe Blin    schedule 02.04.2019
comment
Вы можете поймать ThrottlingException, подождать несколько секунд и повторить попытку, вызвав ту же функцию для x повторных попыток.   -  person abdullahkhawer    schedule 30.07.2019


Ответы (1)


Я нашел решение / обходной путь, которым поделюсь здесь.

Не стесняйтесь комментировать, если найдете лучший способ!

TL; DR: обходной путь работает, потому что он выполняет только 1 запрос к SSM (на лямбда) вместо 6 благодаря рекурсивному GetParametersByPath вместо GetParameterHistory.

Итак, для упрощения, мой вариант использования заключался в хранении секрета для шифрования токена и возможности использовать его в течение 10 часов.

Примечание: IRL, я использую 3 разных секрета, отсюда P1, P2, P3 в вопросе. Далее я упрощу и расскажу только об 1 секрете, поскольку он работает аналогично для любого количества секретов (пока вы не достигнете максимального количества параметров в SSM, которое составляет 10 КБ ...)

Раньше это работало так: я чередую секрет каждый час, я расшифровываю токен по последним 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).

Таким образом, каждая лямбда выполняет один запрос, вероятность достижения превышения RateExceeded очень мала.

Когда клиент отправляет токен, я пытаюсь расшифровать 10 текущих секретов.

Секретное вращение изменилось на: retrieve / current и изменение следующего (т.е. если current s4, мы меняем s5 и устанавливаем / current на s5)

В заключение, я также реализовал улучшение, которое заключается в добавлении / текущем токене (незашифрованном).

При этом мне не нужно сверяться с 10 секретами, а только с тем, что содержится в токене.

Обратите внимание, что я мог бы сделать это улучшение раньше (отправив номер версии в незашифрованном виде в токене), я просто не думал об этом раньше.

Надеюсь, это кому-то поможет

person Christophe Blin    schedule 02.04.2019
comment
Вариант использования действительно кажется настолько странно надуманным и противоречит ожидаемому шаблону использования SSM ... Я ожидал, что должен быть более простой способ использования DynamoDb или какого-либо другого средства AWS. - person MikeW; 22.06.2020