一、为什么需要给Django加速?
想象你开了一家网红奶茶店,顾客排队点单时,如果每个订单都要现摘茶叶、现挤牛奶,队伍肯定排到马路对面去了。Django处理动态内容就像现做奶茶——每次用户访问都要重新计算数据、渲染模板。这时候缓存和CDN就像是提前备好的半成品原料和开在商场里的分店,能大大缩短"制作时间"。
举个例子,你有个展示实时天气的页面:
# 技术栈:Django 4.2 + Redis
# views.py
def weather(request):
# 实时调用气象局API(耗时操作)
data = requests.get('https://weather.com/api').json()
return render(request, 'weather.html', {'data': data})
每次访问都要等API响应,用户体验就像在等现熬的珍珠奶茶。其实天气预报每小时更新一次,完全没必要实时获取。
二、给Django装上"记忆"——缓存系统
2.1 基础缓存配置
先在settings.py里设置:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1", # 使用Redis数据库1
"TIMEOUT": 3600 # 默认缓存1小时
}
}
2.2 视图缓存实战
改造刚才的天气视图:
from django.views.decorators.cache import cache_page
@cache_page(60 * 30) # 缓存30分钟
def weather(request):
data = requests.get('https://weather.com/api').json()
return render(request, 'weather.html', {'data': data})
现在30分钟内相同请求直接返回缓存,响应速度提升10倍不止。就像提前泡好了30分钟的茶底,随取随用。
2.3 模板片段缓存
有些页面只有部分需要缓存:
<!-- 缓存导航栏24小时 -->
{% load cache %}
{% cache 86400 navbar %}
<div class="navbar">...</div>
{% endcache %}
<!-- 实时内容 -->
<div class="main-content">...</div>
三、把内容分发到用户家门口——CDN加速
3.1 静态文件加速
在settings.py配置:
STATIC_URL = 'https://cdn.yourdomain.com/static/'
然后把静态文件同步到CDN:
python manage.py collectstatic
aws s3 sync static/ s3://your-cdn-bucket/static/
3.2 动态内容边缘缓存
对于频繁访问的动态内容,可以用CDN边缘计算:
# 技术栈:Django + Cloudflare CDN
@cache_page(60 * 15)
@vary_on_headers('X-Forwarded-For') # 按用户IP缓存不同版本
def product_detail(request, id):
product = get_object_or_404(Product, pk=id)
return render(request, 'product.html', {'product': product})
这样北京用户访问时,CDN北京节点直接返回缓存;同时上海用户请求会触发上海节点单独缓存。
四、实战中的注意事项
4.1 缓存失效策略
商品修改时要及时清除缓存:
# signals.py
from django.core.cache import cache
from django.db.models.signals import post_save
def clear_product_cache(sender, instance, **kwargs):
cache.delete(f'product_{instance.id}') # 精确删除
cache.delete_pattern('products_*') # 批量删除(需要django-redis)
post_save.connect(clear_product_cache, sender=Product)
4.2 多级缓存方案
大型项目可以采用多级缓存:
# 技术栈:Django + Redis + Memcached
CACHES = {
"local": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"TIMEOUT": 60 # 1分钟快速缓存
},
"redis": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://cluster.example.com:6379/1",
"TIMEOUT": 3600
}
}
def get_data():
# 先查本地内存
data = caches['local'].get('key')
if not data:
# 再查Redis
data = caches['redis'].get('key')
if data:
# 回填到本地
caches['local'].set('key', data, 60)
return data
五、什么时候该用这些技术?
5.1 适用场景
- 内容更新频率低(如新闻详情页)
- 计算成本高(如数据分析报表)
- 访问量大(如电商首页)
- 用户分布广(全球业务)
5.2 技术对比
| 方案 | 速度 | 成本 | 适用规模 |
|---|---|---|---|
| 本地内存 | ★★★★ | ★ | 单服务器 |
| Redis | ★★★ | ★★ | 中小型集群 |
| CDN | ★★★★ | ★★★ | 全球分布式系统 |
5.3 常见误区
- 过度缓存:用户私信页面也缓存会导致信息不同步
- 忽略缓存穿透:对不存在的键添加空值缓存
- 忘记设置超时:导致更新后长期不生效
六、总结与最佳实践
经过这些优化,我们的Django应用就像升级成了连锁奶茶店:
- 中央厨房(Redis)统一准备原料
- 分店(CDN节点)就近服务顾客
- 特调区(动态内容)保留个性化服务
最后分享一个压测对比:
# 优化前
ab -n 1000 -c 100 http://site.com/weather
# 平均响应 1200ms
# 优化后
ab -n 1000 -c 100 http://site.com/weather
# 平均响应 85ms
记住三个黄金原则:
- 能缓存的不要实时计算
- 能就近获取的不要回源
- 该清缓存时绝不手软
评论