我希望以优雅的方式缓存来自外部服务的数据:旧数据虽然已过期,但仍在提供,直到工作人员成功获取新数据.数据不是时间关键的,但缺少数据(外部服务关闭)会阻止服务运行,从而使用持久性缓存.

目前

>我将获取时间戳存储在单独的Redis密钥中

>我无限期地缓存数据,直到工作者获取新数据(我没有设置到期时间)

问题

>这是使用Redis进行优雅缓存的正确方法吗?

>我可以原生地从Redis获取关键的更新时间戳,因此我不需要自己存储这些信息

这是代码:

def set_data(self, data):
self.redis.set("bitcoinaverage", pickle.dumps(data))
self.redis.set("bitcoinaverage_updated", calendar.timegm(datetime.datetime.utcnow().utctimetuple()))
def get_data(self):
return pickle.loads(self.redis.get("bitcoinaverage"))
def is_up_to_date(self):
last_updated = datetime.utcfromtimestamp(self.redis.get("bitcoinaverage_updated"))
if not last_updated:
return False
return datetime.datetime.utcnow() < last_updated + self.refresh_delay
def tick(self):
""" Run a periodical worker task to see if we need to update.
"""
if not self.is_up_to_date():
self.update()

解决方法:

你有什么可以工作,但取决于你期望你的数据集有多大.如果我理解正确,你当前的实现将要求你运行一个工人用tick()ping每个键.由于您必须通过网络,查询Redis并将结果发送回每个单独的密钥(如果需要,可能需要两个查询),这在您当前实施的网络来回非常非常昂贵更新).如果它只是你提到的两个键,那很好.如果它是更多,pipelines are your friend.

如果你想要更优雅和更健壮,你可以在钥匙到期时使用notifications.这里的范例是,对于每个值,您将设置两个键:k和k_updated. k将保持键的实际值,并且k_updated将只是一个具有TTL设置的哑键,用于何时想要更新k.当k_updated到期时,您将收到通知,然后您可以拥有一个监听器,然后立即将其作为请求新作业来更新k并设置新的k_updated.这将使用pubsub模型,如果您想要非常强大,您可以拥有多个订阅者并使用队列来管理新作业.这个系统的好处:

>密钥将在到期时立即更新,无需不断查询它们以查看是否需要更新密钥.

>您可以让多个独立工作人员订阅并监听更新任务,并在他们进入时管理新的更新作业,这样,如果一个更新工作人员出现故障,则在您重新启动该框之前不会丢失更新.

如果您没有极端速度或稳健性需求,后一种系统对您的情况可能过度,但如果您这样做或计划,则需要考虑.

标签:python,caching,redis