主要分享下我的對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配置,應該仍是準確合適的。