Python 如何使用派生数据在Django中进行DB memcaching?
注意: 这是一个详细的问题,询问如何在使用memcached的web应用程序中最好地实现和管理数据库缓存。这个问题使用Python/Django来说明数据模型和用法,但是语言并没有那么重要。我更感兴趣的是学习维护缓存一致性的最佳策略是什么。Python/Django恰好是我用来说明这个问题的语言 我的申请规则:Python 如何使用派生数据在Django中进行DB memcaching?,python,django,caching,memcached,database-caching,Python,Django,Caching,Memcached,Database Caching,注意: 这是一个详细的问题,询问如何在使用memcached的web应用程序中最好地实现和管理数据库缓存。这个问题使用Python/Django来说明数据模型和用法,但是语言并没有那么重要。我更感兴趣的是学习维护缓存一致性的最佳策略是什么。Python/Django恰好是我用来说明这个问题的语言 我的申请规则: import memcache mc = memcache.Client(['127.0.0.1:11211'], debug=0) class Cell(models.Model):
import memcache
mc = memcache.Client(['127.0.0.1:11211'], debug=0)
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
# Whenever this value is updated, the keys for the row and column need to be
# invalidated. But not sure exactly how I should manage that.
value = models.IntegerField()
class Row(models.Model):
y = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.x * p.value, Cell.objects.filter(y=self.y)))
class Column(models.Model):
x = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.y * p.value, Cell.objects.filter(x=self.x)))
(value*Y-Coord)
求和来计算(value*X-Coord)
求和来计算memcached
最小化对数据库的访问import memcache
mc = memcache.Client(['127.0.0.1:11211'], debug=0)
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
# Whenever this value is updated, the keys for the row and column need to be
# invalidated. But not sure exactly how I should manage that.
value = models.IntegerField()
class Row(models.Model):
y = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.x * p.value, Cell.objects.filter(y=self.y)))
class Column(models.Model):
x = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.y * p.value, Cell.objects.filter(x=self.x)))
所以我的问题是:
import memcache
mc = memcache.Client(['127.0.0.1:11211'], debug=0)
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
# Whenever this value is updated, the keys for the row and column need to be
# invalidated. But not sure exactly how I should manage that.
value = models.IntegerField()
class Row(models.Model):
y = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.x * p.value, Cell.objects.filter(y=self.y)))
class Column(models.Model):
x = models.IntegerField()
@property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.y * p.value, Cell.objects.filter(x=self.x)))
您可以看到,我已经设置了一个memcached
实例。当然,我知道如何在memcached
中插入/删除/更新键和值。但鉴于我上面的代码,我应该如何恰当地命名密钥?如果键名是固定的,那么它将不起作用,因为每一行和每一列都必须存在单独的键。关键的是,当单元格中的值更新时,如何确保适当的键(并且只有适当的键)无效
每当有人更新Cell.values时,我如何管理缓存失效,以便最小化数据库访问?有没有django中间件可以帮我处理这个簿记?我看到的没有这样做。如果要缓存单个行/列组合,应该将对象id附加到键名 给定一个x,y变量:
key = 'x={}_y={}'.format(x, y)
我将使用表名并只附加id,行id可以是表PK,列id可以是列名,如下所示
key = '{}_{}_{}'.format(table_name, obj.id, column_name)
在任何情况下,我建议考虑缓存整行而不是单个单元格保存模型对象时,
单元格
对象可以使其行
和列
的缓存值无效
# your client, be it memcache or redis, assign to client variable
# I think both of them use set without TTL for permanent values.
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
value = models.IntegerField()
def save(self, *args, **kwargs):
Cell.cache("row",self.y)
Cell.cache("column",self.x)
super(Cell, self).save(*args, **kwargs)
@staticmethod
def score(dimension, number):
return client.get(dimension+str(number), False) or Cell.cache(number)
@staticmethod
def cache(dimension, number):
if dimension == "row":
val = sum([c.y * c.value for c in Cell.objects.filter(y=number)])
client.set(dimension+str(self.y),val)
return val
if dimension == "column":
val = sum([c.x * c.value for c in Cell.objects.filter(x=number)])
client.set(dimension+str(self.x),val)
return val
raise Exception("No such dimension:"+str(dimension))
(行
和列
在这里是普通对象,而不是Django模型,但是如果出于某种原因需要将它们存储在数据库中,当然可以更改。)
但是更新Cell.values时,如何管理缓存失效?是否有一些django中间件可以为我处理这个簿记?仅供参考,我看到的关于将Django与memcached结合使用的文档似乎都在谈论如何为我缓存动态页面的输出。我不想那样。我实际上不提供任何页面。我的应用程序只是一系列可调用的RESTAPI。但我希望这些API能够最小化数据库访问。因此,我希望我的django模型缓存对DB的调用。要使其无效,您可以使用时间,例如,将缓存有效时间设置为1秒,这样您的数据库每秒的命中率不会超过1。您可以从上面的问题中提取我的代码,并实际插入语句以使其工作吗?我还没有得到一个清晰的例子,说明如何以干净和原子的方式管理缓存失效。修改上面的代码对我帮助最大。你不需要行或列模型,它们只是在Cell.Ok中重复数据。这很有帮助。谢谢但是,该代码是否包含潜在的竞争条件?我不是100%肯定。但我认为可能。如果我将字典存储为缓存中的一个值(如
client.set(“myKey”,“a”:1”,“B”:2})
),并且我的应用程序希望将B的值从2增加到3,那么如何防止竞争条件?如果两个不同的web用户及时触发相同的增量操作,我认为B中的值可能会损坏。我怎么能避免呢?我使用的操作是原子级的。对于模型的任何给定快照,您永远不会得到错误的答案,但您可能会遇到这样的情况:如果两个增量操作在时间上足够接近(您确实说过更改值的频率很低),两个线程可能会得出不同的结论,并且具有较旧结果的线程可能是后一个存储该结果的线程。考虑到你的限制,几率相对较低。您可以在客户端中为keyvalue分配一个sentinel值,该值指示正在进行设置操作。有关使用memcached sentinel的示例,请参阅