繁体   English   中英

django如何处理多个memcached服务器?

[英]How does django handle multiple memcached servers?

在django文档中它说:

...

Memcached的一个出色功能是它能够在多个服务器上共享缓存。 这意味着您可以在多台计算机上运行Memcached守护程序,程序会将该组计算机视为单个缓存,而无需在每台计算机上复制缓存值。 要利用此功能,请在LOCATION中包含所有服务器地址,以分号或列表分隔。

...

Django的缓存框架 - Memcached

这究竟是如何工作的? 我在这个网站上读到了一些答案,建议通过基于密钥的哈希来跨服务器进行分片来实现。

多个memcached服务器提问

MemCacheStore如何真正与多个服务器配合使用?

这很好,但我需要一个更具体和详细的​​答案。 使用django和pylibmc或python-memcached这个分片是如何实际执行的? 配置设置中的IP地址顺序是否重要? 如果运行相同django应用程序的两个不同的Web服务器有两个不同的设置文件,其中memcached服务器的IP地址的顺序不同,该怎么办? 这会导致每台机器使用不同的分片策略导致重复密钥和其他低效率吗?

如果特定机器在列表中出现两次怎么办? 例如,如果我要做这样的事情,127.0.0.1实际上是与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',
        ]
    }
}

如果其中一个memcached服务器的容量大于其他服务器,该怎么办? 如果机器1具有64MB memcached而机器2具有128MB,那么分片算法是否会考虑到这一点并为机器2提供更大比例的密钥?

我还读过,如果memcached服务器丢失,那么这些密钥就会丢失。 当涉及分片时,这是显而易见的。 更重要的是,如果memcached服务器出现故障并将其IP地址留在设置文件中会发生什么? django / memcached是否会无法获得任何已经分类到该故障服务器的密钥,或者它是否会意识到服务器已经失败并提出了新的分片策略? 如果有一个新的分片策略,它是否会智能地获取最初用于故障服务器的密钥并将它们分配给剩余的服务器,或者它是否提出了一个全新的策略,就像第一个服务器不存在一样导致密钥重复?

我试着阅读python-memcached的源代码,但根本无法解决这个问题。 我打算尝试阅读libmemcached和pylibmc的代码,但我想如果有人已经知道,问这里会更容易。

这是进行分片的实际memcached客户端。 Django只将配置从settings.CACHES传递给客户端。

服务器的顺序无关紧要*,但(至少对于python-memcached),您可以为每个服务器指定“权重”:

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

我想快速浏览一下memcache.py (来自python-memcached),特别是memcached.Client._get_server应该回答你的其余问题:

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

我希望其他memcached客户端以类似的方式实现。


@Apreche澄清:在一种情况下,服务器的顺序很重要。 如果您有多个Web服务器,并且您希望它们都将相同的密钥放在相同的memcached服务器上,则需要使用相同的服务器列表以相同的顺序配置它们并使用相同的权重

我测试了部分内容并发现了django 1.1和python-memcached 1.44的一些有趣内容。

在django上使用2个memcache服务器

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

cache.get('a') # returned 1

我查找了哪个memcache服务器'a'被分片为使用其他2个django设置,每个设置指向一个memcache服务器。 我通过在原始django实例和存储'a'的内存缓存服务器之间建立防火墙来模拟连接中断。

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

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

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

如果服务器出现故障,memcache客户端库会更新其分片策略。

然后我删除了防火墙。

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

当memcache服务器掉线并返回时,您可以读取过时的数据! Memcache没有做任何巧妙的尝试来防止这种情况。

如果您使用的缓存策略将内容放在memcache中很长时间并且依赖于缓存失效来处理更新,那么这可能会让事情变得更糟。 可以将旧值写入该密钥的“普通”缓存服务器,如果您断开连接并在该窗口期间失效,则当服务器再次可访问时,您将读取您不应该能够访问的陈旧数据至。

还有一点需要注意:我一直在阅读一些对象/查询缓存库,我认为johnny-cache应该不受此问题的影响。 它没有明确地使条目无效; 相反,它会更改表更改时缓存查询的键。 所以它永远不会意外地读取旧值。

编辑:我认为关于johnny-cache工作正常的笔记是废话。 http://jmoiron.net/blog/is-johnny-cache-for-you/说“每个加载当前代的请求都有额外的缓存读取”。 如果代数存储在缓存本身中,则上述情况可能导致读取过时代。

想在问题提出两年后添加这个答案,因为它在搜索中排名很高,因为我们确实发现了django只与其中一个memcached服务器通信的情况。

有一个站点在django 1.4.3上运行,python-memcached 1.51与四个memcached实例通信,我们发现数据库的查询频率远远高于预期。 进一步挖掘,我们发现cache.get()为已知存在于至少一个memcached实例中的键返回None 当使用-vv选项启动memcached时,它显示只询问了一个服务器的问题!

在拉了很多头发后,我们将后端切换到django.core.cache.backends.memcached.PyLibMCCache (pylibmc),问题就消失了。

如果使用两个不同的memcache是​​理想的,django的默认实现允许这种行为。

首先,您需要更新settings.py:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    },
    'rusty': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11222',
    }
}

在你的django代码中,访问memcache的默认方法没有改变。 您现在可以使用其他缓存接口,如下所示:

from django.core.cache import cache, caches

cache.set("activity", 'great stuff', 15 ) # Default cache
caches["rusty"].set("activity", "A great time}", 32) # New rusty cache interface

Django文档有一个很好的写作,涵盖了这个主题: https//docs.djangoproject.com/en/dev/topics/cache/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM