OpenStack公共组件oslo之十三——oslo.cache
来源:互联网 发布:网络布线收费标准 编辑:程序博客网 时间:2024/06/05 11:45
在OpenStack中除了使用数据库对云平台所产生的数据进行持久化外,还需要对一些常用的数据或状态进行缓存。而oslo.cache便通过dogpile.cache库实现了一个缓存机制为OpenStack其他组件提供缓存。目前,oslo.cache支持多种缓存机制,包括Memcache、etcd 3.x、MongoDB、dictionary等。本文将详细介绍oslo.cache提供的缓存机制与常用的使用方法。
1 dogpile.cache库
dogpile.cache是一个缓存API,它为各种类型的缓存后端提供了一个通用的接口;另外,它还提供了API钩子,可以将这些不同的缓存后端与dogpile库提供的锁机制结合使用。由于本文重点介绍oslo.cache,所以不对dogpile.cache库做深入展开,有兴趣的同学可以参考dogpile.cache文档。本文只对dogpile.cache中提供的通用接口进行介绍。
首先,dogpile.cache封装了CacheValue类用来保存一个缓存数据,该类中包含两个属性:payload属性,载荷,即缓存保存的数据;metadata属性,即dogpile.cache的元数据。所有通过dogpile.cache库进行缓存的数据都会被封装成CacheValue类的实例化对象。
CacheBackend类是dogpile.cache为不同缓存后端提供的一个通用的缓存接口,该接口为不同类型的缓存后端,如Memcache等提供了统一的接口,程序员在使用时只需要为该类添加实现即可实现读写缓存等操作。该接口主要提供了一下几个属性和方法:
- key_mangler属性:表示一个key的压缩函数,可能是空,也可能声明为一个普通的实例方法。
- set(key, value):缓存一个值,key表示这个值的关键字,value代表一个具体的CacheValue对象。
- set_multi(mapping):缓存多个值,mapping是一个字典类型的值。
- get(key):从缓存中获取一个值,返回一个CacheValue对象,如果指定的key找不到对应的值,则返回一个NoValue类型的对象,表示空。
- get_multi(keys):从缓存中获取多个值。
- get_mutex(key):为给定的键返回一个可选的互斥锁对象,该对象需要提供两个方法:加锁acquire()和释放锁release()。
- delete(key):从缓存中删除一个值。
- delete_multi(keys):从缓存中删除多个值。
2 oslo.cache支持的后端缓存机制
- oslo.cache.backend.memcache_pool:该模块提供了Memcache缓存池支持,首先实现了Memcache缓存连接池ConnectionPool,然后实现了PooledMemcachedBackend类对Memcache缓存连接池进行读写等操作。
- oslo_cache.backend.etcd3gw:该模块提供了etcd 3.x版本的缓存操作,实现了Etcd3gwCacheBackend类。
- oslo_cache.backend.mongo:该模块通过MongoCacheBackend类实现了使用MongoDB进行缓存的操作。
- oslo_cache.backed.dictionary:该模块DictCacheBackend类实现了通过字典进行缓存的操作机制。
3 oslo.cache缓存机制的实现
- create_region(function=function_key_generator):创建缓存区,该方法主要调用了dogpile.cache模块的make_region(function_key_generator=function)方法创建了一个CacheRegion对象。该对象通过配置文件找到对应的后端缓存实现机制创建缓存区,该对象通过具体的后端缓存机制实现了缓存数据的增删改操作。该方法调用了oslo.cache自己定义的key键生成方法。
- configure_cache_region(conf, region):该方法通过配置文件中缓存的相关配置以及CacheRegion对象提供的配置方法配置缓存区。
- get_memoization_decorator(conf, region, group, expiration_group=None):这是一个根据CacheRegion对象中cache_on_arguments()装饰器定义的oslo.cache的一个装饰器,其会根据group或expiration_group确定是否允许缓存以及缓存的时间。而CacheRegion对象中的cache_on_arguments()方法则提供了对一个或多个值的缓存、获取等操作方法。
4 oslo.cache的使用
[cache] enabled = true backend = dogpile.cache.memory [feature-name] caching = True cache_time = 7200接下来,你可以直接使用oslo.cache中封装的方法进行缓存操作。首先根据配置文件创建一个CacheRegion对象,然后使用oslo.cache中的get_memoization_decorator装饰器进行缓存操作。
from oslo_cache import core as cache from oslo_config import cfg CONF = cfg.CONF caching = cfg.BoolOpt('caching', default=True) cache_time = cfg.IntOpt('cache_time', default=3600) CONF.register_opts([caching, cache_time], "feature-name") cache.configure(CONF) example_cache_region = cache.create_region() MEMOIZE = cache.get_memoization_decorator( CONF, example_cache_region, "feature-name") # Load config file here cache.configure_cache_region(CONF, example_cache_region) @MEMOIZE def f(x): print x return x当然,你也可以对oslo.cache的功能进行扩展,使其符合项目的自身需求。在此,以nova组件为例介绍对oslo.cache的扩展方法。nova在nova.cache_utils模块中实现了对oslo.cache的扩展。首先,nova实现了两种创建CacheRegion对象的方式:_get_default_cache_region(expiration_time)方法使用默认的后端缓存实现,而_get_custom_cache_region(expiration_time=WEEK, backend=None, url=None)方法可以自己指定后端缓存的实现。
def _get_default_cache_region(expiration_time): region = cache.create_region() if expiration_time != 0: CONF.cache.expiration_time = expiration_time cache.configure_cache_region(CONF, region) return regiondef _get_custom_cache_region(expiration_time=WEEK, backend=None, url=None): """Create instance of oslo_cache client. For backends you can pass specific parameters by kwargs. For 'dogpile.cache.memcached' backend 'url' parameter must be specified. :param backend: backend name :param expiration_time: interval in seconds to indicate maximum time-to-live value for each key :param url: memcached url(s) """ region = cache.create_region() region_params = {} if expiration_time != 0: region_params['expiration_time'] = expiration_time if backend == 'oslo_cache.dict': region_params['arguments'] = {'expiration_time': expiration_time} elif backend == 'dogpile.cache.memcached': region_params['arguments'] = {'url': url} else: raise RuntimeError(_('old style configuration can use ' 'only dictionary or memcached backends')) region.configure(backend, **region_params) return region接着,nova组件实现了一个CacheClient类,封装了对数据的缓存操作。该类包含一个region属性保存CacheRegion对象,而对数据的缓存、获取、删除等操作具体是通过CacheRegion对象来实现的。
class CacheClient(object): """Replicates a tiny subset of memcached client interface.""" def __init__(self, region): self.region = region def get(self, key): value = self.region.get(key) if value == cache.NO_VALUE: return None return value def get_or_create(self, key, creator): return self.region.get_or_create(key, creator) def set(self, key, value): return self.region.set(key, value) def add(self, key, value): return self.region.get_or_create(key, lambda: value) def delete(self, key): return self.region.delete(key) def get_multi(self, keys): values = self.region.get_multi(keys) return [None if value is cache.NO_VALUE else value for value in values] def delete_multi(self, keys): return self.region.delete_multi(keys)最后,nova组件在cache_utils中实现了两个创建CacheClient对象的方法,这两个方法可以在使用中快速创建所需要的CacheClient对象。get_memcached_client()方法创建了一个后端缓存为Memcache的CacheClient对象,get_client()方法则创建了一个后端缓存为dictionary的CacheClient对象。其中,都会使用_warn_if_null_backend()方法检查后端缓存backend是否为空。
def _warn_if_null_backend(): if CONF.cache.backend == 'dogpile.cache.null': LOG.warning("Cache enabled with backend dogpile.cache.null.")def get_memcached_client(expiration_time=0): """Used ONLY when memcached is explicitly needed.""" # If the operator has [cache]/enabled flag on then we let oslo_cache # configure the region from the configuration settings if CONF.cache.enabled and CONF.cache.memcache_servers: _warn_if_null_backend() return CacheClient( _get_default_cache_region(expiration_time=expiration_time))def get_client(expiration_time=0): """Used to get a caching client.""" # If the operator has [cache]/enabled flag on then we let oslo_cache # configure the region from configuration settings. if CONF.cache.enabled: _warn_if_null_backend() return CacheClient( _get_default_cache_region(expiration_time=expiration_time)) # If [cache]/enabled flag is off, we use the dictionary backend return CacheClient( _get_custom_cache_region(expiration_time=expiration_time, backend='oslo_cache.dict'))在使用时,首先需要调用上述方法创建CacheClient对象,然后通过该对象进行具体的缓存操作。
from nova import cache_utilsdef memoize(func): @functools.wraps(func) def memoizer(context, reqid): global _CACHE if not _CACHE: _CACHE = cache_utils.get_client(expiration_time=_CACHE_TIME) key = "%s:%s" % (func.__name__, reqid) key = str(key) value = _CACHE.get(key) if value is None: value = func(context, reqid) _CACHE.set(key, value) return value return memoizer@memoizedef id_to_glance_id(context, image_id): """Convert an internal (db) id to a glance id.""" return objects.S3ImageMapping.get_by_id(context, image_id).uuid@memoizedef glance_id_to_id(context, glance_id): """Convert a glance id to an internal (db) id.""" if not glance_id: return try: return objects.S3ImageMapping.get_by_uuid(context, glance_id).id except exception.NotFound: s3imap = objects.S3ImageMapping(context, uuid=glance_id) s3imap.create() return s3imap.id在上述示例中,nova首先创建了一个memoize装饰器,在该装饰器中首先调用get_client()获取了一个CacheClient对象,然后调用该对象的get()方法获取指定key的值,如果查不到则将该值保存到缓存中,如id_to_glance_id(context, image_id)方法中image_id的值和glance_id_to_id(context, glance_id)中的glance_id的值等。
- OpenStack公共组件oslo之十三——oslo.cache
- OpenStack公共组件oslo之二——oslo.utils
- OpenStack公共组件oslo之三——oslo.log
- OpenStack公共组件oslo之四——oslo.context
- OpenStack公共组件oslo之五——oslo.service
- OpenStack公共组件oslo之六——oslo.messaging
- OpenStack公共组件oslo之七——oslo.middleware
- OpenStack公共组件oslo之八——oslo.i18n
- OpenStack公共组件oslo之九——oslo.db
- OpenStack公共组件oslo之十——oslo.concurrency
- OpenStack公共组件oslo之十一——oslo.serialization
- OpenStack公共组件oslo之十二——oslo.policy
- OpenStack公共组件oslo之一——oslo.config
- OpenStack公共组件oslo之十四——pbr
- OpenStack公共组件oslo之十五——taskflow
- OpenStack公共组件oslo之十六——stevedore
- openstack组件oslo.message之RPCClient
- openstack组件oslo.message之RPCServer实现
- 多项目同质化 gradle配置问题
- Java笔记11
- [学习笔记][Java编程思想]第9章:接口
- POJ-1028 Web Navigation(STL)
- 修改K8S中NodePort方式暴露服务的端口的默认范围(30000-32767)的方法
- OpenStack公共组件oslo之十三——oslo.cache
- <VRTK学习三> 拿取使用物体
- 《集合》
- * 期末考试 编程题#4:计算整数平方和(Coursera 程序设计与算法 专项课程3 C++程序设计 郭炜、刘家瑛;OpenJudge)
- 谈一谈自己对依赖、关联、聚合和组合之间区别的理解
- poj 3781
- 类加载器
- java中AWT和SWing的区别与联系
- [学习笔记][Java编程思想]第10章:内部类