在django文档中,它说:
...
Memcached的一个优秀功能是它能够共享缓存 多个服务器。这意味着您可以在多个上运行Memcached守护程序 机器,程序将把这组机器视为单一机器 缓存,无需在每台计算机上复制缓存值。至 利用此功能,包括所有服务器地址 LOCATION,用分号或列表分隔。
...
Django's cache framework - Memcached
这究竟是如何工作的?我在这个网站上读到了一些答案,建议通过基于密钥的哈希来跨服务器进行分片来实现。
Multiple memcached servers question
How does the MemCacheStore really work with multiple servers?
这没关系,但我需要一个更具体,更详细的答案。使用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服务器的容量大于其他服务器,该怎么办?如果机器一个具有64MB memcached而机器2具有128MB,那么分片算法是否会考虑到这一点并为机器2提供更大比例的密钥?
我还读过,如果memcached服务器丢失,那么这些密钥就会丢失。当涉及分片时,这是显而易见的。更重要的是,如果memcached服务器出现故障并将其IP地址留在设置文件中会发生什么? django / memcached是否会无法获得任何已经分类到该故障服务器的密钥,或者它是否会意识到服务器已经失败并提出了新的分片策略?如果有一个新的分片策略,它是否会智能地获取最初用于故障服务器的密钥并将它们分配给剩余的服务器,或者它是否提出了一个全新的策略,就像第一个服务器不存在一样导致密钥重复?
我试过阅读python-memcached的源代码,但根本无法解决这个问题。我打算尝试阅读libmemcached和pylibmc的代码,但我想如果有人已经知道,问这里会更容易。
答案 0 :(得分:13)
这是进行分片的实际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服务器上,则需要使用相同的服务器列表以相同的顺序配置它们具有相同的权重
答案 1 :(得分:5)
我测试了部分内容并发现了django 1.1和python-memcached 1.44的一些有趣内容。
使用2个memcache服务器在django上
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没有做任何巧妙的尝试来阻止这种情况。
如果您使用缓存策略将内容放入内存缓存中并依赖缓存失效来处理更新,那么这可能会让事情变得更糟。可以将旧值写入该密钥的“普通”缓存服务器,如果您断开连接并在该窗口期间失效,则当服务器再次可访问时,您将读取您不应该能够访问的陈旧数据到。
还有一点需要注意:我一直在阅读一些对象/查询缓存库,我认为johnny-cache应该不受此问题的影响。它没有明确地使条目无效;相反,它会更改表更改时缓存查询的键。所以它永远不会意外地读取旧值。
编辑:我认为我关于johnny-cache工作正常的说明是垃圾。 http://jmoiron.net/blog/is-johnny-cache-for-you/说“每次加载当前代的请求都有额外的缓存读取”。如果代数存储在缓存本身中,则上述情况可能导致读取过时代。
答案 2 :(得分:2)
考虑在提出问题两年后添加此答案,因为它在搜索中排名很高,因为我们确实发现django只与其中一个memcached服务器通信的情况。
在django 1.4.3上运行一个站点,python-memcached 1.51与四个memcached实例通信,我们发现数据库的查询频率远远低于预期。进一步挖掘,我们发现cache.get()
正在为已知存在于至少一个memcached实例中的密钥返回None
。当使用-vv选项启动memcached时,它显示只询问了一个服务器的问题!
拔掉很多头发之后,我们将后端切换到django.core.cache.backends.memcached.PyLibMCCache
(pylibmc),问题就消失了。
答案 3 :(得分:1)
如果使用两个不同的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/