一、为什么需要给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 常见误区

  1. 过度缓存:用户私信页面也缓存会导致信息不同步
  2. 忽略缓存穿透:对不存在的键添加空值缓存
  3. 忘记设置超时:导致更新后长期不生效

六、总结与最佳实践

经过这些优化,我们的Django应用就像升级成了连锁奶茶店:

  • 中央厨房(Redis)统一准备原料
  • 分店(CDN节点)就近服务顾客
  • 特调区(动态内容)保留个性化服务

最后分享一个压测对比:

# 优化前
ab -n 1000 -c 100 http://site.com/weather
# 平均响应 1200ms

# 优化后
ab -n 1000 -c 100 http://site.com/weather  
# 平均响应 85ms

记住三个黄金原则:

  1. 能缓存的不要实时计算
  2. 能就近获取的不要回源
  3. 该清缓存时绝不手软