The Glance API server may be configured to have an optional local image cache. A local image cache stores a copy of image files, essentially enabling multiple API servers to serve the same image file, resulting in an increase in scalability due to an increased number of endpoints serving an image file.
This local image cache is transparent to the end user – in other words, the end user doesn’t know that the Glance API is streaming an image file from its local cache or from the actual backend storage system.
Configuration options for the Image Cache
Config File:glance-api.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
[DEFAULT] # This is the base directory where Glance stores the cache data (Required to be set, as does not have a default). image_cache_dir = /var/lib/glance/image-cache
# Path to the sqlite file database that will be used for cache management. image_cache_driver = sqlite
# This is a relative path from the image_cache_dir directory (Default:cache.db) image_cache_sqlite_db = cache.db
# The size when the glance-cache-pruner will remove the oldest images, to reduce the bytes until under this value. (Default:10 GB) image_cache_max_size = 1073741824
[paste_deploy] # Enabling the Image Cache Management Middlewar. There are three types you can chose: # - cachemanagement # - keystone+cachemanagement # - trusted-auth+cachemanagement. flavor = keystone+cachemanagement
Managing the Glance Image Cache
While image files are automatically placed in the image cache on successful requests to GET /v2/images/{image_id}/file, eg: openstack image save --file <file name> <image id>.
the image cache is not automatically managed. Here, we describe the basics of how to manage the local image cache on Glance API servers and how to automate this cache management.
# Copyright 2011 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License.
""" Image Cache Management API """
from oslo_log import log as logging import routes
from glance.api.v2 import cached_images from glance.common import wsgi from glance.i18n import _LI
defprocess_request(self, request): # Map request to our resource object if we can handle it match = self._mapper.match(request.path_info, request.environ) if match: request.environ['wsgiorg.routing_args'] = (None, match) return self._resource(request) # Pass off downstream if we don't match the request path else: returnNone
数据库
sqlite数据库
1 2 3 4 5 6 7 8 9 10 11
sqlite> .tables cached_images sqlite> .schema cached_images CREATE TABLE cached_images ( image_id TEXT PRIMARY KEY, last_accessed REAL DEFAULT 0.0, last_modified REAL DEFAULT 0.0, size INTEGER DEFAULT 0, hits INTEGER DEFAULT 0, checksum TEXT );
defcache_image_iter(self, image_id, image_iter, image_checksum=None): """ Cache an image with supplied iterator. :param image_id: Image ID :param image_file: Iterator retrieving image chunks :param image_checksum: Checksum of image :returns: True if image file was cached, False otherwise """ ifnot self.driver.is_cacheable(image_id): returnFalse
for chunk in self.get_caching_iter(image_id, image_checksum, image_iter): pass returnTrue
defget_caching_iter(self, image_id, image_checksum, image_iter): """ Returns an iterator that caches the contents of an image while the image contents are read through the supplied iterator. :param image_id: Image ID :param image_checksum: checksum expected to be generated while iterating over image data :param image_iter: Iterator that will read image contents """ ifnot self.driver.is_cacheable(image_id): return image_iter
LOG.debug("Tee'ing image '%s' into cache", image_id)
with self.driver.open_for_write(image_id) as cache_file: for chunk in image_iter: try: cache_file.write(chunk) finally: current_checksum.update(chunk) yield chunk cache_file.flush()
if (image_checksum and image_checksum != current_checksum.hexdigest()): msg = _("Checksum verification failed. Aborted " "caching of image '%s'.") % image_id raise exception.GlanceException(msg)
except exception.GlanceException as e: with excutils.save_and_reraise_exception(): # image_iter has given us bad, (size_checked_iter has found a # bad length), or corrupt data (checksum is wrong). LOG.exception(encodeutils.exception_to_unicode(e)) except Exception as e: LOG.exception(_LE("Exception encountered while tee'ing " "image '%(image_id)s' into cache: %(error)s. " "Continuing with response.") % {'image_id': image_id, 'error': encodeutils.exception_to_unicode(e)})
# If no checksum provided continue responding even if # caching failed. for chunk in image_iter: yield chunk
defprune(self): """ Removes all cached image files above the cache's maximum size. Returns a tuple containing the total number of cached files removed and the total size of all pruned image files. """ max_size = CONF.image_cache_max_size current_size = self.driver.get_cache_size() if max_size > current_size: LOG.debug("Image cache has free space, skipping prune...") return (0, 0)
overage = current_size - max_size LOG.debug("Image cache currently %(overage)d bytes over max " "size. Starting prune to max size of %(max_size)d ", {'overage': overage, 'max_size': max_size})