缓存基础处理方式和一些优化记录


这些只是打开思路,具体怎么使用要根据业务来,不要盲目使用!

内存缓存

适用场景:函数结果缓存,尤其递归或重复计算,例如递归一类计算 ,或者按照某种规则循环取一些配置参数之类,如循环取产品配置的数值表

import time
from flask import Flask
from cachetools import TTLCache, cached
app = Flask(__name__)
# 还有一些别的策略
cache = TTLCache(maxsize=100, ttl=10)

@app.route("/")
def hello_world():
	# !!!!函数参数要能hash,因为要作为键
    a = temp(str([1]))
    return str(a)

@cached(cache)
def temp(x):
    a = time.time()
    print(a)
    return a

分布式缓存

适用场景:多进程/多服务共享缓存,各种锁,计数器
通常使用redis,要是只有key,value且要求不是那么高可考虑Memcached
很常用

数据库查询缓存

ORM层缓存(如Django Cache Framework)

from django.core.cache import cache

def get_articles():
    articles = cache.get('all_articles')
    if not articles:
        articles = Article.objects.all()
        cache.set('all_articles', articles, timeout=60*15)  # 15分钟
    return articles

HTTP响应缓存

请求结果缓存

import time
import requests_cache, requests

from cachetools import TTLCache, cached
from flask import Flask


app = Flask(__name__)
# 本地会生成api_cache.sqlite的数据库文件,存储请求后的数据,到期后重新请求刷新
requests_cache.install_cache(
    'api_cache', 
    backend='sqlite', 
    expire_after=180  # 3分钟自动过期
)

@app.route("/")
def hello_world():
    a = temp(str([1]))
    response = requests.get('http://localhost:5000')
    print(response.text)
    return str()

def temp(x):
    a = time.time()
    print(a)
    return a


if __name__ == "__main__":
    app.run(debug=True, port=5001)

ETag缓存(条件请求)

重点记录下,以前没太接触过这种处理方式,但是这种处理方式需要前端配合,对比常规请求返回,可能最大阻力是在和前端沟通上。

核心原理
请求缓存

存储API的完整响应结果(含headers和body)
使用本地存储(如SQLite/文件)或内存缓存
设置合理过期时间(TTL),避免长期不更新

ETag验证

服务器为每个资源生成唯一标识符(ETag)
客户端首次请求保存ETag,后续请求携带If-None-Match头
服务器比对ETag:

  • 匹配 → 返回304 Not Modified(空body)
  • 不匹配 → 返回完整新数据+新ETag
完整工作流程
sequenceDiagram
    participant Client
    participant Cache
    participant Server

    Client->>Cache: 首次请求(无ETag)
    Cache->>Server: 转发请求
    Server->>Cache: 返回数据 + ETag
    Cache->>Client: 返回数据,保存ETag

    Client->>Cache: 后续请求(带If-None-Match)
    Cache->>Server: 转发请求(含ETag)
    alt ETag匹配
        Server->>Cache: 304 Not Modified
        Cache->>Client: 返回本地缓存
    else ETag不匹配
        Server->>Cache: 新数据 + 新ETag
        Cache->>Client: 返回新数据,更新ETag
    end
后端代码示意:
from flask import Flask, request, jsonify
import hashlib

app = Flask(__name__)

def generate_etag(data):
    # 根据内容生成ETag(示例使用MD5)
    return hashlib.md5(str(data).encode()).hexdigest()

@app.route('/data')
def get_news():
    # 实际业务:从数据库获取最新数据
    current_data = {"articles": [1]}  
    
    # 生成当前ETag
    current_etag = generate_etag(current_data)
    
    # 检查客户端ETag
    client_etag = request.headers.get('If-None-Match')
    if client_etag == current_etag:
        return '', 304  # Not Modified
    # 返回新数据+ETag
    response = jsonify(current_data)
    response.headers['ETag'] = current_etag
    return response

if __name__ == '__main__':
    app.run(debug=True)

浏览器访问示例
在这里插入图片描述

文件/资源缓存

本地文件缓存

就是将一些复杂的结果存储到本地文件中,之后读取文件获取结果

import os
import pickle
from hashlib import md5

def cached_file(key, compute_func, cache_dir='.cache'):
    os.makedirs(cache_dir, exist_ok=True)
    file_hash = md5(key.encode()).hexdigest()
    path = os.path.join(cache_dir, file_hash)
    
    if os.path.exists(path):
        with open(path, 'rb') as f:
            return pickle.load(f)
    else:
    	# !!!这里执行函数,获取数据
        data = compute_func()
        with open(path, 'wb') as f:
            pickle.dump(data, f)
        return data

图像处理结果缓存

类似于内存缓存

from PIL import Image
from functools import lru_cache

@lru_cache(maxsize=100)
def load_image(path):
    return Image.open(path)
适用场景建议

推荐使用

  • 用户动态流(微博/Twitter)
  • 新闻/文章列表
  • 商品价格(需要及时性但变化不频繁

不推荐使用

  • 实时股价/加密货币行情
  • 高频更新的聊天消息
  • 需要严格实时性的场景

高级优化策略

缓存预热

启动时加载常用数据

防缓存击穿(Mutex Lock)

增加互斥锁,防止重复

from threading import Lock

cache_lock = Lock()
def get_data_safe(key):
    data = cache.get(key)
    if data is None:
        with cache_lock:  # 防止并发重复计算
            data = compute_data()
            cache.set(key, data)
    return data

分层缓存(多级缓存)

本地缓存和redis混合使用,很重要要的一个思路

def get_data_multi_level(key):
    data = local_cache.get(key)
    if not data:
        data = redis.get(key)
        if not data:
            data = db.query(key)
            redis.setex(key, 3600, data)
        local_cache.set(key, data, 60)  # 本地缓存1分钟
    return data
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值