memcached服务在linux/macos上用apt或brew安装并启动后监听127.0.0.1:11211;python客户端应优先选用pylibmc,配置需启用二进制协议和ketama一致性哈希,生产环境location须用内网域名或固定ip,避免dns失败导致缓存失效。

直接用 cache.get_or_set() 或 @cache_page 能快速降低 MySQL 查询量,但必须避开用户态误缓存、并发重建打崩 DB、外键未展开致缓存失效这三类高频问题。
Memcached 服务与 Python 客户端怎么装对
Linux/macOS 上装 Memcached 本身很简单:apt install memcached 或 brew install memcached,启动后默认监听 127.0.0.1:11211。关键在客户端选型和配置:
- 优先用
pylibmc(C 扩展,性能比纯 Python 的python-memcached高 3–5 倍),装法:pip install pylibmc -
settings.py中必须启用二进制协议和一致性哈希:'binary': True和'behaviors': {'ketama': True},否则多节点扩容时 key 分布不均,缓存命中率断崖下跌 - 别写
'LOCATION': '127.0.0.1:11211',生产环境用内网域名或固定 IP,避免 DNS 解析失败导致整个缓存链路不可用
@cache_page 为什么一用就出错
它只适合无状态页面,比如商品分类页、帮助文档、轮播图接口。一旦视图里出现 request.user、request.session 或基于角色渲染的内容,就会复用错误响应。
- 现象:未登录用户看到已登录用户的购物车入口,或管理员看到普通用户的按钮
- 根本原因:Django 默认按完整 URL 生成缓存 key,不区分请求上下文
- 类视图要用
@method_decorator(cache_page(300))包裹get方法,不是加在类定义上 - 如果前端有 CDN 或 Nginx 缓存,必须手动加
Cache-Control: public, max-age=300响应头,否则cache_page可能被跳过
cache.get_or_set() 怎么防雪崩和缓存穿透
cache.get_or_set('key', expensive_call(), 300) 是错的——expensive_call() 会立刻执行,失去惰性;高并发下所有线程都触发查询,MySQL 瞬间被打满。
- 正确写法是传 lambda:
cache.get_or_set('key', lambda: list(Book.objects.all()), 300) - 超时值要按业务节奏设:静态页可设
3600(1 小时),库存类建议 ≤60(1 分钟) - 不要缓存空结果(
None或空列表),否则缓存穿透风险拉满;需配合空值缓存:cache.setex('key', 60, 'NULL') - 分页类 key 必须带业务维度,例如
f"product:list:cat_{cat_id}:sort_{sort}:page_{page}",不能只拼f"list:page:{page}"
外键字段缓存为什么总查库
缓存了 Book 实例或只存 book.author_id,后续访问 book.author.name 仍会触发新查询——缓存等于白做。
- 正确做法:预加载 + 展开成 dict,例如
{'id': b.id, 'title': b.title, 'author_name': b.author.name, 'category_name': b.category.name} - 预加载必须用
select_related('author', 'category')或prefetch_related('tags'),再转成字典缓存 - 更新时必须同步清理缓存:在
@receiver(post_save, sender=Book)里调用cache.delete('books'),记得加dispatch_uid='book_save_cleanup'防重复注册
最易被忽略的是:Memcached 连接池没设重试机制,网络抖动时请求直接抛 ConnectionResetError,而你还在 MySQL 慢查询日志里翻半天。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











