主要分享下我的对Liberty版本openstack中cache使用的理解,因为做者水平有限,不免有所错误,疏漏,还望批评指正。python
openstack中可使用cache层来缓存数据,Liberty版本主要有如下几种场景:redis
优点在于,不少查询函数的结果是固定的,可是又比较经常使用,查询一次以后,按照key-value存到cache中,再次查询时不须要访问数据库,直接从内存缓存中根据key将结果取出,能够提升不少速度。或者还有一些查询请求,查询的参数变幻无穷,可是结果只有固定的几类,这种更适合使用cache加速。sql
Liberty 版本openstack主要是nova和keystone这方面用的比较多,来看nova中的一个例子:数据库
def get_instance_availability_zone(context, instance): """Return availability zone of specified instance.""" host = instance.get('host') if not host: # 若是虚拟机尚未被分配到主机上,就把建立虚拟机时指定的zone信息取出返回 az = instance.get('availability_zone') return az #虚拟机所在的zone取决于虚拟机所在物理机的归属的zone,因此能够生成一个 #'azcache-主机名'样式的字符串做为cache key cache_key = _make_cache_key(host) #获取一个链接cache的client cache = _get_cache() #尝试取出这个key在cache中的值,做为zone信息,可能为空,也可能直接是结果 az = cache.get(cache_key) #取出实例对象中的availability_zone属性 az_inst = instance.get('availability_zone') if az_inst is not None and az != az_inst: #对象属性中有zone信息,且和cache取到的zone信息不一致,那么须要从新获取zone信息 #而且更新到cache中 az = None if not az: #若是cache中没有取到zone信息,或者是在上一步中zone信息被清空,从新获取zone信息 elevated = context.elevated() az = get_host_availability_zone(elevated, host) #更新cache cache.set(cache_key, az) #返回zone信息 return az
这样除第一次查询到这台物理机上的虚拟机外,查询这台物理机上的任何虚拟机所属的zone,不再须要访问数据库,这样极大地减小了对数据库的请求数量,提升了响应速度。
这里支持的cache后端包括memcached,redis,mongondb或者是python的dict.目前主流openstack发行版推荐的选项是memcached,简单稳定,性能和功可以用。django
keystone中除了Fernet格式的token外,其余格式的token都须要keystone由存储起来,存储支持如下几种driver:后端
一个常见的memcache token driver的配置多是这样的:api
[token] caching = true provider = keystone.token.providers.uuid.Provider driver = keystone.token.persistence.backends.memcache.Token [memcache] servers = controller-1:11211,controller-2:11211,controller-3:11211
memcache driver的缺点在于,memcache自己是分布式的设计,可是并非高可用的,若是controller-1上的的cache服务被重启,这个节点上的全部token都会丢失掉,会带来一些错误。缓存
比这更糟糕的是,若是controller1网络不可达或者宕机,那么咱们会观察到几乎每一个openstack api请求都会有3s以上的卡顿。这是由于openstack默认使用python-memcached访问memcache,它提供的操做keystone的client继承自Thread.local类,和构建它的线程绑定。openstack服务启动后,会启动必定数量的子进程,每一个http request到达,会有一个子进程接收,孵化一个线程去处理这个请求。若是用到memcache,线程会调用python-memcached
构建一个client类,经过这个client的实例对memcache进行操做。若是访问到网络不可达的memcache节点,卡住,操做超时,将这个节点标识为30秒内不可用,在这个线程内,不会再所以而卡住,可是这个http请求结束以后,下一个http请求过来,从新孵化的线程会reinit这个client,新的client丢失了旧的client的状态,仍是可能会访问到卡住的memcache节点上。网络
社区之因此要作memcache_pool,就是为了解决这个问题,将client统一由pool管理起来,memcache节点的状态,也由pool管理起来,这样每一个子进程里只会卡第一次,因此强烈推荐使用memcache_pool驱动而不是memcache。社区将memcache_pool的代码从keystone复制到oslo_cache项目中,但愿全部使用memcache的项目都经过它的memcachepool去访问,避免这个问题。其中,nova在M版本支持,heat在L版本支持。dom
具体的各个服务如何配置使用memcache_pool driver这里再也不赘述。
咱们请求任何openstack服务时,该服务都要校验请求中提供的token是否合理,这部分代码显然不是每一个项目都本身实现一遍,它在keystonemiddleware项目实现,并做为filter配置在各个项目的api-paste.ini文件中,以下所示:
[filter:authtoken] paste.filter_factory = keystonemiddleware.auth_token:filter_factory
当请求到达服务时,由keystonemiddleware访问keystone来查询请求携带的token是否合法,一般咱们一个token会使用不少次,因此keystonemiddleware建议使用memcache缓存,把从keystone取到的token缓存一段时间,默认是300秒,以减小对keystone的压力,提升性能。kolla项目中nova keystonemiddleware配置示例以下:
[keystone_authtoken] [keystone_authtoken] auth_uri = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_public_port }} auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }} auth_plugin = password project_domain_id = default user_domain_id = default project_name = service username = {{ nova_keystone_user }} password = {{ nova_keystone_password }} memcache_security_strategy = ENCRYPT memcache_secret_key = {{ memcache_secret_key }} memcached_servers = {% for host in groups['memcached'] %}{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ memcached_port }}{% if not loop.last %},{% endif %}{% endfor %}
一直以来,若是不配置其中的memcached_servers的的话,每一个服务每一个子进程都会建立一个字典做为cache存放从keystone得到的token,可是字典内容都是类似的,若是使用统一的memcache,就不会有这方面的问题。如今master版本keystonemiddleware认为这是不合适的,会致使不一致的结果和较高的内存占用,计划在N或者O版本移除这个特性。
这个是django支持的功能,这里不做讨论,有兴趣的能够看The Django Book 2.0--中文版
cache相关的具体的配置项能够参考kolla项目中的cache配置,应该仍是准确合适的。