ITPub博客

首页 > 应用开发 > Python > Python缓存一致性处理

Python缓存一致性处理

原创 Python 作者:raptors 时间:2025-11-12 16:20:22 0 删除 编辑

# Python缓存一致性处理


缓存一致性是确保缓存数据与底层数据源保持同步的重要问题。在Python中处理缓存一致性有多种方法,下面我将介绍几种常见的策略和实现方式。


## 1. 缓存失效策略


### 1.1 时间过期策略


```python

from datetime import datetime, timedelta

import functools


def timed_cache(seconds: int, maxsize: int = 128):

    def wrapper_cache(func):

        func = functools.lru_cache(maxsize=maxsize)(func)

        func.lifetime = timedelta(seconds=seconds)

        func.expiration = datetime.utcnow() + func.lifetime


        @functools.wraps(func)

        def wrapped_func(*args, **kwargs):

            if datetime.utcnow() >= func.expiration:

                func.cache_clear()

                func.expiration = datetime.utcnow() + func.lifetime

            return func(*args, **kwargs)

        return wrapped_func

    return wrapper_cache


@timed_cache(seconds=60)

def get_expensive_data():

    # 获取数据的逻辑

    pass

```


### 1.2 基于事件的失效


```python

from functools import lru_cache


# 使用装饰器

@lru_cache(maxsize=128)

def get_data(key):

    # 从数据库获取数据

    pass


# 当数据变更时清除缓存

def update_data(key, value):

    # 更新数据库

    get_data.cache_clear()  # 清除整个缓存

    # 或者更精确地清除特定键的缓存

    get_data.cache_pop(key, None)

```


## 2. 使用缓存库


### 2.1 Redis缓存


```python

import redis

import pickle


r = redis.Redis(host='localhost', port=6379, db=0)


def get_data_with_cache(key):

    # 尝试从缓存获取

    cached_data = r.get(key)

    if cached_data:

        return pickle.loads(cached_data)

    

    # 缓存中没有,从数据库获取

    data = get_data_from_db(key)

    

    # 存入缓存,设置过期时间

    r.setex(key, 3600, pickle.dumps(data))  # 1小时过期

    return data


def update_data_with_cache(key, value):

    # 更新数据库

    update_data_in_db(key, value)

    

    # 更新缓存

    r.setex(key, 3600, pickle.dumps(value))

```


### 2.2 使用Django缓存框架


```python

from django.core.cache import cache


def get_user_profile(user_id):

    cache_key = f"user_profile_{user_id}"

    profile = cache.get(cache_key)

    if profile is None:

        profile = UserProfile.objects.get(user_id=user_id)

        cache.set(cache_key, profile, timeout=3600)  # 1小时过期

    return profile


def update_user_profile(user_id, data):

    # 更新数据库

    profile = UserProfile.objects.get(user_id=user_id)

    profile.update(data)

    

    # 更新缓存

    cache_key = f"user_profile_{user_id}"

    cache.set(cache_key, profile, timeout=3600)

```


## 3. 高级策略


### 3.1 读写穿透 (Read/Write Through)


```python

class CacheThrough:

    def __init__(self):

        self.cache = {}

    

    def get(self, key):

        if key in self.cache:

            return self.cache[key]

        

        # 缓存未命中,从数据库加载

        value = self.load_from_db(key)

        self.cache[key] = value

        return value

    

    def set(self, key, value):

        # 先更新数据库

        self.save_to_db(key, value)

        # 再更新缓存

        self.cache[key] = value

    

    def load_from_db(self, key):

        # 数据库读取逻辑

        pass

    

    def save_to_db(self, key, value):

        # 数据库写入逻辑

        pass

```


### 3.2 写回 (Write Behind)


```python

import threading

import time


class WriteBehindCache:

    def __init__(self):

        self.cache = {}

        self.dirty_keys = set()

        self.lock = threading.Lock()

        self.running = True

        self.worker = threading.Thread(target=self.flush_worker)

        self.worker.start()

    

    def get(self, key):

        with self.lock:

            return self.cache.get(key)

    

    def set(self, key, value):

        with self.lock:

            self.cache[key] = value

            self.dirty_keys.add(key)

    

    def flush_worker(self):

        while self.running:

            time.sleep(10)  # 每10秒刷新一次

            self.flush()

    

    def flush(self):

        with self.lock:

            dirty = self.dirty_keys.copy()

            self.dirty_keys.clear()

        

        # 批量更新数据库

        self.batch_save_to_db(dirty)

    

    def batch_save_to_db(self, keys):

        # 批量保存到数据库的逻辑

        pass

    

    def stop(self):

        self.running = False

        self.worker.join()

        self.flush()  # 最后一次刷新

```


## 4. 分布式缓存一致性


### 4.1 使用版本号或时间戳


```python

def get_data_with_version(key):

    # 获取数据和版本号

    data, version = get_from_db_with_version(key)

    

    # 检查缓存中的数据是否过期

    cached_data, cached_version = cache.get(key, (None, None))

    if cached_version == version:

        return cached_data

    

    # 缓存过期,更新缓存

    cache.set(key, (data, version))

    return data


def update_data_with_version(key, new_data):

    # 更新数据库并获取新版本号

    new_version = update_db_and_get_version(key, new_data)

    

    # 更新缓存

    cache.set(key, (new_data, new_version))

```


## 5. 最佳实践


1. **选择合适的缓存策略**:根据数据访问模式选择LRU、LFU或FIFO等策略

2. **设置合理的过期时间**:避免缓存数据长时间不更新

3. **考虑缓存穿透**:对不存在的键也进行缓存(缓存空值)

4. **防止缓存雪崩**:设置不同的过期时间或使用互斥锁

5. **监控缓存命中率**:评估缓存效果


```python

# 防止缓存穿透的示例

def get_product(product_id):

https://zq.zhaopin.com/moment/71139063

https://zq.zhaopin.com/moment/71138886

https://zq.zhaopin.com/moment/71138784

https://zq.zhaopin.com/moment/71138499

https://zq.zhaopin.com/moment/71138430

https://zq.zhaopin.com/moment/71138309

https://zq.zhaopin.com/moment/71138245

https://zq.zhaopin.com/moment/71138244

https://zq.zhaopin.com/moment/71138240

https://zq.zhaopin.com/moment/71138237

https://zq.zhaopin.com/moment/71138236

https://zq.zhaopin.com/moment/71137873

https://zq.zhaopin.com/moment/71137764

https://zq.zhaopin.com/moment/71137708

https://zq.zhaopin.com/moment/71137605

https://zq.zhaopin.com/moment/71134097

https://zq.zhaopin.com/moment/71134036



    # 尝试从缓存获取

    product = cache.get(f"product_{product_id}")

    

    if product is None:

        # 从数据库获取

        product = db.get_product(product_id)

        

        if product is None:

            # 缓存空值,短时间过期

            cache.set(f"product_{product_id}", "NULL", timeout=60)

        else:

            # 缓存真实值

            cache.set(f"product_{product_id}", product, timeout=3600)

    

    return None if product == "NULL" else product

```


通过合理选择和应用这些策略,可以在Python应用中有效处理缓存一致性问题,提高系统性能的同时保证数据的准确性。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/34366/viewspace-3101107/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-09-29

  • 博文量
    20
  • 访问量
    20448