Usando Memcached: ¿es una buena práctica actualizar el caché cuando se actualiza la base de datos?

13

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

Nuestra arquitectura actual

Tengo una clase de PHP que accede a MySQL para obtener información del usuario. Llamémoslo User . Se accede a User 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". Una vez que los datos se han recuperado 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 en función de cada solicitud, este caché solo impide 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 en ocasiones es imperativo que algunos datos estén lo más actualizados posible. En el lapso de unos cinco minutos, una solicitud de lectura de 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 falla.

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 algún problema de rendimiento u otros "errores" que debamos tener en cuenta al intentar mantener una especie de "caché viviente" como este?

    
pregunta Stephen 29.12.2011 - 17:37

2 respuestas

10

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

No veo 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ás un envoltorio en tu actualización de base de datos (lo que has hecho). Su código para actualizar al usuario en la base de datos y en la RAM también debe hacer un empuje a memcached, O una caducidad 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 caché (por ejemplo, el puntaje total): debe caducar de inmediato.

Si, sin embargo, van a actualizar los datos (por ejemplo, el estado actual del juego) y luego, 0,2 segundos más tarde, tendrá una visita inmediata a la página PHP que solicitará los datos, por lo que querría tenerlos en la caché.

    
respondido por el jasonk 06.01.2012 - 12:16
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 pueden almacenarse 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 cambie, por lo que no envía correos a la dirección incorrecta, pero es poco probable que la fecha de nacimiento o apellido del usuario sea necesaria. estar completamente actualizado para proporcionar una experiencia de usuario decente. (N.B. No estoy usando un ejemplo de arquitectura de juego porque no sé a qué tipo de juego apuntar, y creo que este es bastante fácil de entender).

De esta manera, tiene dos conjuntos claros de datos: datos almacenables a corto y largo plazo. Es probable que pueda salir con una duración de la memoria caché de aproximadamente un minuto en los datos a corto plazo, solo para aliviar la carga en la base de datos, pero los datos a largo plazo pueden dejarse en la memoria caché en una duración variable mientras sea utilizado.

Entonces necesitas lidiar con las actualizaciones. Primero observaría el uso de un desencadenante de base de datos para eliminar simplemente los elementos de la memoria 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 están utilizando los datos (por ejemplo, si un usuario cambia su dirección de correo electrónico y 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 ver simplemente desencadenar la llamada de la memoria caché una vez que el elemento se haya eliminado 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 garantizar que el retraso inducido por 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 cualquier 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 los errores, lo principal que debe tener cuidado si está escribiendo directamente en el caché es la sincronización. Si muchos subprocesos intentan leer mientras realiza su actualización silenciosa, es posible que tenga algunos problemas graves de datos no válidos, lo que anulará el hecho de intentar mantener los datos actualizados en primer lugar.

    
respondido por el Ed James 06.01.2012 - 12:30

Lea otras preguntas en las etiquetas