database - ¿Qué es el almacenamiento en caché?
caching (9)
Constantemente escucho sobre la persona y tuve un problema de rendimiento x que resolvieron a través del almacenamiento en caché.
O bien, cómo hacer x, y, z en el código de tu programa puede dañar tu capacidad de almacenamiento en caché.
Incluso en uno de los últimos podcasts, Jeff Atwood habla sobre cómo almacenan en caché ciertos valores para una recuperación rápida.
Parece que hay cierta ambigüedad en los términos "caché" y "almacenamiento en caché" y me ha llevado a estar confundido sobre su significado en diferentes casos. Si se refiere al almacenamiento en caché de la aplicación o de la base de datos, a la CPU, etc., y lo que eso significa.
¿Qué es el almacenamiento en caché y cuáles son los diferentes tipos?
Desde el contexto puedo entenderlo, almacenar un valor recuperado a menudo en la memoria principal y tener acceso rápido a él. Sin embargo, ¿qué es realmente ?
Esta palabra parece usarse en muchos contextos diferentes con un significado ligeramente diferente (CPU, base de datos, aplicación, etc.) y realmente estoy buscando aclararlo.
¿Hay alguna diferencia entre cómo funciona el almacenamiento en caché en sus aplicaciones frente al almacenamiento en caché de su base de datos?
Cuando alguien dice que encontró un código que dañaría el almacenamiento en caché y, una vez que lo arreglaron, mejoró la velocidad de su aplicación, ¿de qué están hablando?
¿El caché del programa es algo que se hace automáticamente? ¿Cómo permite que los valores se guarden en caché en sus programas? A menudo he leído a los usuarios en este sitio decir que almacenaron en caché un valor en su aplicación, me siento aquí y me pregunto qué significan.
Además, ¿qué significa realmente cuando alguien habla sobre el almacenamiento en caché de la base de datos? ¿Es esto simplemente una característica que encienden en su base de datos? ¿Tiene que caché explícitamente valores o la base de datos elige cuáles almacenar en caché para usted?
¿Cómo comienzo a almacenar en caché los elementos para mejorar el rendimiento?
¿Me puede dar algunos ejemplos de cómo puedo comenzar a almacenar valores en caché en mis aplicaciones ? O bien, ¿esto es algo que ya está hecho, bajo el capó y simplemente tengo que escribir mi código de una manera particular para permitir el "almacenamiento en caché"?
¿Qué pasa con el almacenamiento en caché de la base de datos, cómo empiezo eso? He escuchado sobre cosas como Memcache. ¿Se requiere este tipo de utilidad para almacenar en caché las bases de datos?
Estoy buscando una buena distinción entre el almacenamiento en caché en las aplicaciones frente a las bases de datos, cómo se usan y cómo se implementa en ambos casos.
El almacenamiento en caché no se aplica necesariamente solo a los valores "recuperados", sino a cualquier cosa en la que pueda ahorrar tiempo reduciendo el número de veces que lo vuelve a calcular. Un ejemplo simple que viene a la mente es calcular la secuencia de fibonacci . La implementación recursiva más simple se ve así (en código psuedo):
function f(n)
if n < 2 then
return n;
return f(n - 1) + f(n - 2)
Esto se puede mejorar con el almacenamiento en caché para evitar volver a calcular los valores ya conocidos:
fib_cache = {}
function f(n)
if n < 2 then
return n;
if fib_cache.contains(n) then
return fib_cache[n]
fib_cache[n] = f(n - 1) + f(n - 2)
return fib_cache[n]
El almacenamiento en memoria caché en bases de datos suele ser una función de la base de datos y la base de datos lo gestiona automáticamente. El almacenamiento en caché de las aplicaciones va a variar de una plataforma a otra.
Un caché de objetos es un mecanismo que puede usar para colocar objetos usados comúnmente en la memoria para que no tenga que pagar el costo de recuperar los datos y volver a crearlos. Esto generalmente se gestiona mediante código y varía según la solución de almacenamiento en caché que esté utilizando.
Existen soluciones de caché distribuidas que implican la configuración de servicios en varios servidores para proporcionarle una especie de granja de caché. Esto proporciona escalabilidad y redundancia. Los clientes pueden solicitar la información en caché a través de la red. De nuevo, este es un procedimiento manual en tu código. Un ejemplo de un proveedor de memoria caché distribuida es memcached:
http://www.danga.com/memcached/
Un ejemplo de un tipo específico de almacenamiento en caché sería el almacenamiento en caché asp.net. Asp.net admite varios tipos de caché. Existe el caché de objetos tradicional (que se puede usar en todo tipo de aplicaciones .net, no solo en sitios web). También hay funciones de almacenamiento en caché que le permiten configurar páginas y controles de usuario para almacenar automáticamente en caché su salida. Esto no almacena datos en caché, almacena en caché el resultado final (el HTML de la página) y lo publica cuando el usuario solicita la misma página con la misma cadena de consulta parms que un usuario anterior.
El almacenamiento en memoria caché es solo la práctica de almacenar datos y recuperar datos de una tienda de alto rendimiento (generalmente memoria) de forma explícita o implícita.
Dejame explicar. La memoria es más rápida de acceder que un archivo, una URL remota (generalmente), una base de datos o cualquier otro almacén externo de información que desee. Entonces, si el acto de usar uno de esos recursos externos es importante, entonces puede beneficiarse del almacenamiento en caché para aumentar el rendimiento.
Knuth dijo una vez que la optimización prematura es la raíz de todo mal. Bueno, el almacenamiento en caché prematuro es la raíz de todos los dolores de cabeza en lo que a mí respecta. No resuelva un problema hasta que tenga un problema. Cada decisión que tomas tiene un costo que pagarás para implementarla ahora y volver a pagarla para cambiarla más tarde, por lo que cuanto más puedas postergar la deicción y cambiar tu sistema, mejor.
Entonces primero identifique que realmente tiene un problema y dónde está . La creación de perfiles, el registro y otras formas de pruebas de rendimiento lo ayudarán aquí. No puedo dejar de insistir en lo importante que es este paso. La cantidad de veces que he visto a personas "optimizar" algo que no es un problema es asombroso.
Ok, entonces tienes un problema de rendimiento. Supongamos que sus páginas ejecutan una consulta que lleva mucho tiempo. Si es una lectura, entonces tienes varias opciones:
- Ejecute la consulta como un proceso separado y coloque el resultado en un caché. Todas las páginas simplemente acceden al caché. Puede actualizar la versión en caché tantas veces como sea apropiado (una vez al día, una vez a la semana, una cada 5 segundos, lo que sea apropiado);
- Guarde en caché de forma transparente a través de su proveedor de persistencia, ORM o lo que sea. Por supuesto, esto depende de la tecnología que estés usando. Hibernate e Ibatis, por ejemplo, admiten el almacenamiento en caché de resultados de consultas;
- Haga que sus páginas ejecuten la consulta si el resultado no está en el caché (o está "obsoleto", lo que significa que se ha calculado más tiempo que la "edad" especificada) y colóquelo en el caché. Esto tiene problemas de concurrencia si dos (o más) procesos independientes deciden que necesitan actualizar el resultado para que termine ejecutando la misma (costosa) consulta ocho veces a la vez. Puede manejar esto bloqueando el caché, pero eso crea otro problema de rendimiento. También puede recurrir a métodos de concurrencia en su idioma (por ejemplo, API de concurrencia Java 5).
Si se trata de una actualización (o actualizaciones que deben reflejarse en la memoria caché de lectura), es un poco más complicada porque no es bueno tener un valor anterior en la memoria caché y un valor más nuevo en la base de datos para poder proporcionar sus páginas con una vista inconsistente de los datos. Pero, en términos generales, hay cuatro enfoques para esto:
- Actualice la caché y luego ponga en cola una solicitud para actualizar la tienda correspondiente;
- Escritura a través del almacenamiento en caché: el proveedor de caché puede proporcionar un mecanismo para mantener la actualización y bloquear a la persona que llama hasta que se realice dicho cambio; y
- Almacenamiento en memoria caché de escritura oculta: igual que el almacenamiento en memoria caché de escritura simultánea, pero no bloquea a la persona que llama. La actualización ocurre de forma asíncrona y por separado; y
- Modelos de persistencia como servicio: esto supone que su mecanismo de caché admite algún tipo de observabilidad (es decir, oyentes de eventos de caché). Básicamente, un proceso completamente separado, desconocido para la persona que llama, escucha las actualizaciones de la memoria caché y las persiste según sea necesario.
¿Cuál de las metodologías anteriores eliges dependerá mucho de tus requisitos, qué tecnologías estás usando y una gran cantidad de otros factores (por ejemplo, se requiere clúster y soporte de conmutación por error?).
Es difícil ser más específico que eso y darle orientación sobre qué hacer sin saber mucho más detalles sobre su problema (como si tiene o no un problema).
El concepto de caché es un término sobrecargado aquí. No estoy familiarizado con las tuercas y los pernos del almacenamiento en caché de la base de datos.
En las aplicaciones, hay dos usos del término.
Cuando alguien dice que encontró un código que dañaría el almacenamiento en caché y, una vez que lo arreglaron, mejoró la velocidad de su aplicación, ¿de qué están hablando?
En este caso, están haciendo referencia a la memoria caché de la CPU.
La memoria caché de la CPU es mucho más rápida que la RAM, pero no tiene acceso aleatorio. Lo que la CPU decide cargar en el caché puede volverse un poco complicado. Ver Ulrich Dreppers Lo que todo programador debería saber sobre la memoria para muchos detalles.
Tener en cuenta la memoria caché de la CPU puede acelerar bastante bien las cosas: solo hay que prestar más atención al lugar en el que se ubican las cosas entre sí en la memoria física y cuándo es probable que se utilicen.
Un ejemplo (también probablemente un antipatrón para la mantenibilidad) es que si tiene una matriz de estructuras y hace un montón de bucles sobre los miembros de la estructura, es posible que le sirva mejor con una estructura donde los campos son todas las matrices. Si los datos que está recorriendo son contiguos en la memoria, tiene más posibilidades de no alterar el caché.
Todo tipo de cosas pueden afectar la eficiencia del uso de la memoria caché: predicción de bifurcación del código cargado en la memoria caché, tamaño y alineación de estructuras de datos y patrones de acceso, dónde y cuándo declarar las variables locales que se colocarán en la pila.
El otro uso común del término para la programación de aplicaciones puede hacerse mediante algo llamado memoization . El ejemplo factorial en esa página de wikipedia explica las cosas mejor de lo que hubiera hecho.
Hay dos significados que yo sé.
Uno es el almacenamiento en caché de aplicaciones . Aquí es cuando, si los datos tardan en llegar desde algún lugar (p. Ej., Desde la red) o tardan en calcularse, la aplicación guarda en caché una copia de los datos (para que no sea necesario volver a obtenerlos o recalcularlos). ya en la memoria caché). La implementación de un caché requiere un poco de software de aplicación adicional (lógica para usar el caché) y memoria extra (en la que almacenar los datos en caché).
Eso es "el almacenamiento en caché" que se usa cuando estás citando aquí:
Desde el contexto puedo entenderlo, almacenar un valor recuperado a menudo en la memoria principal y tener acceso rápido a él.
Otro es el almacenamiento en caché de CPU , que se describe en este artículo de Wikipedia . El almacenamiento en caché de la CPU ocurre automáticamente. Si lee mucho de una pequeña cantidad de memoria, entonces la CPU puede hacer la mayoría de esas lecturas desde su caché. OTOH si lee de una gran cantidad de memoria, no puede caber en la memoria caché y la CPU debe pasar más tiempo trabajando con la memoria más lenta.
Eso es "el almacenamiento en caché" que se usa cuando estás citando aquí:
Cuando alguien dice que encontró un código que dañaría el almacenamiento en caché y, una vez que lo arreglaron, mejoró la velocidad de su aplicación, ¿de qué están hablando?
Significa que encontraron una forma de reorganizar su código para causar menos fallas en la caché .
En cuanto al almacenamiento en caché de la base de datos , no lo sé.
Hay un par de problemas.
Uno, es granularidad. Su aplicación puede tener niveles muy finos de almacenamiento en caché por encima de lo que hace la base de datos. Por ejemplo, es probable que la base de datos simplemente almacene en caché las páginas de datos, no necesariamente las filas específicas.
Otra cosa es que la aplicación puede almacenar datos en su formato "nativo", mientras que la DB obviamente solo se almacena en caché en su formato interno.
Ejemplo simple
Supongamos que tiene un Usuario en la base de datos, que está formado por las columnas: USERID
, FIRSTNAME
, LASTNAME
. Muy simple.
Desea cargar un Usuario, USERID=123
, en su aplicación. ¿Cuáles son los pasos involucrados?
- Emitir la llamada a la base de datos
- Analizando la solicitud (
SELECT * FROM USER WHERE USERID = ?
) - Planificación de la solicitud (es decir, cómo va a recuperar el sistema los datos)
- Obteniendo los datos del disco
- Transmitir los datos de la base de datos a la aplicación
- Convertir los datos de la base de datos en datos de la aplicación (es decir,
USERID
en un entero, por ejemplo, los nombres en Strings.
La memoria caché de la base de datos, probablemente, almacenará en caché los pasos 2 y 3 (es decir, un caché de declaración, por lo que no analizará o volverá a planificar la consulta), y almacenará en caché los bloques de disco reales.
Entonces, aquí está la clave. Su usuario, USER ID 123
, nombre JESSE JAMES
. Puedes ver que esto no es mucha información. Pero la base de datos está almacenando bloques de disco en caché. Usted tiene el bloque de índice (con el 123
en él), luego el bloque de datos (con los datos reales y todas las otras filas que encajan en ese bloque). Entonces, lo que nominalmente es, digamos, 60-70 bytes de datos en realidad tiene un almacenamiento en caché y un impacto de datos en la base de datos de, probablemente, 4K-16K (depende del tamaño del bloque).
¿El lado brillante? Si necesita otra fila que esté cerca (digamos USER ID = 124
), las probabilidades son altas, el índice y los datos ya están en la memoria caché.
Pero incluso con ese almacenamiento en caché, todavía tiene que pagar el costo de trasladar los datos a través del cable (y siempre pasa por encima del cable a menos que esté usando un DB local, entonces ese es un bucle invertido), y está "eliminando" los datos . Es decir, convertirlo de bits de Base de datos a bits de idioma, a bits de Aplicación.
Ahora, una vez que la aplicación obtiene su USER ID 123
, rellena el valor en un mapa hash de larga duración.
Si la aplicación alguna vez la quiere de nuevo, buscará en el mapa local, el caché de la aplicación y guardará la búsqueda, el transporte por cable y los costos de clasificación.
El lado oscuro del almacenamiento en caché de aplicaciones es la sincronización. Si alguien entra y realiza una UPDATE USER SET LASTNAME="SMITH" WHERE USERID=123
, su aplicación no "lo sabe", y por lo tanto, la memoria caché está sucia.
Entonces, hay un montón de detalles en el manejo de esa relación para mantener la aplicación sincronizada con la base de datos.
Tener MUCHA caché de base de datos es muy bueno para grandes consultas sobre un conjunto "caliente" de datos. Cuanta más memoria tenga, más datos "calientes" podrá tener. Hasta el punto, si puede almacenar en caché toda la base de datos en la memoria RAM, eliminará el retraso de I / O (al menos para las lecturas) de mover datos desde el disco a una memoria RAM. Pero aún tiene los costos de transporte y clasificación.
La aplicación puede ser mucho más selectiva, como el almacenamiento en caché de subconjuntos de datos más limitados (los DB solo bloquean el caché) y tener los datos "más cerca" de la aplicación da como resultado un rendimiento mucho mejor.
El inconveniente es que no todo está almacenado en la aplicación. La base de datos tiende a almacenar datos de manera más eficiente, en general, que la aplicación. También le falta un lenguaje de "consulta" en contra de los datos de la aplicación en caché. La mayoría de las personas simplemente almacenan en caché con una simple clave y van desde allí. Fácil de encontrar USER ID 123
, más difícil para "TODOS LOS USUARIOS NOMBRADOS JESSE".
El almacenamiento en caché de la base de datos tiende a ser "libre", usted establece un número de buffer y el DBMS maneja el resto. Bajo impacto, reduce las demoras generales de E / S y discos.
El almacenamiento en caché de aplicaciones es, bueno, específico de la aplicación.
Funciona muy bien para datos "estáticos" aislados. Eso es muy fácil. Cargue un montón de cosas en las tablas de búsqueda al inicio y reinicie la aplicación si cambian. Eso es fácil de hacer.
Luego, la complejidad comienza a aumentar a medida que agrega lógica "sucia", etc.
Lo que todo se reduce, sin embargo, es que siempre que tenga una API de datos, puede almacenar en caché de forma incremental.
Entonces, siempre que llame a getUser(123)
todas partes en lugar de presionar la base de datos, luego puede regresar y agregar el almacenamiento en caché a getUser
sin afectar su código.
Por lo tanto, siempre sugiero algún tipo de capa de acceso a datos en el código de todos, para proporcionar ese poco de abstracción y capa de interceptación.
Lo más probable es que lea sobre el almacenamiento en caché en el contexto de las aplicaciones web. Debido a la naturaleza de la Web, el almacenamiento en caché puede hacer una gran diferencia en el rendimiento.
Considera lo siguiente:
Una solicitud de página web llega al servidor web, que pasa la solicitud al servidor de aplicaciones, que ejecuta algún código que representa la página, que debe dirigirse a la base de datos para recuperar datos de forma dinámica.
Este modelo no se escala bien, porque a medida que aumenta el número de solicitudes para la página, el servidor tiene que hacer lo mismo una y otra vez, para cada solicitud.
Esto se convierte en un problema aún mayor si el servidor web, el servidor de aplicaciones y la base de datos se encuentran en hardware diferente y se comunican a través de la red entre sí.
Si tiene una gran cantidad de usuarios que visitan esta página, tiene sentido no acceder a la base de datos para cada solicitud. En cambio, recurre a la memoria caché en diferentes niveles.
Caché de resultados
El almacenamiento en caché de los conjuntos de resultados almacena los resultados de una consulta de base de datos junto con la consulta en la aplicación. Cada vez que una página web genera una consulta, las aplicaciones comprueban si los resultados ya están almacenados en la memoria caché y, en caso afirmativo, los extraen de un conjunto de datos en memoria. La aplicación todavía tiene que mostrar la página.
Caché de componentes
Una página web se compone de diferentes componentes: páginas, o lo que sea que quiera llamar. Una estrategia de almacenamiento en caché de componentes debe saber qué parámetros se usaron para solicitar el componente. Por ejemplo, una pequeña barra de "Últimas noticias" en el sitio usa la ubicación geográfica o preferencia del usuario para mostrar las noticias locales. En consecuencia, si las noticias de una ubicación se almacenan en caché, no es necesario procesar el componente y se puede extraer de una memoria caché.
Caché de página
Una estrategia para el almacenamiento en caché de páginas enteras es almacenar la cadena de consulta y / o los parámetros del encabezado junto con el HTML completamente renderizado. El sistema de archivos es lo suficientemente rápido para esto: todavía es mucho menos costoso para un servidor web leer un archivo que realizar una llamada al servidor de aplicaciones para que se represente la página. En este caso, cada usuario que envíe la misma cadena de consulta obtendrá el mismo contenido en caché.
La combinación de estas estrategias de almacenamiento en caché de forma inteligente es la única forma de crear aplicaciones web realmente escalables para un gran número de usuarios simultáneos. Como puede ver fácilmente, el riesgo potencial aquí es que si una parte del contenido de la memoria caché no puede ser identificada de manera única por su clave, las personas comenzarán a ver el contenido incorrecto. Esto puede ser bastante complicado, particularmente cuando los usuarios tienen sesiones y existe un contexto de seguridad.
Probablemente sea más fácil de lo que puedas imaginar, y es por eso que las personas intentan cerrarlo.
Simplemente significa almacenar los valores en su memoria en lugar de volver a la base de datos para ellos cada vez.
Hay muchas formas de hacerlo, pero el concepto en sí mismo es trivial.
Editar: Se puede hacer en CUALQUIER nivel también; todo lo que lleve mucho tiempo puede guardarse en caché en algún lugar al que pueda acceder más rápidamente.
el almacenamiento en caché toma el resultado de un algoritmo largo o intensivo de CPU y guarda la respuesta para que no tenga que volver a ejecutar el algoritmo, simplemente reutilice el resultado.