Para que go-cache sea tan útil como Memcache, necesita un límite superior en la cantidad de memoria que puede usar, de lo contrario, es fácil almacenar en caché demasiadas cosas y explotar el uso de memoria.
Idealmente, tendría un límite de memoria como lo hace Memcache. Podría ser algo aproximado, ya que estoy seguro de que no es particularmente fácil contabilizar la memoria utilizada en el caché.
Un límite máximo de objetos también probablemente sería útil.
Estoy de acuerdo en que sería útil, pero tal como está, sería bastante difícil como sugiere. go-cache, a diferencia de Memcached, no procesa / serializa la mayoría de los datos, sino que mantiene un puntero hacia ellos. Por supuesto, si bien esto hace que go-cache sea más rápido en órdenes de magnitud, también significa que no se distribuye de ninguna manera (como Memcached) y, desafortunadamente, no puede saber el tamaño de lo que está almacenando sin algunos Reflexión grave / magia insegura / sobrecarga.
La mejor solución probablemente sería crear un nuevo tipo de caché que almacene elementos que satisfagan una interfaz Sizeable donde foo.Size () representa su tamaño relativo como un número entero. Así es como lo hace el caché LRU de Vitess: https://code.google.com/p/vitess/source/browse/go/cache/lru_cache.go Esto transferiría esa responsabilidad al usuario. No estoy totalmente seguro de si los usuarios pueden determinar esto fácilmente en muchos casos, es decir, cuando están almacenando algo más complejo que, por ejemplo, una estructura con un campo de bytes [] o algo, como un mapa de estructuras o sectores.
Otra solución sería simplemente limitar la cantidad de elementos en la caché en un momento dado, pero eso supone que cada elemento de la caché tiene aproximadamente el mismo tamaño. El mayor problema con esto es elegir los elementos correctos para eliminarlos cuando sea necesario. Tal caché probablemente terminaría convirtiéndose en un clon de LRU (es decir, realiza un seguimiento de cuándo se accedió a los elementos por última vez y usa algo diferente a / además de un mapa para el almacenamiento) donde cada elemento tiene el mismo tamaño, por ejemplo, 1.
Seguiré pensando en la mejor manera de abordar esto en go-cache, pero mi intuición en este momento:
Gracias por la respuesta detallada y el enlace al caché de Vitess.
Creo que tiene razón en que el dimensionamiento de los objetos requeriría la ayuda del usuario. Pensé ingenuamente que podría introspectarse, pero tiene razón, los objetos pueden ser indicadores de estructuras arbitrariamente complicadas que pueden o no necesitar ser contabilizadas en la caché. El usuario podría intentar estimar el tamaño con una interfaz Sizeable
como sugirió.
Sigo pensando que un límite total de objetos sería útil. Supongamos que está almacenando sesiones de usuario durante 24 horas. Sin embargo, te encuentras en el extremo equivocado de una red de bots que hace muchas sesiones en un período de tiempo muy corto. Ese es el tipo de escenario en el que el uso de la memoria se dispara. Vaciar las sesiones de usuario no sería ideal en este caso, pero mantendría el servidor en funcionamiento en lugar de quedarse sin memoria.
Memcached ciertamente podría hacer el trabajo en este caso, pero me gusta la idea de hacerlo de manera realmente eficiente con go-cache
.
Me gustaría señalar que yo también creo que un límite de número total de objetos sería útil.
Pido disculpas por la demora. Todavía estoy pensando en cómo hacer esto bien, es decir, cómo desalojar elementos de la mejor manera sin implementar una copia de Vitess (y la sobrecarga de mantener una lista adicional de elementos / elementos de actualización en Get). Estoy de acuerdo en que es problemático si alguien explota su número de artículos.
¿No redis simplemente desaloja cosas del caché al azar? Creo que me importa más que mi caché esté limitada a la memoria que desalojar el elemento "incorrecto". Tal vez podamos hacer que el algoritmo real para desalojar se pueda conectar y comenzar con el desalojo aleatorio si no necesita una contabilidad elegante.
Me gusta más el enfoque LRU, pero con eso la preocupación es la sobrecarga para las cargas pesadas de lectura y el uso de memoria de Ctime / Atime para cada elemento en caché.
El desalojo aleatorio podría funcionar, pero no sé si hay una forma confiable de implementarlo, dado que el almacenamiento subyacente es map. El recorrido del mapa es impredecible pero no realmente aleatorio, por lo que no puede simplemente atravesar, elegir la primera clave y eliminarla: https://play.golang.org/p/lUw_1oPTLB Pero quizás eso sea menos preocupante para mapas más grandes ...
El desalojo aleatorio está bien para los cachés perezosos, pero cuando su caché es de lectura intensa, los objetos son costosos de generar y termina desalojando algunos elementos calientes (y, por lo tanto, inmediatamente pierde el caché), duele.
Momento interesante; esto acaba de llegar a HN: https://danluu.com/2choices-eviction/
Posiblemente podríamos tener ambas opciones, pero LRU todavía parece mejor dado que no tenemos una buena forma de seleccionar elementos aleatorios de la caché sin mantener alguna estructura de datos paralela.
También voy a votar por esta función. Seguiré usando esto, pero con mucha precaución. Un ataque de bot mataría mi servicio sin el límite superior.
Iba a usar esto para almacenar en caché los objetos de usuario en relación con las claves de sesión para no tener que presionar mi base de datos en cada solicitud. Así que el tiempo de expiración es genial para esto. Estaría bien con la caída aleatoria de entradas si fuera de tamaño. Sería incluso mejor si simplemente arrojara el objeto más antiguo, pero imagino que habría un éxito de rendimiento en eso.
buena idea, error Creo que la memoria máxima de límite de diseño es mejor.
Esto parece una característica importante que falta. Hay casos de uso en los que los tiempos de desalojo grandes tienen mucho sentido, pero la memoria caché debe estar limitada a la memoria; de lo contrario, el servicio eventualmente se quedará sin memoria y morirá. Cualquier tipo de limitación en ese sentido es mucho mejor que nada en mi opinión. Agregué este caché a nuestro sistema con gran facilidad, pero probablemente intentaré reemplazarlo con otro que admita esta característica vital.
Comentario más útil
También voy a votar por esta función. Seguiré usando esto, pero con mucha precaución. Un ataque de bot mataría mi servicio sin el límite superior.
Iba a usar esto para almacenar en caché los objetos de usuario en relación con las claves de sesión para no tener que presionar mi base de datos en cada solicitud. Así que el tiempo de expiración es genial para esto. Estaría bien con la caída aleatoria de entradas si fuera de tamaño. Sería incluso mejor si simplemente arrojara el objeto más antiguo, pero imagino que habría un éxito de rendimiento en eso.