Uso de Memcached: ¿es una buena práctica actualizar el caché al actualizar la base de datos?

13

Esta pregunta es sobre las mejores prácticas en arquitectura.

Nuestra arquitectura actual

Tengo una clase PHP que accede a MySQL para obtener información del usuario. Digamos que es User. Userse accede muchas veces, por lo que hemos implementado capas de almacenamiento en caché para reducir la carga.

La primera capa es lo que llamamos el caché "por solicitud". Después de recuperar los datos de MySQL, almacenamos los datos en una propiedad privada de User. Cualquier solicitud posterior de los datos devuelve la propiedad en lugar de volver a solicitar los datos de MySQL.

Dado que la solicitud web vive y muere por solicitud, este caché solo evita que la aplicación acceda a MySQL más de una vez en una sola solicitud.

Nuestra segunda capa es Memcached. Cuando la propiedad privada está vacía, primero verificamos los datos en Memcached. Si Memcached está vacío, consultamos los datos de MySQL, actualizamos Memcached y actualizamos la propiedad privada de User.

La pregunta

Nuestra aplicación es un juego, y a veces es imperativo que algunos datos estén lo más actualizados posible. En el lapso de aproximadamente cinco minutos, una solicitud de lectura para los datos del usuario puede ocurrir 10 u 11 veces; entonces puede ocurrir una actualización. Las solicitudes de lectura posteriores deben estar actualizadas o la mecánica del juego fallará.

Entonces, lo que hemos hecho es implementar un fragmento de código que se ejecuta cuando ocurre una actualización de la base de datos. Este código establece la clave en Memcached con los datos actualizados, por lo que todas las solicitudes posteriores a Memcached están actualizadas.

¿Es esto óptimo? ¿Hay alguna inquietud de rendimiento u otras "trampas" que deberíamos tener en cuenta al tratar de mantener una especie de "caché viva" como esta?

Stephen
fuente
¿Qué tiene esto que ver con eliminar y volver a agregar datos?
Mike Nakis
Aclaró el título de la pregunta.
Stephen
¿Por qué no simplemente caducar los datos en caché? Actualizarlo significa que deberá asegurarse de que la actualización se mantenga (de modo que si es necesario actualizar los datos nuevos de esta manera, deberá continuar cambiando la actualización). La expiración del caché significa que todo se extrae nuevamente de la base de datos --- y cualquier actualización nueva no necesita nuevos cambios en el código de actualización. La desventaja es que la carga de la base de datos podría ser mayor.
Peter K.
@ Peter Sí, también pensamos en eso. Si no surgen otros problemas con nuestro enfoque actual, nos quedaremos con él. De lo contrario, podemos seguir con lo que ha descrito.
Stephen
1
@Stephen El enfoque que describe se llama "Escribir a través de la caché" y es un enfoque bastante común.
Sripathi Krishnan

Respuestas:

10

Mi recomendación es mirar su perfil de uso y sus requisitos para el caché.

No puedo ver ninguna razón por la que dejaría datos obsoletos en Memcached. Creo que ha elegido el enfoque correcto, es decir: actualizar la base de datos.

En cualquier caso, necesitará un contenedor en su actualización de base de datos (lo que ha hecho). Su código para actualizar el usuario en la base de datos y en la RAM también debe hacer un empuje a memcached, o una expiración en memcached.

Por ejemplo: si sus usuarios normalmente realizan una actualización una vez por sesión como parte del cierre de sesión, no tiene mucho sentido actualizar los datos en la memoria caché (por ejemplo, un puntaje alto total), debe expirarlo de inmediato.

Sin embargo, si van a actualizar los datos (p. Ej., El estado actual del juego) y luego, 0.2 segundos más tarde, tendrán un acceso inmediato a la página PHP que solicitará los datos, lo desearán frescos en el caché.

jasonk
fuente
3

No lo haría como lo describiste. Lo que debe hacer es decidir si realmente NECESITA datos completamente actualizados. Luego, si lo necesita, decida qué partes de los datos deben estar actualizadas en todo momento y sepárelas de las cosas que se pueden almacenar en caché en su arquitectura.

Por ejemplo, es probable que desee actualizar la dirección de correo electrónico de su usuario tan pronto como la cambien, de modo que no envíe correos a la dirección incorrecta, pero es poco probable que la fecha de nacimiento o apellido del usuario sea completamente actualizado para proporcionar una experiencia de usuario decente. (Nota: no estoy usando un ejemplo de arquitectura de juego, ya que no sé a qué tipo de juego apuntar, y creo que este es bastante fácil de entender).

De esta forma, tiene dos conjuntos claros de datos: datos almacenables en caché a corto y largo plazo. Probablemente pueda salirse con una duración de caché de un minuto más o menos en los datos a corto plazo, solo para aliviar la carga en la base de datos, pero los datos a largo plazo se pueden dejar en la memoria caché con una duración variable durante el tiempo que sea usado.

Entonces necesitas lidiar con las actualizaciones. Primero miraría el uso de un disparador de base de datos para simplemente eliminar elementos del caché una vez que estén desactualizados. Eso obligará a su capa empresarial a activar una actualización de la memoria caché la próxima vez que solicite los datos, liberando algo de espacio en la memoria caché si no se utilizan los datos (por ejemplo, si un usuario cambia su dirección de correo electrónico y luego se desconecta de inmediato) . Si esto va a causar problemas de rendimiento en la interfaz de usuario (es decir, introducir demasiado retraso mientras se esperan las actualizaciones de la memoria caché), puede mirar simplemente desencadenar la llamada de la memoria caché una vez que el elemento se elimine de la memoria caché. También me gustaría optimizar los tiempos de lectura de la base de datos para este pequeño conjunto de datos, para asegurar que cualquier retraso inducido en la actualización de la memoria caché sea mínimo (esto debería ser más fácil ya que solo necesita cargar los datos que realmente necesita).

Lo que no haría, en ninguna circunstancia, es agregar un método adicional para llenar el caché, ya que entonces deberá mantener la llamada (y los enlaces de API, etc.) en dos lugares.

En cuanto a las trampas, lo principal que debe tener cuidado si está escribiendo directamente en el caché es la sincronización. Si muchos hilos intentan leer mientras realiza su actualización silenciosa, es posible que tenga algunos problemas serios de datos no válidos, lo que anulará el punto de tratar de mantener los datos actualizados en primer lugar.

Ed James
fuente