2011-07-29 12 views
19

En la documentación de Django que dice esto:¿Cómo maneja django múltiples servidores de memcached?

...

Una característica excelente de Memcached es su capacidad para compartir caché sobre varios servidores. Esto significa que puede ejecutar daemons de Memcached en varias máquinas , y el programa tratará el grupo de máquinas como una única caché , sin la necesidad de duplicar los valores de caché en cada máquina. Para aproveche esta función, incluya todas las direcciones de servidor en UBICACIÓN, ya sea separadas por punto y coma o como una lista.

...

Django's cache framework - Memcached

¿Cómo funciona exactamente este trabajo? He leído algunas respuestas en este sitio que sugieren que esto se lleva a cabo filtrando los servidores a través de hash de las claves.

Multiple memcached servers question

How does the MemCacheStore really work with multiple servers?

Eso está bien, pero necesito una respuesta mucho más específico y detallado que eso. Usando django con pylibmc o python-memcached, ¿cómo se realiza este sharding? ¿Importa el orden de las direcciones IP en la configuración? ¿Qué sucede si dos servidores web diferentes que ejecutan la misma aplicación django tienen dos archivos de configuración diferentes con las direcciones IP de los servidores memcached en un orden diferente? ¿Conseguirá eso que cada máquina utilice una estrategia de fragmentación diferente que cause duplicados de claves y otras ineficiencias?

¿Qué sucede si una máquina en particular aparece en la lista dos veces? Por ejemplo, ¿qué pasaría si tuviera que hacer algo como esto donde 127.0.0.1 es realmente la misma máquina que 172.19.26.240?

CACHES = { 
    'default': { 
     'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 
     'LOCATION': [ 
      '127.0.0.1:11211', 
      '172.19.26.240:11211', 
      '172.19.26.242:11211', 
     ] 
    } 
} 

¿Qué sucede si uno de los servidores de memcached tiene más capacidad que los demás? Si la máquina uno tiene como 64 MB de memoria y la máquina 2 tiene 128 MB, ¿tendrá en cuenta el algoritmo de fragmentación y otorgará a la máquina 2 una mayor proporción de claves?

También he leído que si se pierde un servidor memcached, entonces esas claves se pierden. Eso es obvio cuando se trata de fragmentación. ¿Qué es más importante es qué sucederá si un servidor de memcached se cae y dejo su dirección IP en el archivo de configuración? ¿Django/memcached simplemente no obtendrá ninguna clave que se haya fragmentado en ese servidor fallido, o se dará cuenta de que el servidor ha fallado y se le ocurrirá una nueva estrategia de fragmentación? Si hay una nueva estrategia de fragmentación, ¿toma inteligentemente las claves que originalmente estaban destinadas para el servidor fallido y las divide entre los servidores restantes, o se le ocurre una nueva estrategia como si el primer servidor no existiera y Como resultado, las llaves se duplican?

Intenté leer el código fuente de python-memcached, y no pude resolver esto. Planeo intentar leer el código de libmemcached y pylibmc, pero pensé que preguntar aquí sería más fácil si alguien ya lo sabía.

Respuesta

13

Es el cliente real de memcached que realiza la fragmentación. Django solo pasa la configuración de settings.CACHES al cliente.

El orden de los servidores no importa *, pero (al menos para el pitón-memcached) puede especificar un 'peso' para cada uno de los servidores:

CACHES = { 
    'default': { 
     'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 
     'LOCATION': [ 
       ('cache1.example.org:11211', 1), 
       ('cache2.example.org:11211', 10), 
      ], 
} 

creo que una mirada rápida en memcache.py (de pitón-memcached) y especialmente memcached.Client._get_server debe responder el resto de sus preguntas:

def _get_server(self, key): 
    if isinstance(key, tuple): 
     serverhash, key = key 
    else: 
     serverhash = serverHashFunction(key) 

    for i in range(Client._SERVER_RETRIES): 
     server = self.buckets[serverhash % len(self.buckets)] 
     if server.connect(): 
      #print "(using server %s)" % server, 
      return server, key 
     serverhash = serverHashFunction(str(serverhash) + str(i)) 
    return None, None 

que sería de esperar que los otros clientes memcached se implementan de una manera similar.


Aclaración por @Apreche: El orden de los servidores sí importa en un caso. Si tiene varios servidores web y desea que todos ellos coloquen las mismas claves en los mismos servidores memcached, debe configurarlos con la misma lista de servidores en el mismo orden con los mismos pesos

+0

Gracias! Esto no respondió completamente todas mis preguntas, pero me indicó la dirección correcta para responderlas por mi cuenta. Lo único que obtuviste mal es que el orden de los servidores sí importa en un caso. Si tiene varios servidores web y desea que todos ellos coloquen las mismas claves en los mismos servidores de memcached, debe configurarlos con la misma lista de servidores en el mismo orden con los mismos pesos. – Apreche

5

He probado parte de esto y encontré algunas cosas interesantes con django 1.1 y python-memcached 1.44.

En Django usando 2 servidores memcache

cache.set('a', 1, 1000)

cache.get('a') # returned 1

Miré hacia arriba, que Memcache servidor 'a' fue fragmentada a la utilización de otros 2 configuraciones django cada uno apuntando a uno de los servidores memcache. Simulé una interrupción de la conectividad mediante la colocación de un cortafuegos entre la instancia de Django original y el servidor memcache que 'a' se almacena en.

cache.get('a') # paused for a few seconds and then returned None

cache.set('a', 2, 1000)

cache.get('a') # returned 2 right away

El cliente Memcache La biblioteca actualiza su estrategia de fragmentación si un servidor se cae.

Luego eliminé el firewall.

cache.get('a') # returned 2 for a bit until it detected the server back up then returned 1!

Usted puede leer datos obsoletos cuando un servidor memcache cae y vuelve! Memcache no hace nada inteligente para tratar de evitar esto.

Esto realmente puede complicar las cosas si está utilizando una estrategia de almacenamiento en caché que pone las cosas en Memcache durante mucho tiempo y depende de la invalidación de caché para manejar las actualizaciones. Se puede escribir un valor antiguo en el servidor de caché "normal" para esa clave, y si pierde la conectividad y se realiza una invalidación durante esa ventana, cuando el servidor vuelva a estar accesible, leerá datos obsoletos que no podrá ver. a.

Una nota más: He estado leyendo sobre algunas bibliotecas de caché de objetos/consultas y creo que johnny-cache debería ser inmune a este problema. No invalida explícitamente las entradas; en cambio, cambia la clave en la que se almacena en caché una consulta cuando cambia una tabla. Por lo tanto, nunca leería accidentalmente valores antiguos.

Edit: Creo que mi nota sobre johnny-cache working ok is crap. http://jmoiron.net/blog/is-johnny-cache-for-you/ dice "hay lecturas de caché adicionales en cada solicitud para cargar las generaciones actuales". Si las generaciones se almacenan en la memoria caché, el escenario anterior puede provocar la lectura de una generación obsoleta.

+0

Whoah, eso es fascinante, y algo en lo que nunca pensé. Supongo que solo tienes que borrar cualquier servidor Memcache que se caiga. Muy útil, gracias! – Apreche

+1

Sean señala [1] que el problema inverso también es posible: también puede leer datos obsoletos del servidor memcached que no se cayeron. Parece que la única solución segura es descargarlos a todos al volver a conectar a uno. [1] https://bugs.launchpad.net/python-memcached/+bug/887765/comments/9 –

2

Pensamos agregar esta respuesta dos años después de que se hizo la pregunta, ya que tiene una posición muy alta en la búsqueda y porque encontramos una situación en la que django solo hablaba con uno de los servidores de memcached.

Con un sitio ejecutándose en django 1.4.3, python-memcached 1.51 hablando con cuatro instancias de memcached, encontramos que la base de datos se consultaba con mucha más frecuencia de la esperada. Cavando más, encontramos que cache.get() devolvía None para claves que se sabía que estaban presentes en al menos una de las instancias de memcached. Cuando memcached se inició con la opción -vv, ¡demostró que la pregunta solo se hacía sobre un servidor!

Después de haber tirado de mucho pelo, cambiamos el servidor a django.core.cache.backends.memcached.PyLibMCCache (pylibmc) y el problema desapareció.

Cuestiones relacionadas