Groupcache: Práctica recomendada para actualizar una entrada de caché con frecuencia

Creado en 8 mar. 2015  ·  9Comentarios  ·  Fuente: golang/groupcache

Mi pregunta es un poco similar al problema https://github.com/golang/groupcache/issues/3.

Tengo un mapa que actualmente se administra en la RAM de la aplicación go en una sola instancia. Quiero compartir este mapa entre varias instancias para escalar. Ya estoy usando consul para el descubrimiento de instancias de pares y actualmente estoy resolviendo esto con redis, sin embargo, no estoy contento con el hecho de que no estoy aprovechando la RAM de cada máquina (así que en ese sentido siento que redis es más una base de datos que una cache). Esta es una de las razones por las que me encanta groupcache.

Sin embargo, tengo una restricción: mi mapa cambia todo el tiempo (recibo solicitudes para actualizarlo a través de http). Entonces, para una clave K1 en el mapa, es probable que m [K1] se actualice con mucha frecuencia (posiblemente cada segundo o menos).

Entonces mis preguntas son:

  1. ¿Estoy eligiendo la arquitectura incorrecta? ¿Debería usar algo como Redis o memecached en su lugar?
  2. Si groupcache es una buena solución para mi caso de uso, ¿tengo que eliminar y agregar constantemente (por ejemplo, en un caché LRU) o hay una forma más inteligente?

¡Gracias!

Comentario más útil

Hola @orcaman. Solo soy otro usuario de Groupcache, pero espero poder responder a su pregunta.

En primer lugar, las dos cosas más importantes que debe recordar son que Groupcache es un caché de solo lectura, lo que significa que no puede actualizar las claves en él. y segundo, que los datos se consideran inmutables y no vencedores. Básicamente es solo una LRU distribuida. Entonces, si necesita actualizar las claves con frecuencia, GC no es una buena opción.

Sin embargo, puede emular la caducidad o el cambio de datos existentes mediante la manipulación de claves.

En mi caso, necesitaba una caducidad de aproximadamente una hora para las llaves. Lo que hice fue agregar la marca de tiempo de la siguiente hora redonda a cualquier clave que esté tratando de obtener. Por lo tanto, cuando pasa una hora, esta parte de la clave de mi aplicación solicita cambios y, desde el punto de vista de Groupcache, pido una nueva clave. El viejo será desalojado a través del mecanismo LRU ya que nadie lo toca.

Pero si necesita escribir claves constantemente y vencer en la segunda resolución, es mejor que use redis o memcache. Elegiría Memcache porque es más fácil de escalar con más servidores.

Todos 9 comentarios

Hola @orcaman. Solo soy otro usuario de Groupcache, pero espero poder responder a su pregunta.

En primer lugar, las dos cosas más importantes que debe recordar son que Groupcache es un caché de solo lectura, lo que significa que no puede actualizar las claves en él. y segundo, que los datos se consideran inmutables y no vencedores. Básicamente es solo una LRU distribuida. Entonces, si necesita actualizar las claves con frecuencia, GC no es una buena opción.

Sin embargo, puede emular la caducidad o el cambio de datos existentes mediante la manipulación de claves.

En mi caso, necesitaba una caducidad de aproximadamente una hora para las llaves. Lo que hice fue agregar la marca de tiempo de la siguiente hora redonda a cualquier clave que esté tratando de obtener. Por lo tanto, cuando pasa una hora, esta parte de la clave de mi aplicación solicita cambios y, desde el punto de vista de Groupcache, pido una nueva clave. El viejo será desalojado a través del mecanismo LRU ya que nadie lo toca.

Pero si necesita escribir claves constantemente y vencer en la segunda resolución, es mejor que use redis o memcache. Elegiría Memcache porque es más fácil de escalar con más servidores.

¡Gracias @dvirsky !
Creo que me hago una idea.

No hay problema, aunque esperaba una mayor adopción de Groupcache en la escena israelí. ¿Conoce otras empresas que lo utilicen? :)

Todavía podríamos usarlo, solo esperando el caso de uso correcto. :-)
No conozco muchos topos en la escena israelí, por lo que no sabría sobre los usuarios de Groupcache. Espero conocerte en la próxima reunión de Go (si vas a venir, claro está).

Frio. Lo estamos usando como una caché HTTP saliente (es decir, las solicitudes de caché que estamos haciendo a terceros). Podríamos abrir esta implementación en algún momento.
No estoy seguro de la reunión de Go, espero lograrlo.

@dvirsky y @bradfitz : en mi caso de uso, me gustaría manejar TTL [Planificación para agregar la marca de tiempo de la hora actual a la clave]. Tengo las siguientes preguntas,

1.¿Cómo el mecanismo LRU quita la llave? ¿Podemos establecer una duración mínima en la que no se utiliza la clave [para marcarla como caducada]?
De lo contrario, ¿depende de la memoria asignada para el caché? Cuando los datos superen los asignados, ¿se eliminarán los utilizados menos recientemente? En ese caso, ¿cómo podemos manejar el saldo de la memoria para no eliminar los datos de la hora actual?

¿Podría dar algunas sugerencias para esto?

@dvirsky Gracias por su gran respuesta. Sin embargo, ¿ve un pequeño aumento de CPU y memoria cada hora cuando los elementos se "desalojan" al mismo tiempo?

@qbig , depende de cómo haya implementado la caducidad. Esto es lo que hice:

// turn a ttl into an expiration timestamp, using discrete time windows.
// i.e. ask for an hour and get the nearest hour end as the expiration point.
//
// We pad these discrete boundaries  pseudo random margin (based on hashing the key)
// to avoid hitting the cache too hard if all requests expire at once
//
// This can be seconds from now even if you cache for days :)
func calcExpiration(ttl int64, key string, now int64) int64 {
    //we calculate the non discrete expiration, relative to current time
    expires := now

    var padding int64 = 0
    if ttl > 0 {
        // now we want to pad it so we'll no expire all reqeusts for a given time window at once
        // to be consistent, the seed of the padding is a hash on the url
        h := fnv.New32a()
        h.Write([]byte(key))
        padding = int64(h.Sum32()) % ttl

               // not sure this is correct - I wrote it long ago :)
        expires += (ttl - (expires % ttl)) - padding
        if expires < now {
            expires += ttl
        }

    }

    return expires

}

@orcaman echa un vistazo a https://tarantool.org/

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

yml picture yml  ·  3Comentarios

cowboyrushforth picture cowboyrushforth  ·  5Comentarios

abennett picture abennett  ·  3Comentarios

AlexanderChen1989 picture AlexanderChen1989  ·  6Comentarios

dbanck picture dbanck  ·  3Comentarios