Google App Engine能否结合GCS使用Django文件缓存
结论
完全可以实现。Django原生file-based caching在GAE环境失效的核心原因是:GAE实例的本地文件系统是实例独占的临时存储,实例重启、扩缩容时数据会被清空,且实例之间文件不共享,根本不满足文件缓存需要持久化、跨实例共享读写的要求。你不需要修改现有cache.get()/cache.set()的业务代码,只需要自定义对接GCS的Django缓存后端即可。
实现步骤
安装依赖
首先安装GCS官方SDK:pip install google-cloud-storage编写自定义GCS缓存后端
在Django项目目录下新建gcs_cache.py文件,实现Django标准缓存接口,代码如下:
from django.core.cache.backends.base import BaseCache from google.cloud import storage from datetime import datetime, timedelta import pickle import codecs class GCSCache(BaseCache): def __init__(self, bucket, params): super().__init__(params) self.client = storage.Client() self.bucket = self.client.bucket(bucket) self.key_prefix = params.get("KEY_PREFIX", "") def _get_blob_path(self, key): # 对key做base64编码,避免特殊字符不符合GCS对象命名规则 safe_key = codecs.encode(pickle.dumps(f"{self.key_prefix}{key}"), "base64").decode().strip() return f"django_cache/{safe_key}" def get(self, key, default=None, version=None): key = self.make_key(key, version=version) blob = self.bucket.blob(self._get_blob_path(key)) if not blob.exists(): return default # 校验缓存是否过期 blob.reload() expire_ts = blob.metadata.get("expire_at") if blob.metadata else None if expire_ts and datetime.now() > datetime.fromtimestamp(float(expire_ts)): blob.delete() return default try: return pickle.loads(blob.download_as_bytes()) except Exception: return default def set(self, key, value, timeout=None, version=None): key = self.make_key(key, version=version) timeout = self.default_timeout if timeout is None else timeout expire_at = (datetime.now() + timedelta(seconds=timeout)).timestamp() blob = self.bucket.blob(self._get_blob_path(key)) blob.upload_from_string(pickle.dumps(value)) blob.metadata = {"expire_at": str(expire_at)} blob.patch() def delete(self, key, version=None): key = self.make_key(key, version=version) blob = self.bucket.blob(self._get_blob_path(key)) if blob.exists(): blob.delete() def clear(self): # 清空所有缓存 for blob in self.bucket.list_blobs(prefix="django_cache/"): blob.delete()
- 修改Django配置
在项目settings.py中修改缓存配置,指向你刚写的自定义后端:
CACHES = { "default": { # 替换为你自己的项目路径,比如项目名为myapp则填myapp.gcs_cache.GCSCache "BACKEND": "你的项目路径.gcs_cache.GCSCache", "BUCKET": "你用来存缓存的GCS存储桶名称", "TIMEOUT": 60 * 15, # 匹配你需要的15分钟默认超时 "KEY_PREFIX": "", } }
配置完成后你原有的缓存读写代码不需要做任何修改,就能直接把缓存存在指定GCS存储桶里。
权限配置
只需要给GAE运行时绑定的服务账号配置最小必要权限即可:
- GAE默认使用的服务账号格式为
[你的GCP项目ID]@appspot.gserviceaccount.com - 给该账号绑定目标存储桶的三个角色:
存储对象查看者、存储对象创建者、存储对象删除者,不需要配置项目级别的存储权限,也不需要额外导出服务账号密钥,GAE环境会自动加载默认凭证 - 存储桶保持私有访问权限即可,不要开放公共读写,避免缓存数据泄露
补充说明
- 这个方案的读写延迟高于内存级缓存(memcached/Redis),适合缓存更新频率低、对延迟不敏感的场景,符合你不使用memcached的需求
- 建议给存储桶配置生命周期规则,自动删除创建时间超过7天的
django_cache/前缀下的对象,避免异常残留的过期对象占用存储空间 - 不建议用这个方案缓存单条超过10MB的大对象,GCS读写的网络开销会明显拖慢响应速度
内容的提问来源于stack exchange,提问作者Anthony M
相关产品推荐
相关产品推荐

