基于标记的失效和dogpile效应预防的python缓存库

HermesCache的Python项目详细描述


https://bitbucket-badges.atlassian.io/badge/saaj/hermes.svg?ref=defaulthttps://codecov.io/bitbucket/saaj/hermes/branch/default/graph/badge.svghttps://badge.fury.io/py/HermesCache.png

赫尔墨斯卡什

hermes是一个python缓存库。其设计满足的要求:

  • 基于标记的缓存失效
  • 防止狗桩效应
  • 螺纹安全性
  • 简洁的设计
  • 简单,同时,灵活的装饰器作为最终用户API
  • 实现多个后端的接口

实现的后端:redismemcacheddict(没有过期)。

安装

pip install HermesCache

确保已安装所需的后端客户端库。见下文。

使用量

下面演示所有最终用户api。

importhermes.backend.rediscache=hermes.Hermes(hermes.backend.redis.Backend,ttl=600,host='localhost',db=1)@cachedeffoo(a,b):returna*bclassExample:@cache(tags=('math','power'),ttl=1200)defbar(self,a,b):returna**b@cache(tags=('math','avg'),key=lambdafn,*args,**kwargs:'avg:{0}:{1}'.format(*args))defbaz(self,a,b):return(a+b)/2.0print(foo(2,333))example=Example()print(example.bar(2,10))print(example.baz(2,10))foo.invalidate(2,333)example.bar.invalidate(2,10)example.baz.invalidate(2,10)cache.clean(['math'])# invalidate entries tagged 'math'cache.clean()# flush cache

注意

api鼓励导入时实例化Hermes,以允许最终用户 装饰它的功能。实例化没有副作用。潜在的 后端服务器连接很懒。

有关高级示例,请查看 test suite

标记缓存条目

首先让我们看看基本缓存是如何工作的。

importhermes.backend.dictcache=hermes.Hermes(hermes.backend.dict.Backend)@cachedeffoo(a,b):returna*bfoo(2,2)foo(2,4)print(cache.backend.dump())#  {#    'cache:entry:foo:515d5cb1a98de31d': 8,#    'cache:entry:foo:a1c97600eac6febb': 4#                            ↓#                      argument hash#  }

基本上我们有一个密钥值存储,其中O(1)复杂度为^ {TT5} $,^ {TT6}$,^ {TT7}$。 这意味着操作速度是恒定的,与已经存在的项目数无关 存储。当一个可调用的(函数或方法)被缓存时,从 可调用自身并传递参数。callable的返回值保存到密钥。下一次调用 我们可以使用缓存中的值。

“There are only two hard problems in Computer Science: cache invalidation and naming things.” — Phil Karlton

所以这是一个复杂的应用程序。有一种情况是某些方法的操作相同 数据和使单个条目无效是不切实际的。尤其是当 方法返回跨越多个实体的复杂值。缓存标记使标记成为可能 这组方法产生一个标记,并使它们同时失效。

这是埃里克的article 弗洛伦扎诺解释了这个想法。让我们看看代码。

importhermes.backend.dictcache=hermes.Hermes(hermes.backend.dict.Backend)@cache(tags=('tag1','tag2'))deffoo(a,b):returna*bfoo(2,2)print(cache.backend.dump())#  {#    'cache:tag:tag1': '0674536f9eb4eb19',#    'cache:tag:tag2': 'db22b5ab2e504895',#    'cache:entry:foo:a1c97600eac6febb:c1da510b3d42bad6': 4#                                              ↓#                                           tag hash#  }

当我们要标记缓存项时,首先需要创建标记项。表示每个标记 通过它自己的入口。每次创建标记时,标记项的值都设置为随机值。一次全部标记 值存在,它们被连接并散列。标记哈希被添加到缓存项密钥。

一旦我们想使标记的条目失效,我们只需要删除标记条目。没有任何标签 值标记哈希是用创建的,因此无法构造条目键,因此标记的缓存 条目变得不可访问,因此无效。通常是建立在另一个特性之上的特性 增加复杂性。

表演。所有操作都变成o(n),其中n是条目标记的数目。但是既然我们可以 很少需要超过几十个标签,实际上仍然是o(1)。标签输入操作是 批处理,因此对网络操作数的影响如下:

  • set–最坏情况下是3x个后端调用(get + 2 * set)。当 将创建所有已使用的标记项。
  • get–2x个后端调用。
  • delete–2x个后端调用。

内存开销包括标记项和过时的缓存项。演示如下。

importhermes.backend.dictcache=hermes.Hermes(hermes.backend.dict.Backend)@cache(tags=('tag1','tag2'))deffoo(a,b):returna*bfoo(2,2)print(cache.backend.dump())#  {#    'cache:tag:tag1': '047820ac777abe8a',#    'cache:tag:tag2': '126365ec7175e851',#    'cache:entry:foo:a1c97600eac6febb:5cae80f5e7d58329': 4#  }cache.clean(['tag1'])foo(2,2)print(cache.backend.dump())#  {#    'cache:tag:tag1': '66336fec212def16',  ← recreated tag entry#    'cache:tag:tag2': '126365ec7175e851',#    'cache:entry:foo:a1c97600eac6febb:8e7e24cf70c1f0ab': 4,#    'cache:entry:foo:a1c97600eac6febb:5cae80f5e7d58329': 4  ← garbage#  }

因此,ttl的选择要慎重。对于redis后端,也建议 将maxmemory-policy设置为volatile-lru

后端和客户端库

支持的依赖项列在 tox.ini 包裹的一部分。他们的组合方式是 drone.io CI page

重新发现

hermes.backend.redis依赖于redis。任选 hiredis可以安装在boost协议之外 正在分析。然而,hiredis在大批量操作和 包的上下文添加了大约10%。

内存缓存

hermes.backend.memcached依赖于纯python python-memcachedpython3-memcached如前一个仍然是 在python 3上(包含二进制数据)或,libmemcached包装器上损坏, pylibmcpylibmc给出关于提高50%。

指令

hermes.backend.dict既不是完整的后端,也不是为任何分布式使用而设计的。 最初的目的是开发需要,实际上它只是pythondict上的一个包装器。它 不实现条目过期和任何内存限制。虽然它可以在有限的情况下使用 其中缓存条目大小是一个先验的小值,而实际状态仅由手动维护 无效。

性能

这里有一些关于后端和客户端库性能的线索。不是故意的 提供一些具有统计意义的性能估计。这些只是 一个CI版本。

https://goo.gl/ZT0phqhttps://goo.gl/ZYCSGi

审查实施

在我写书之前,我翻遍了奶酪店,想找一家适合我需要的。 不幸的是,没有一个,但是有些是部分匹配的,是 某些方面:

cache

专业版:
  • 清洁最终用户API
  • 简洁的设计
继续:
  • 无自动缓存键计算
  • 无狗桩效应预防
  • 没有缓存条目标记
  • 使用实例方法失败

dogpile.cache

专业版:
  • 成熟
  • 有很好的记录
  • 防止狗桩效应
继续:
  • 没有缓存条目标记
  • 复杂的代码库
  • 不简洁的最终用户API

cache-tagging

专业版:
  • 缓存条目标记
继续:
  • 为新闻网站脚手架框架设计
  • 因此,周围都是臃肿

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java如何反射地迭代数组字段?   java NamedQuery错误“具有给定标识符的多行:1”   java无法使用单独类中的计时器更新TextView   兼容性什么时候可以很快使用新的Java功能?   java二叉树路径和   java矩形的性能   java我想从同一个子表在主表中添加两个外键   java如何获取基于特定日期的所有数据?   java javafx、OO编程规则和写入变量类型的选择   java使用带枚举的switch语句   java异步任务生成运行时异常   java为什么JLabel不显示下划线字符?   java如何解析具有可变参数号的函数?   带有按钮的java JavaFX自定义列表单元格:未调用处理程序   java Modelmapper无法映射整个模型?   传递给持久化的java分离实体,包含LatLng列表