← Tornar al blog

Optimització de costos: Cache de Secrets i DynamoDB amb Redis/Valkey

March 19, 2025

En aplicacions que fan un ús intensiu de Secrets Manager i DynamoDB, els costos operatius poden disparar-se ràpidament si no s’aplica una estratègia d’optimització adequada. En aquest article, comparteixo com hem implementat una solució de cache amb Redis (i posteriorment Valkey) que ens ha permès reduir els costos d’aquests serveis de 300$ a 45$ mensuals, tot millorant la latència de les nostres aplicacions.

El problema: Costos desproporcionats en API calls

La nostra arquitectura consistia en diversos components que accedien freqüentment a secrets i dades de configuració:

Components afectats:

El problema principal? Cada vegada que un worker o la web necessitava un secret o una configuració, feia una petició directa a AWS Secrets Manager o DynamoDB. Això significava:

La solució: Capa de cache amb Redis

L’estratègia va ser senzilla però efectiva: interposar una capa de cache entre l’aplicació i els serveis d’AWS.

Arquitectura inicial: Redis in-cluster

La primera implementació va utilitzar Redis desplegat dins del clúster Kubernetes:

Característiques:

Beneficis immediats:

  1. Reducció dràstica de peticions: La gran majoria de consultes es servien des de cache
  2. Millora de latència: Les consultes locals eren significativament més ràpides
  3. Cost menor: El cost de Redis dins del clúster era insignificant comparat amb l’estalvi

Implementació: Patró Cache-Aside

Per a la implementació, vam utilitzar el patró Cache-Aside (també conegut com Lazy Loading):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Pseudocodi del patró Cache-Aside
def get_secret(secret_name):
    # 1. Primer, intentem obtenir del cache
    cached_value = redis.get(f"secret:{secret_name}")
    if cached_value:
        return cached_value

    # 2. Si no existeix al cache, anem a la font
    secret_value = secrets_manager.get_secret_value(secret_name)

    # 3. Guardem al cache amb un TTL adequat
    redis.setex(f"secret:{secret_name}", 3600, secret_value)

    return secret_value

Estratègia de TTL:

Migració a Valkey (AWS)

Un cop vam validar que l’approach de cache funcionava correctament, vam decidir migrar a Valkey gestionat per AWS (ElastiCache).

Per què Valkey?

Valkey és el projecte open source que va sorgir després de la divergència de Redis. AWS va adoptar-lo com a opció per defecte per ElastiCache.

Avantatges de la migració:

  1. Gestió reduïda: No cal gestionar la infraestructura del cache
  2. Alta disponibilitat: Replicació automàtica i failover
  3. Escalabilitat: Fàcil escalar verticalment o horitzontalment
  4. Monitoratge: Integració nativa amb CloudWatch
  5. Seguretat: Encriptació en trànsit i repòs

Configuració implementada:

Resultats quantificables

Estalvi en costos

Abans (sense cache):

Després (amb Valkey):

Estalvi total: 255$/mes (85% de reducció)

Millora en rendiment

Més enllà de l’estalvi econòmic, les millores de rendiment han estat significatives:

Beneficis operatius

  1. Reducció de dependències externes: La majoria de peticions no surten del clúster
  2. Millor experiència d’usuari: Les APIs responen més ràpid
  3. Menys limitacions: Reducció significativa de throttling a Secrets Manager i DynamoDB
  4. Escalabilitat: El sistema pot gestionar més càrrega amb els mateixos recursos

Lliçons apreses

1. No cal fer caché de tot

És important analitzar quines dades es beneficien realment del cache:

2. La mida importa

La mida de la instància de Valkey s’ha d’ajustar segons:

En el nostre cas, un cache.t4g.small ha estat suficient, però cal monitorar.

3. Monitoratge és clau

Hem implementat alertes per:

4. Planificant la fallback

Sempre hem de tenir un pla per si Valkey cau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def get_with_fallback(key, fetcher, ttl=3600):
    try:
        # Intent obtenir del cache
        cached = redis.get(key)
        if cached:
            return cached
    except RedisError:
        # Si Redis falla, anem directament a la font
        pass  # Fallback

    # Obtenir de la font (AWS)
    value = fetcher()

    # Intentar cachar (opcional, pot fallar)
    try:
        redis.setex(key, ttl, value)
    except RedisError:
        pass  # No fallar l'operació si cache falla

    return value

Aquesta estratègia garanteix que el sistema segueixi funcionant encara que el cache falli.

Conclusió

La implementació d’una capa de cache amb Redis/Valkey entre la nostra aplicació i els serveis d’AWS (Secrets Manager i DynamoDB) ha estat una de les optimitzacions més impactants que hem realitzat.

Resultats finals:

La clau de l’èxit ha estat:

  1. Analitzar el patró d’ús abans d’implementar
  2. Començar senzill (Redis in-cluster) i després escalar (Valkey AWS)
  3. Implementar estratègies adequades de TTL i invalidació
  4. Monitoritzar contínuament per optimitzar
  5. Planificar el fallback per garantir disponibilitat

Per a qualsevol aplicació que faci un ús intensiu de Secrets Manager, DynamoDB o qualsevol servei d’AWS amb costos per API call, l’ús d’un cache com Valkey és, gairebé segur, una de les millors inversions que pots fer. El retorn és immediat, tant en costos com en rendiment.

Si la teva aplicació té una factura mensual elevada en aquests serveis, t’encoratjo a provar aquesta estratègia. Els resultats, com hem vist nosaltres, poden ser sorprenents.